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 to return the proper media type in GraphqlService #4451

Merged
merged 3 commits into from
Sep 28, 2022

Conversation

minwoox
Copy link
Member

@minwoox minwoox commented Sep 27, 2022

Motivation:
According to the spec, we respect the accept header first.
If there's no accept header, we should return using application/json before 2025 year and application/graphal-response json after that.

Modification:

Result:

  • GraphqlService now respects the accept header correctly.

Motivation:
The default produce type for a GraphQL response has been changed to `application/graphql-response json` from `application/graphal json`.
We can't just change the default produce type at the moment because it will break the backward compatibility.
Instead, we provide a way to set default produce type so that the service owner can choose the default produce type.

Modification:
- Add `GraphqlServiceBuilder.defaultProduceType(type)`
- Respect accept header first in `GraphqlService` as described in the spec.
  - See https://github.com/graphql/graphql-over-http/blob/main/spec/GraphQLOverHTTP.md#body

Result:
- You can now set the default produce type for a GraphQL response.
@codecov
Copy link

codecov bot commented Sep 27, 2022

Codecov Report

Base: 74.06% // Head: 74.08% // Increases project coverage by 0.02% 🎉

Coverage data is based on head (49927df) compared to base (529738c).
Patch coverage: 80.00% of modified lines in pull request are covered.

Additional details and impacted files
@@             Coverage Diff              @@
##             master    #4451       /-   ##
============================================
  Coverage     74.06%   74.08%    0.02%     
- Complexity    18107    18112        5     
============================================
  Files          1527     1527              
  Lines         67103    67107        4     
  Branches       8484     8483       -1     
============================================
  Hits          49698    49717       19     
  Misses        13351    13337      -14     
  Partials       4054     4053       -1     
Impacted Files Coverage Δ
.../armeria/server/graphql/DefaultGraphqlService.java 79.59% <ø> (ø)
...armeria/server/sangria/SangriaGraphqlService.scala 64.70% <0.00%> (-1.97%) ⬇️
...meria/spring/AbstractArmeriaAutoConfiguration.java 71.42% <ø> (ø)
...spring/ArmeriaServerGracefulShutdownLifecycle.java 95.23% <ø> ( 9.52%) ⬆️
...in/java/com/linecorp/armeria/common/MediaType.java 97.08% <100.00%> ( 0.01%) ⬆️
.../internal/server/graphql/protocol/GraphqlUtil.java 100.00% <100.00%> ( 6.66%) ⬆️
...ecorp/armeria/server/LengthBasedServiceNaming.java 75.00% <0.00%> (-16.67%) ⬇️
...armeria/internal/common/stream/SubscriberUtil.java 72.22% <0.00%> (-11.12%) ⬇️
...meria/client/DefaultDnsQueryLifecycleObserver.java 76.81% <0.00%> (-2.90%) ⬇️
.../armeria/client/endpoint/dns/DnsEndpointGroup.java 75.32% <0.00%> (-2.60%) ⬇️
... and 16 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.

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.

Thanks @minwoox ! 🙇 👍 🙇

}
}

public static MediaType produceType(RequestHeaders headers, MediaType defaultProduceType) {
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 take a function to select a response type dynamically which would be useful to handle both legacy and new clients in a server?

public static MediaType produceType(ServiceRequestContext ctx, Function<ServiceRequestContext, MediaType> defaultProduceTypeFunction) {
     ...
}

...
GrpcService.builder()
           // statically set 
           .defaultProduceType(MediaType.GRAPHQL_JSON)
           // or dynamically choose
           .defaultProduceType(ctx -> {
               if (legacyclient) {
                   return MediaType.GRAPHQL_JSON;
               } else {
                   return MediaType.GRAPHQL_RESPONSE_JSON;
               }
           });

Copy link
Member Author

Choose a reason for hiding this comment

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

Should we take a function to select a response type dynamically

Is there any usage to select the type dynamically except using accept header which we are already handling?

Copy link
Contributor

Choose a reason for hiding this comment

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

defaultProduceType is used when Accept header is empty.
As per Legacy watershed, the response content-type could be either application/json or application/graphql-response json.

Before 1st January 2025 (2025-01-01T00:00:00Z), if the client does not supply an Accept header, the server SHOULD treat the request as if it had Accept: application/json. From 1st January 2025 (2025-01-01T00:00:00Z), if the client does not supply an Accept header, the server SHOULD treat the request as if it had Accept: application/graphql-response json.

If an Accept header is absent, I imagine that a server could choose application/json for a legacy client and application/graphql-response json for a new client in corner cases.
But I'm not sure there is such a desire for that.

Copy link
Member Author

Choose a reason for hiding this comment

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

I imagine that a server could choose application/json for a legacy client and application/graphql-response json for a new client in corner cases.

If it's distinguishable, I think we can add the logic to our code. However, I thought it was hard to determine if the client is the legacy one or not.

Copy link
Contributor

Choose a reason for hiding this comment

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

User-Agent of clients may be used. In addition, GraphQL servers could switch to the response type after the deadline.
If you think it looks overkill, we add it later without breaking changes when there is a demand for it.

Copy link
Member Author

Choose a reason for hiding this comment

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

Had a chat with the team we found out that the current implementation does not respect spec.
If accept is empty, we should return application/json before 2025 year according to the spec.
So I will fix the current logic and remove the setter at the moment.

@minwoox minwoox changed the title Provide a way to set default produce type for GraphqlService Fix to return the proper media type in GraphqlService Sep 27, 2022
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.

Still looks good to me 👍

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!

@minwoox minwoox merged commit 9b12ce9 into line:master Sep 28, 2022
@minwoox minwoox deleted the graphql_defaultProduceType branch September 28, 2022 15:02
@minwoox
Copy link
Member Author

minwoox commented Sep 28, 2022

Thanks, reviewers. 😉

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