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

Enable jsonschema support in debug page for annotated too #5253

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

anuraaga
Copy link
Collaborator

Motivation:

Annotated services can define JSON bodies which benefit from autocomplete.

Modifications:

Query for JSON schema for annotated services too when there is a body parameter by setting it as the "root parameter", have docs client always render with autocomplete when there is a root parameter regardless of service type.

Result:

Annotated services with a request body can take advantage of autocomplete

Copy link
Collaborator Author

@anuraaga anuraaga left a comment

Choose a reason for hiding this comment

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

I'm not super familiar with annotated service but tried making this PR, as in my go implementation I'm also trying to add support for REST, and want it to also have autocomplete :)

https://github.com/curioswitch/go-docs-handler/pull/2/files

I tried running AnnotatedDocServiceTest and could get completion in the JSON method, so AFAICT this should be pretty nice for annotated users if the change makes sense.

/**
* Creates a new instance.
*/
public MethodInfo(String serviceName, String name,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I have added yet more craziness to this file. Hopefully not for this PR, but probably need to get a builder in

@@ -130,7 +152,6 @@ public MethodInfo(String serviceName, String name,

this.returnTypeSignature = requireNonNull(returnTypeSignature, "returnTypeSignature");
this.parameters = ImmutableList.copyOf(requireNonNull(parameters, "parameters"));
assert !useParameterAsRoot || this.parameters.size() == 1;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I could tweak the assertion to look for a single root parameter but it seemed like overkill

@ikhoon ikhoon added this to the 1.27.0 milestone Oct 23, 2023
@codecov
Copy link

codecov bot commented Oct 23, 2023

Codecov Report

Attention: Patch coverage is 96.77419% with 1 line in your changes missing coverage. Please review.

Project coverage is 74.11%. Comparing base (b8eb810) to head (d8af561).
Report is 272 commits behind head on main.

Current head d8af561 differs from pull request most recent head b41f945

Please upload reports for the commit b41f945 to get more accurate results.

Files Patch % Lines
...l/server/annotation/AnnotatedDocServicePlugin.java 96.15% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #5253      +/-   ##
============================================
+ Coverage     73.95%   74.11%   +0.15%     
- Complexity    20115    20982     +867     
============================================
  Files          1730     1819      +89     
  Lines         74161    77324    +3163     
  Branches       9465     9879     +414     
============================================
+ Hits          54847    57308    +2461     
- Misses        14837    15365     +528     
- Partials       4477     4651     +174     

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

@anuraaga
Copy link
Collaborator Author

anuraaga commented Nov 6, 2023

Hello - I think things were hectic with release when sending this but is it possible to get a review now? 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.

Although I do think the current change will cover most cases, let me think a little more of a way to filter out false-positive cases

@@ -130,6 +130,7 @@ private ObjectNode generate(MethodInfo methodInfo) {
methodFields = ImmutableList.of();
} else {
methodFields = structInfo.fields();
root.put("useParamaterAsRoot", true);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
root.put("useParamaterAsRoot", true);
root.put("useParameterAsRoot", true);

methodInfos.computeIfAbsent(serviceClass, unused -> new HashSet<>()).add(methodInfo);
});
List<FieldInfo> fieldInfos = fieldInfos(service.annotatedValueResolvers());
boolean useParamaterAsRoot = false;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
boolean useParamaterAsRoot = false;
boolean useParameterAsRoot = false;


const hasJsonSchema = useMemo(() => {
const schema = jsonSchemas.find((s: any) => s.$id === method.id);
if (schema && (schema.useParamaterAsRoot || forceJsonSchema)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if (schema && (schema.useParamaterAsRoot || forceJsonSchema)) {
if (schema && (schema.useParameterAsRoot || forceJsonSchema)) {

@@ -130,7 +152,6 @@ public MethodInfo(String serviceName, String name,

this.returnTypeSignature = requireNonNull(returnTypeSignature, "returnTypeSignature");
this.parameters = ImmutableList.copyOf(requireNonNull(parameters, "parameters"));
assert !useParameterAsRoot || this.parameters.size() == 1;
Copy link
Contributor

Choose a reason for hiding this comment

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

Note: the following is also a valid method that has multiple resolvers, but uses headers/query params instead of the body to fill the bean.

Since the last non-param/query will be used, in the worst case it is possible that wrong autocomplete/recommendations are done.

@Post("/bean2")
public HttpResponse bean2(@RequestObject JsonRequest jsonRequest, CompositeBean compositeBean1) {
    return HttpResponse.of("world");
}

Having said this, I'm not sure if there is a non-trivial way to intelligently find the parameter that should be used as the body.
Let me think about this a little more..

@jrhee17
Copy link
Contributor

jrhee17 commented Nov 14, 2023

Hey, sorry about the late update. So talked with the team and a couple of ideas:

I think one of the concerns was autocompletion for the wrong schema which may confuse users.

  1. Introduce a new @JsonSchema annotation which accepts a class (or json schema url). Only annotated service methods annotated with this annotation will be available for autocompletion.
    e.g.
@JsonSchema(class = JsonRequest.class)
public void hello(JsonRequest jsonRequest, Bean bean) {
}

The downsides of this idea was that

  1. Users have to manually add the above annotation to each method to enable autocomplete
  2. We still can't know perfectly how the user intends to deserialize the request. For instance, the user may add a custom RequestConverterFunction which may differ from the JsonRequest schema.
  1. Just add autocompletion for all possible parameters.

We accept that we can't know for sure how exactly the user would like to deserialize the request. For this reason, we disable the monaco validate option for annotated services, and just offer autocompletion for all parameters that seem like a request body as a best-effort.

  1. Also pass RequestConverterFunction information as part of the doc service schema.

And the user can choose which RequestConverterFunction they would like to use.
Each RequestConverterFunction can define how they would like to define the json schema, and this information can be sent down to the doc service.

This approach probaby requires a lot of changes.

cc. @line/dx let me know if I missed/misunderstood any ideas.


Alternatively, if all of these approaches sounds like too much, I think it's also reasonable to add client-side changes only for this iteration. (since I heard that you are working on a separate server implementation which also tries to use the doc service)

@minwoox minwoox modified the milestones: 1.27.0, 1.28.0 Jan 24, 2024
@jrhee17
Copy link
Contributor

jrhee17 commented Apr 4, 2024

Haven't forgotten about this issue, but there's a lot going on at the moment 😅 Let me try to brainstorm a little more before the next release

@jrhee17 jrhee17 modified the milestones: 1.28.0, 1.29.0 Apr 4, 2024
@github-actions github-actions bot added the Stale label May 5, 2024
@anuraaga
Copy link
Collaborator Author

anuraaga commented May 7, 2024

@jrhee17 Sorry for letting this PR be stale, haven't been heads-down in Java enough to give a deep thought on it and it hasn't been on my critical path yet. Happy to make some changes though if we decide on an approach to take.

@github-actions github-actions bot removed the Stale label May 8, 2024
@minwoox minwoox modified the milestones: 1.29.0, 1.30.0 May 21, 2024
@github-actions github-actions bot added the Stale label Jun 21, 2024
@ikhoon ikhoon modified the milestones: 1.30.0, 1.31.0 Aug 1, 2024
@github-actions github-actions bot removed the Stale label Aug 2, 2024
@github-actions github-actions bot added the Stale label Sep 9, 2024
@jrhee17 jrhee17 modified the milestones: 1.31.0, 1.32.0 Nov 5, 2024
@github-actions github-actions bot removed the Stale label Nov 10, 2024
@github-actions github-actions bot added the Stale label Dec 16, 2024
@minwoox minwoox modified the milestones: 1.32.0, 1.33.0 Feb 11, 2025
@github-actions github-actions bot removed the Stale label Feb 17, 2025
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.

4 participants