Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

experimental doc service route guessing #4987

Merged
merged 22 commits into from Aug 18, 2023

Conversation

Dogacel
Copy link
Contributor

@Dogacel Dogacel commented Jun 26, 2023

Motivation:

Modifications:

Add cfg.route() of the DocService to the ServiceSpecification as an optional value.

Result:

Example URL: http://127.0.0.1:9000/proxy/docs/#/methods/armeria.grpc.testing.TestService/UnaryCallWithAllDifferentParameterTypes/POST

Previously it sent requests to http://127.0.0.1:9000/test/armeria.grpc.testing.TestService/UnaryCallWithAllDifferentParameterTypes

but in reality it should be
URL: http://127.0.0.1:9000/proxy/test/armeria.grpc.testing.TestService/UnaryCallWithAllDifferentParameterTypes

Because DocService is bound under /docs not /proxy/docs.

To emulate, you can create the following proxy service:

    sb
        .virtualHost(9000)
        .serviceUnder("/proxy/", ProxyService())

// Under ProxyService

class ProxyService(val config: ProxyConfiguration) : HttpService {
    override fun serve(ctx: ServiceRequestContext, req: HttpRequest): HttpResponse {
        val r2 = req.mapHeaders { headers -> headers.toBuilder().path(req.path().replace("/proxy", "")).build() }
        return client.execute(r2) // WebClient
    }
}

@Dogacel Dogacel marked this pull request as ready for review June 26, 2023 23:57
@minwoox minwoox added this to the 1.25.0 milestone Jun 27, 2023
Copy link
Member

@minwoox minwoox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great. Thanks a lot! 😄

@@ -149,6 +152,11 @@ public ServiceSpecification(Iterable<ServiceInfo> services,
this.exampleHeaders = ImmutableList.copyOf(requireNonNull(exampleHeaders, "exampleHeaders"));
}

public ServiceSpecification withServiceRoute(Route serviceRoute) {
this.serviceRoute = serviceRoute;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Global suggestion:
How about renaming serviceRoute to docServiceRoute which is more specific?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to set this route only when Route.pathType() is RoutePathType.PREFIX?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about EXACT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am adding that as default too, seems like it shouldn't hurt.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't serve docserivce using EXACT so I think only one of PREFIX, REGEX and GLOB can be used.
If REGEX and GLOB are used, I thought we could just don't set it because we can't handle it. 😉

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, even if we can handle it seems like not worth it. Why would somebody mount DocService under a glob or regex path? 😅

About exact, this is related to how client code is generated, right? Because we are not serving a single static page but rather a page under path /docs/#/...?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, even if we can handle it seems like not worth it. Why would somebody mount DocService under a glob or regex path?

That is correct. 😄

Because we are not serving a single static page but rather a page under path /docs/#/...?

That is also correct. The client sends additional requests whose path is:

/docs/main.js?somehash
/docs/specification.json
/docs/versions.json
/docs/injected.js
/docs/schemas.json
/docs/assets/favicon.png

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@minwoox Please take a second look when you are free 😄

Also, what is the standard procedure for testing those changes?

I am thinking about running Annotated, GraphQL, Grpc doc services and test everything is fine.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have automated tests for UI. 😓
We definitely need to set up front-end tests.

@@ -203,6 +216,10 @@ const DebugPage: React.FunctionComponent<Props> = ({
)?.pathMapping || '';
}

if (urlPath.startsWith('/')) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Is there a case that urlPath doesn't start with a slash?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I was thinking about exact: and relative path (if possible?)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think exact: will be stripped by the extractUrlPath method above but I'm not sure about the relative path.
So let's leave it as is. We can fix it later if we found any problems. 😉

@Dogacel Dogacel requested a review from minwoox June 30, 2023 11:07
Comment on lines 156 to 163
/**
* Return a {@link ServiceSpecification} that contains the {@link Route} info of
* the attached {@link DocService}.
*/
public ServiceSpecification withDocServiceRoute(Route docServiceRoute) {
this.docServiceRoute = docServiceRoute;
return this;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we keep this class immutable? It would also be nice if this method is not public.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, I think it makes sense to move this route to exampleSupport because it contains path information as well? What do you think, I am not sure about creating a new class just to put a single method 😆

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good idea! We probably should rename it though. What do you think about SpecificationSupport?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind. Just realized that you fixed it in a better way.

Comment on lines 120 to 129
const parseServerRootPath = (docServiceRoute: string) => {
const plainRoute = docServiceRoute.replace('/*', '');
const index = window.location.href.indexOf(plainRoute);

if (index === -1) {
return '';
}
const rootPath = window.location.href.substring(0, index);
return rootPath;
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also show an error message if a user bound a DocService with other routes than prefix:? I think we can throw an exception on the server side, then we could simplify the logic here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, exact paths don't work (I personally experienced it in the past).

Globs and regex, should we disable them?. I feel like it won't really make sense unless somebody has a particular need (i.e. bound it to a dynamic path).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so. Let's allow prefix: only.

Copy link
Contributor

@jrhee17 jrhee17 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some minor comments 👍
Can you also check if exact paths correctly use the base path?

i.e. if the following line is false:

Screenshot 2023-07-07 at 1 26 59 PM

docs-client/src/lib/transports/transport.ts Outdated Show resolved Hide resolved
import com.linecorp.armeria.server.ServerBuilder;
import com.linecorp.armeria.testing.junit5.server.ServerExtension;

class ServiceSpecificationRouteTest {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of adding another service (maybe in AnnotatedDocServiceTest) so that we can at least verify manually easily if doc service works correctly behind a proxy?

e.g.

sb.serviceUnder("/proxy", (ctx, req) -> {
    final String origPath = req.path();
    assertThat(origPath).startsWith("/proxy");
    final String newPath = req.path().substring("/proxy".length());
    final HttpRequest newReq = req.withHeaders(req.headers().toBuilder().path(newPath).build());
    return server.webClient().execute(newReq);
});

and we can call http://localhost:3000/proxy/docs when testing

@@ -116,6 +117,17 @@ const copyTextToClipboard = (text: string) => {
modal.removeChild(textArea);
};

const parseServerRootPath = (docServiceRoute: string) => {
const plainRoute = docServiceRoute.replace('/*', '');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of skipping unless the route ends with /*?
I'm thinking of regex cases where the path may look like: a/**/b

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In backend we configured it in a way that it only works for PREFIX paths. If it is something else, docServiceRoute is going to be empty string. But it makes sense to just have the logic here as a safe-guard.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated logic to check route type.

return '';
}
const rootPath = window.location.href.substring(0, index);
return rootPath;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question) I haven't tried, but what do you think of returning a relative path instead of the full location? I feel like this can be a confusing point later if either an absolute path or a relative path can be set to additionalPath

i.e. /foo instead of http://host/foo

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm good idea, I was also thinking about the same thing let me try.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now using a relative path. Tested manually behind a proxy and a non-proxy.

@Dogacel Dogacel requested review from trustin and jrhee17 July 7, 2023 07:52
@Dogacel
Copy link
Contributor Author

Dogacel commented Jul 14, 2023

ditto,

I have a 3 day weekend, have some time to finalize my PRs.

@Dogacel
Copy link
Contributor Author

Dogacel commented Jul 18, 2023

Hey folks, I want to merge this if possible. We can't still use doc service for our staging services in my company so with this change I can promote usage of Doc service 🙂

@jrhee17
Copy link
Contributor

jrhee17 commented Jul 20, 2023

Hey folks, I want to merge this if possible. We can't still use doc service for our staging services in my company so with this change I can promote usage of Doc service 🙂

Thanks for the reminder. Will try to get review/get this merged in the next release (1.25.0).

*/
@JsonProperty
@Nullable
public Route docServiceRoute() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we will always be aware that Route can be serialized to a json when modifying the class.

What do you think of either:

  1. Transforming Route to a dedicated dto
  2. Adding unit tests on json serialization which ensures that the contract won't change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, it is a good idea. Let me handle this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I found out that in ServiceSpecification we serialize the following structs to JSON as well:

  • HttpHeaders
  • MediaType

So I think it is OK as long as I add a custom serializer to it and add a unit test rather than creating a DTO. Because we did not create DTO for any of the above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm actually it is not really necessary to add a custom serializer either. How about just keeping @JsonProperty and adding unit tests?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about just keeping @JsonProperty and adding unit tests?

Sure sounds good 👍

@ParameterizedTest
@CsvSource({ "/proxy", "/proxy2/nested" })
void rightPathBehindProxy(String proxyPath) throws IOException {
server.server().reconfigure(sb -> sb.serviceUnder(proxyPath, (ctx, req) -> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer that we don't use reconfigure in tests since this can affect tests that might be added afterwards.
(Usually when adding tests to files like this, I think it is more convenient to check the added services in ServerExtension instead of having to check each test to see if the server has been configured)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is more convenient to check the added services in ServerExtension

I did not understand this. My intention was to create the endpoint in test and test it afterwards. Kinda like scoping the server extension to single test 😆 So I wanted to make sure behavior is explicit. Any suggestions on how to do it? Maybe I should create different extensions or different test classes but that can be heavyweight.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyway, moved proxies to top-level as pre-defined endpoints for simplicity.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a server.reconfigure() is called, the original services defined in ServerExtension are not restored.
Thus, if a test is executed after rightPathBehindProxy only /proxy2/nested and \docs service will be available.

Alternatively, we could enable ServerExtension#runForEachTest, but it's probably cheaper to just add the service like done in the following commit you added 👍 .

Copy link
Contributor

@jrhee17 jrhee17 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall 👍
I think I'll have to run the service and check if there are any regressions, but basically I'm happy with the current PR if it wokrs 👍

@Dogacel Dogacel requested a review from jrhee17 July 20, 2023 12:08
@jrhee17
Copy link
Contributor

jrhee17 commented Jul 20, 2023

Were you able to check this comment? It seems like the actual request that is sent is not prefixed 😅

#4987 (review)

@Dogacel
Copy link
Contributor Author

Dogacel commented Jul 20, 2023

Sorry I must have missed that 😓

I'll get into it tomorrow 👍

@@ -59,7 +59,7 @@ export default class ThriftTransport extends Transport {
hdrs.set(name, value);
}

return fetch(endpoint.pathMapping, {
return fetch(endpointPath || endpoint.pathMapping, {
Copy link
Contributor

@jrhee17 jrhee17 Jul 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think most logic in DocService relies on using the endpoint's path, whereas we are adding a root path unrelated to endpoints.

Instead of reusing additionalPath (urlPath), what do you think of just passing the rootPrefix (docServiceRoute) all the way down to the transport layer?
i.e.

let newPath =
endpointPath || endpoint.pathMapping.substring('exact:'.length);

This way

  • We don't have to worry about edge cases depending on the method type.
  • We don't have to worry about url paths that are resolved at the last minute.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not understand. Do you think it would be better if we pass rootPrefix into this method,

public async send(
method: Method,
headers: { [name: string]: string },
bodyJson?: string,
endpointPath?: string,
queries?: string,
): Promise<string> {

And leave endpointPath unmodified? So doSend method takes rootPrefix instead?

I will push a PR regarding this and LMK if I understood this incorrectly.

Copy link
Contributor Author

@Dogacel Dogacel Jul 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW it seems like this || change in thrift should be fine regardless of that because same logic applies to annotated services?

Copy link
Contributor

@jrhee17 jrhee17 Jul 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will push a PR regarding this and LMK if I understood this incorrectly.

On second thought, perhaps it's better to just add the prefix automatically to the preset UI. (so the original implementation was fine)
This way if the prefix adding behavior is not what the user wants, worst case the user can just manually remove the prefix.

I'll have to look into a better injection point for this behavior during the weekend, but if you have a better idea which solves this feel free to fix as you'd like. Sorry about the incorrect review 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries, I think your idea makes more sense. Prefix is similar to sending requests to another host (which we were discussing to implement anyway). If we want to show the URL we used to send the request, probably transport should return back the URL used to send because there are additional parsing happening in transport anyway. Should be better to centralize all those URL parsing. I had hard time modifying this code 😄

@@ -203,6 +227,10 @@ const DebugPage: React.FunctionComponent<Props> = ({
)?.pathMapping || '';
}

if (urlPath.startsWith('/')) {
urlPath = parseServerRootPath(docServiceRoute) + urlPath;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question) Should Copy as Curl also use the root path?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should have the same behavior there as well, so yes.

@Dogacel Dogacel force-pushed the dogac/experimental-figure-out-host-by-route branch from 44e491e to d99ee56 Compare July 21, 2023 08:11
@Dogacel
Copy link
Contributor Author

Dogacel commented Jul 26, 2023

Gentle ping @jrhee17 @minwoox

Copy link
Member

@minwoox minwoox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the late review. 😉
Looks good overall. 👍

return CompletableFuture.supplyAsync(() -> {
final DocStringSupport docStringSupport = new DocStringSupport(services);
ServiceSpecification spec = generate(services);
spec = docStringSupport.addDocStrings(spec);
spec = exampleSupport.addExamples(spec);
spec = exampleSupport.addExamples(spec, docServiceRoute);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, docServiceRoute isn't related to the example.
How about specifying it when calling generate method above?

ServiceSpecification spec = generate(services, docServiceRoute);

// generate method
private ServiceSpecification generate(List<ServiceConfig> services, Route docServiceRoute) {
    return ServiceSpecification.merge(
            plugins.stream()
                   .map(plugin -> plugin.generateSpecification(
                           findSupportedServices(plugin, services),
                           filter, descriptiveTypeInfoProvider))
                   .collect(toImmutableList()), docServiceRoute);
}

// merge method
public static ServiceSpecification merge(Iterable<ServiceSpecification> specs, Route docServiceRoute) {
    return new ServiceSpecification(
            Streams.stream(specs).flatMap(s -> s.services().stream())::iterator,
            Streams.stream(specs).flatMap(s -> s.enums().stream())::iterator,
            Streams.stream(specs).flatMap(s -> s.structs().stream())::iterator,
            Streams.stream(specs).flatMap(s -> s.exceptions().stream())::iterator,
            ImmutableList.of(), docServiceRoute);
}

Comment on lines 237 to 239
if (docServiceRoute != null && docServiceRoute.pathType() == RoutePathType.PREFIX) {
return docServiceRoute;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about doing this in the constructor?

if (docServiceRoute != null && docServiceRoute.pathType() == RoutePathType.PREFIX) {
    this.docServiceRoute = docServiceRoute;
} else {
    this.docServiceRoute = null;
}

@@ -121,6 +133,8 @@ private static void generateDescriptiveTypeInfos(
private final Set<StructInfo> structs;
private final Set<ExceptionInfo> exceptions;
private final List<HttpHeaders> exampleHeaders;
@Nullable
private Route docServiceRoute;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
private Route docServiceRoute;
private final Route docServiceRoute;

private final String proxyPath;

private ProxyService(String proxyPath) {
super();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
super();

@@ -328,7 +353,7 @@ const DebugPage: React.FunctionComponent<Props> = ({
`${window.location.port ? `:${window.location.port}` : ''}`;

const httpMethod = method.httpMethod;
let uri;
let baseUri;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let baseUri;
let mappedPath;

because we use the term for this purpose? 😉

@@ -86,6 +86,7 @@ export default class AnnotatedHttpTransport extends Transport {
bodyJson?: string,
endpointPath?: string,
queries?: string,
pathPrefix?: string,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't this be pathPrefix because we specify an empty string when it's null?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep.

@Dogacel
Copy link
Contributor Author

Dogacel commented Aug 11, 2023

@minwoox finally had some time to address the issues while waiting in the airport 😄 Let me know what you think, excited to have this feature in the next release 😄

Copy link
Contributor

@jrhee17 jrhee17 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks almost done 👍 It seems like the addExamples is omitting the route causing test failures.
Can you check it?

@@ -144,9 +146,9 @@ export default abstract class Transport {
* Default implementation is suitable for RPC, using endpoint.pathMapping === path.
*/
protected validatePath(endpoint: Endpoint, path: string): { error?: string } {
if (endpoint.pathMapping !== path) {
if (!path.endsWith(endpoint.pathMapping)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question) Since we decided to pass the pathPrefix to the transport layer, I thought we can revert this change. Is there a code path which requires this change?

@@ -239,6 +239,7 @@ const MethodPage: React.FunctionComponent<Props> = (props) => {
useRequestBody={needsToUseRequestBody(props.match.params.httpMethod)}
debugFormIsOpen={debugFormIsOpen}
setDebugFormIsOpen={setDebugFormIsOpen}
docServiceRoute={props.specification.getDocServiceRoute()}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional; I think also serverRoot can be passed for dedup, but I'm fine with the current approach.


return window.location.pathname.substring(
0,
window.location.pathname.indexOf(docServicePath),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's possible that docServicePath isn't even in the pathname.

i.e. a proxy server just rewrites the path (i.e. foo->bar) instead of removing a prefix.

What do you think of just defaulting to no root path in this case?

const index = window.location.pathname.indexOf(docServicePath);
if (index < 0) {
  return '';
}
return window.location.pathname.substring(0, index);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it should happen rarely and it makes sense to default to that in that case.

Copy link
Member

@minwoox minwoox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great to me. Thanks!

Copy link
Contributor

@jrhee17 jrhee17 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Thanks @Dogacel 🙇 👍 🚀

docs-client/src/lib/transports/transport.ts Outdated Show resolved Hide resolved
Co-authored-by: jrhee17 <guins_j@guins.org>
Copy link
Member

@trustin trustin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent work and sorry for a late approval, @Dogacel. 🙇 We may want to disallow other route types than prefix, but it's probably something that we can take care of later.

@codecov
Copy link

codecov bot commented Aug 17, 2023

Codecov Report

Patch coverage: 89.84% and project coverage change: +0.09% 🎉

Comparison is base (a73f78c) 74.22% compared to head (b6eca95) 74.31%.
Report is 2 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff              @@
##               main    #4987      +/-   ##
============================================
+ Coverage     74.22%   74.31%   +0.09%     
- Complexity    19518    19601      +83     
============================================
  Files          1674     1682       +8     
  Lines         71947    72260     +313     
  Branches       9217     9242      +25     
============================================
+ Hits          53400    53702     +302     
- Misses        14209    14217       +8     
- Partials       4338     4341       +3     
Files Changed Coverage Δ
...c/main/java/com/linecorp/armeria/server/Route.java 66.66% <ø> (ø)
...a/client/observation/ClientObservationContext.java 63.63% <63.63%> (ø)
.../server/observation/ServiceObservationContext.java 63.63% <63.63%> (ø)
...corp/armeria/server/docs/ServiceSpecification.java 91.66% <72.72%> (-3.72%) ⬇️
...servation/DefaultServiceObservationConvention.java 89.23% <89.23%> (ø)
...armeria/server/observation/ObservationService.java 89.47% <89.47%> (ø)
...bservation/HttpClientObservationDocumentation.java 91.42% <91.42%> (ø)
...servation/HttpServiceObservationDocumentation.java 91.42% <91.42%> (ø)
.../armeria/client/observation/ObservationClient.java 91.89% <91.89%> (ø)
...vation/DefaultHttpClientObservationConvention.java 96.92% <96.92%> (ø)
... and 4 more

... and 19 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

@ikhoon ikhoon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @Dogacel!

@ikhoon ikhoon merged commit 20b4ca4 into line:main Aug 18, 2023
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants