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

Fix that overloaded methods are not displayed in DocService #4545

Merged
merged 9 commits into from
Dec 6, 2022

Conversation

minwoox
Copy link
Contributor

@minwoox minwoox commented Nov 21, 2022

Motivation:
Overloaded methods in annotated services are not displayed correctly in DocService.
Armeria DocService was built for Thrift services in which overloading methods are not possible, so we didn't consider overloaded methods at that time.
Also, it was for Thrift types, the TypeSignature wasn't structured well to represent other types used in gRPC and annotated services.

Modifications:

  • Add id to MethodInfo that uniquely identifies each method.
    • It is formed of serviceName/methodName/httpMethod
    • The methodName has increased -n at the end when the method is overloaded.
  • Fix a bug where parsing the same named type recursively.
  • (Breaking)
    • Interface TypeSigniture.
      • Add subclasses with TypeSignatureType that represents each TypeSignature
      • NamedTypeInfo.findNamedTypes() now returns Set<NamedTypeSignature>.

Result:

  • You can now send a debug request via DocService when the method is overloaded.
  • Well-structured TypeSignature

To-do:

  • Add JsonSchemaType to TypeSignature for creating the JSON schema easily.

Copy link
Contributor

@Dogacel Dogacel left a comment

Choose a reason for hiding this comment

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

Does front-end need to know about overloadId?

Comment on lines 141 to 143
println(json5Mapper.writerWithDefaultPrettyPrinter().writeValueAsString(response.get("services").get(0).get("methods")))


Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like a leftover

m.httpMethod === props.match.params.httpMethod,
);
const id = `${params.serviceName}/${params.methodName}/${params.httpMethod}`;
const method = service.methods.find((m) => m.id === id);
Copy link
Contributor

Choose a reason for hiding this comment

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

👍 Great to see this change, did we have issues with overlapping method names from different services in the previous version?

Copy link
Contributor Author

@minwoox minwoox Nov 21, 2022

Choose a reason for hiding this comment

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

overlapping method names from different services in the previous version?

No, we didn't have such an issue. We have issues only with the same service. For example:

class MyAnnotatedService {
    @Get("/foo)
    public HttpResponse foo() {...}

    @Get("/foo1)
    public HttpResponse foo(MyType type) {...}    <--- This isn't rendered.
}

class YourAnnotatedService {
    @Get("/foo2)
    public HttpResponse foo() {...} // Rendered correctly
}

@@ -354,7 +373,7 @@ private static void addMarkdownDescriptionMethodInfo(Map<Class<?>, Set<MethodInf
.descriptionInfo(DescriptionInfo.of("DESCRIPTION `PARAM`", Markup.MARKDOWN))
.build());
final MethodInfo methodInfo = new MethodInfo(
"description", STRING, fieldInfos, ImmutableList.of(),
MyService.class.getName(), "description", 0, STRING, fieldInfos, ImmutableList.of(),
Copy link
Contributor

Choose a reason for hiding this comment

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

just double-checking, does this include the package name?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes and let me show later how we find the corresponding struct in StructInfo or enum in EnumInfo later. 😉

/**
* Container type.
*/
CONTAINER(true, false),
Copy link
Contributor

Choose a reason for hiding this comment

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

What is an example for a container type? Maybe generics? Like Id<T> ?

Copy link
Contributor Author

@minwoox minwoox Nov 21, 2022

Choose a reason for hiding this comment

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

One example would be:

Of course, we cannot represent this type with JSON schema so I'm thinking we just need to omit such fields
and add "additionalProperties": "true"

Copy link
Contributor

Choose a reason for hiding this comment

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

If it is something simple like public class Box<T> { public T shape; ... } I guess FieldInfo will already contain what we have put inside T right? If not, the user might need to find out that from additional properties (which seems mostly redundant, I agree with you.)

@@ -254,41 +255,7 @@
"location": "UNSPECIFIED",
"requirement": "OPTIONAL",
"typeSignature": "armeria.protobuf.testing.SimpleOneof",
"childFieldInfos": [
Copy link
Contributor

Choose a reason for hiding this comment

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

Just double checking, are we removing childFieldInfos from the return type signatures for all types? What is this about?

Copy link
Contributor Author

@minwoox minwoox Nov 21, 2022

Choose a reason for hiding this comment

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

It's a bug. There's a recursion so I removed it. You can find armeria.protobuf.testing.SimpleOneof" in two levels above.

@codecov
Copy link

codecov bot commented Nov 21, 2022

Codecov Report

Base: 74.08% // Head: 74.05% // Decreases project coverage by -0.02% ⚠️

Coverage data is based on head (ce97d4c) compared to base (b127cd2).
Patch coverage: 89.26% of modified lines in pull request are covered.

❗ Current head ce97d4c differs from pull request most recent head 63cc314. Consider uploading reports for the commit 63cc314 to get more accurate results

Additional details and impacted files
@@             Coverage Diff              @@
##             master    #4545      +/-   ##
============================================
- Coverage     74.08%   74.05%   -0.03%     
+ Complexity    18190    18186       -4     
============================================
  Files          1537     1542       +5     
  Lines         67432    67530      +98     
  Branches       8533     8549      +16     
============================================
+ Hits          49959    50012      +53     
- Misses        13401    13438      +37     
- Partials       4072     4080       +8     
Impacted Files Coverage Δ
...er/annotation/ReflectiveNamedTypeInfoProvider.java 88.46% <0.00%> (ø)
...om/linecorp/armeria/server/docs/NamedTypeInfo.java 0.00% <ø> (-100.00%) ⬇️
...rp/armeria/server/docs/ContainerTypeSignature.java 62.50% <62.50%> (ø)
...a/internal/server/annotation/AnnotatedService.java 87.89% <66.66%> (-0.29%) ⬇️
...necorp/armeria/server/docs/NamedTypeSignature.java 76.19% <76.19%> (ø)
...a/com/linecorp/armeria/server/docs/MethodInfo.java 74.72% <83.33%> (+0.97%) ⬆️
...corp/armeria/server/docs/DefaultTypeSignature.java 84.21% <84.21%> (ø)
...erver/annotation/DefaultNamedTypeInfoProvider.java 92.71% <87.50%> (-0.39%) ⬇️
...a/com/linecorp/armeria/server/docs/DocService.java 90.66% <89.01%> (-3.14%) ⬇️
...server/protobuf/ProtobufNamedTypeInfoProvider.java 89.00% <91.66%> (+0.11%) ⬆️
... and 43 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

@minwoox
Copy link
Contributor Author

minwoox commented Nov 21, 2022

Does front-end need to know about overloadId?

Nope. MethodInfo.id() has the overloadId in it and it's all the front-end needs. 😄

m.name === props.match.params.methodName &&
m.httpMethod === props.match.params.httpMethod,
);
const id = `${params.serviceName}/${params.methodName}/${params.httpMethod}`;
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we include overloadId here as well then?

Copy link
Contributor Author

@minwoox minwoox Nov 21, 2022

Choose a reason for hiding this comment

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

No, we shouldn't. 😉
params.methodName is the path parameter that is inserted from the Router.

path="/methods/:serviceName/:methodName/:httpMethod"

It could be overload-1 which already has the overloadId if a user types or navigates through the link.

Copy link
Contributor Author

@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.

@ikhoon Addressed your comments so PTAL.
Thanks a lot for the detailed review. 😉

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, @minwoox and @Dogacel! 🚀🚀

@@ -412,7 +419,7 @@ static TypeSignature toTypeSignature(Type type) {
return TypeSignature.ofList(toTypeSignature(clazz.getComponentType()));
}

return TypeSignature.ofNamed(clazz);
return TypeSignature.ofStruct(clazz);
Copy link
Contributor

Choose a reason for hiding this comment

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

👍


@Override
public String signature() {
return name() + '<' + Joiner.on(", ").join(typeParameters) + '>';
Copy link
Contributor

Choose a reason for hiding this comment

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

Joiner.on(...) creates a new object. Should we use a static variable?
https://github.com/google/guava/wiki/StringsExplained#joiner

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copied the previous logic without much thinking. 😅 Thanks!

requireNonNull(namedTypeInfoProviders, "namedTypeInfoProviders");
for (NamedTypeInfoProvider typeInfoProvider : namedTypeInfoProviders) {
namedTypeInfoProvider(typeInfoProvider);
public DocServiceBuilder descriptiveTypeInfoProvider(
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems like I missed adding @UnstableApi. 😅 Could you add it to this method and below?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops, added. 😉

@@ -169,7 +209,7 @@ public MethodInfo withParameters(Iterable<FieldInfo> parameters) {

return new MethodInfo(name, returnTypeSignature, parameters, exceptionTypeSignatures, endpoints,
exampleHeaders, exampleRequests, examplePaths, exampleQueries, httpMethod,
descriptionInfo);
descriptionInfo, id);
Copy link
Contributor

Choose a reason for hiding this comment

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

Oops... I found the Javadoc is incorrect. Could you fix it as well? 😅

@minwoox
Copy link
Contributor Author

minwoox commented Dec 6, 2022

Let me merge this so I can continue to add JSON schema type for @Dogacel's work.
Thanks for reviewing. 😉

@minwoox minwoox merged commit ef64fde into line:master Dec 6, 2022
@minwoox minwoox deleted the fix_docservice_overload branch December 6, 2022 09:10
@Dogacel
Copy link
Contributor

Dogacel commented Dec 6, 2022

@minwoox Thanks a lot 🙇 I haven't been able to look at armeria for the last couple of weeks because this PR was waiting on open status. Are there any help needed? I expect the changes to be trivial, mostly enum logic will change.

@minwoox
Copy link
Contributor Author

minwoox commented Dec 6, 2022

Are there any help needed? I expect the changes to be trivial, mostly enum logic will change.

Yes, I need your help. 😄
I am planning to send the follow-up PR that adds JSON schema type and adds references for look-up. Please take a look at it and give feedback if there's anything I need to make change for your #4518.

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.

3 participants