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

[RFC] GraphQL requests identifier #938

Closed
kettanaito opened this issue Apr 4, 2022 · 3 comments
Closed

[RFC] GraphQL requests identifier #938

kettanaito opened this issue Apr 4, 2022 · 3 comments

Comments

@kettanaito
Copy link

kettanaito commented Apr 4, 2022

Hello.

I'd like to propose an addition to the GraphQL specification regarding how GraphQL requests are being made. In particular, I'm talking about an identifier that would allow to reliably discern a GraphQL request from any other request, even if similar.

Use case

Consider writing a function that accepts an arbitrary request and returns a Boolean indicating whether this request is a GraphQL request or not.

function isGraphQLRequest(request: Request): boolean {}

Here are some examples of input:

Valid GraphQL request

POST https://example.com/graphql
Content-Type: application/json

{
  "query": "query GetUser { user { name } }"
}

Invalid GraphQL request

POST https://example.com/graphql
Content-Type: application/json

{
  "query": "query GetUser { user { name"
}

Notice the invalid query string.

Seemingly compatible HTTP request

POST https://example.com/resource
Content-Type: application/json

{
  "query": "{\"managers\":\"yarn\"}"
}

As a result, the isGraphQLRequest function needs to distinguish between 3 scenarios:

  • A valid, intentional GraphQL request (1st scenario).
  • An invalid, intentional GraphQL request (2nd scenario).
  • A valid HTTP request which is compatible with a GraphQL request shape but is not intended to be a GraphQL request (3rd scenario).

In the current reality, discerning between scenarios 2 and 3 is impossible. If the code that determines this lives outside of the surface that performs a request, it's only left to assume, which is neither error prone nor reliable by any means.

Context

I acknowledge this is a somewhat unconventional use case. However, it saddens me that there is no way to look at a request and clearly and reliably state: yes, this is intended as a GraphQL request. The only way to do this is to know the GraphQL spec, which pushes the differentiation to the human brain, making machine analyzis impossible.

My use case comes from maintaining a library called Mock Service Worker. As the library is responsible for mocking both REST and GraphQL API, including mocking them simultaneously, it runs in an ambiguous context and needs to make decisions in guessing whether an intercepted request was intended as a GraphQL request.

You can see the amount of guessing we have to do here.

Before you comment

I acknowledge that GraphQL implements HTTP, and I'm not proposing to change this in any way. But I also hope for your acknowledgement that there may be arbitrary HTTP requests that are composed in a way compatible with how GraphQL requests are composed (GET + "query" parameter / POST + "query" JSON body property) while not intending to be GraphQL at all. I'm convinced there should be a clear indication on any GraphQL request describing its intention.

Proposed solutions

I propose for all GraphQL requests to have an Accept: application/graphql+json header.

  • This is not a breaking change.
  • The Accept header is whitelisted by CORS and other request validation mechanisms.
  • The Accept header, actually, starts to adequately represent the intended response.

Apart from the points above, this specific solution takes inspiration from a HAL JSON application/hal+json media type value and, in my opinion, falls under GraphQL intentions:

  • GraphQL operates with json, thus +json suffix indicating that.
  • <subformat>+json media types are compatible with the parental json media type.
  • GraphQL is a language, so it's safe to request a specific media type even if it extends JSON. When making a GraphQL request you don't expect any JSON, you expect a JSON response constructed per GraphQL specification. The Accept header should reflect that.

Closing thoughts

I'd love to discuss this in more detail. If there's an existing, reliable way to distinguish between a GraphQL request and a seemingly-compatible HTTP request—please include it in the comments below. But I'd still very much like for GraphQL requests to be clearly identifiable.

In addition to this proposal, I'm willing to:

  • Champion the changes to the specification related to the proposal.
  • Open pull requests in the most used GraphQL clients to adhere to this change (also doesn't require a breaking change on their side).
@benjie
Copy link
Member

benjie commented Apr 4, 2022

Good idea! However, GraphQL is independent of transport layer, so the GraphQL Spec itself is not where this detail belongs. Fortunately we have a "GraphQL over HTTP" spec that's currently in the works; you can find it here (where many of us have already agreed with this idea 👍):

https://github.com/graphql/graphql-over-http/blob/92b57a9179834318b6f15e1d23afc49368dd5e3c/spec/GraphQLOverHTTP.md#content-types

@kettanaito
Copy link
Author

kettanaito commented Apr 4, 2022

@benjie, thank you for your quick reply!

Oh wow, and that is precisely the thing I'm suggesting. That's some fantastic news.

Is it safe to propose GraphQL clients migrate to the application/graphql+json content type? I'd love for the ecosystem to adhere to this, I'd be happy to help them migrate.

@benjie
Copy link
Member

benjie commented Apr 5, 2022

Probably best to discuss that over on the GraphQL-over-HTTP repo, but I don't see any reason not to do this.

I'm going to close this since I think it's clear it's a discussion for the other repo 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants