Differentiating a GraphQL query from a compatible REST API request #535
Replies: 9 comments 8 replies
-
The parsing of a GraphQL query body isn't a reliable way to determine a GraphQL request, because a failed parsing can indicate two things:
In the first case, the query error should be surfaced to the user. That's what would happen when communicating with an actual GraphQL server: it would throw an exception indicating what's wrong with the query is received. Since MSW acts as a "server", I find it a nice touch to be able to surface those parsing errors to the user. This is especially useful when there's no actual GraphQL server and people are using the mock-first approach in development. However, since a failed query parsing may also indicate a non-GraphQL request, surfacing the parsing error requires extra effort on the library's side. This again comes down to figuring out if the query/exception is related to an invalid query or not. |
Beta Was this translation helpful? Give feedback.
-
With the latest changes we've added an internal It can reliably determine if a given GET/POST request is a valid GraphQL request. However, it cannot distinguish if the request is not GraphQL-compatible (i.e. a POST request with a We can either extend that |
Beta Was this translation helpful? Give feedback.
-
The GraphQL requests differentiation has been improved with the introduction of the msw/src/utils/internal/parseGraphQLRequest.ts Lines 139 to 172 in 655c93f We can now distinguish between regular REST API requests and those that are GraphQL using the said utility. |
Beta Was this translation helpful? Give feedback.
-
@kettanaito Currently there is an issue to handle advanded graphql queries like:
This query is not detected as REST but not right detected as GRAPHQL neither:
Nobody use advanced graphql queries like this? Have you a quick fix in mind? Thanks! |
Beta Was this translation helpful? Give feedback.
-
@kettanaito I'm having trouble having a REST api call being mistaken as graphql with msw.
The input from:
console logs as:
My server handlers.ts includes graphql queries as well, but I would like for this one to be parsed as rest:
Is there anything I am not setting up correctly? Is it possible to mix graphql and rest calls in one handler?
Using |
Beta Was this translation helpful? Give feedback.
-
I've lined up a proposal to the GraphQL specification to adopt an identifier that'd allow distinguishing intended GraphQL requests from other requests. To my surprise, the working group behind the spec has already thought this through and has arrived at the very same conclusion that I'm suggesting! "GraphQL over HTTP" specification now encourages to use Read the GraphQL over HTTP spec I will remain in the discussion loop to see if this change is safe to suggest to GraphQL clients. I'd love to propagate this to Apollo, URQL, you-name-it so everybody has a decent experience. |
Beta Was this translation helpful? Give feedback.
-
Hi there, Is there currently a way for msw not to catch REST requests when the body contains |
Beta Was this translation helpful? Give feedback.
-
Have a thought for avoiding this in the case where users call graphql.link to define an endpoint first, which might be a good compromise here |
Beta Was this translation helpful? Give feedback.
-
For anyone coming along this discussion: In version 2.0.9 we shipped #1871 which should help differentiate graphql from rest requests and avoid the That version allows us to bail out of request parsing early if the endpoint is not specifically designated as a graphql endpoing when using To modify existing code: import {graphql, http} from 'msw'
+ const exampleGraphqlApi = graphql.link("https://example.com/graphql")
const worker = setupWorker(
- graphql.query('GetUser', ...),
+ exampleGraphqlApi.query('GetUser', ...),
http.post("https://example.com/users", ({ request }) => {
const {query} = await request.json()
})
) Before, we'd parse requests to this should also make it slightly more performant on large numbers of graphql handlers, since they'll parse less frequently |
Beta Was this translation helpful? Give feedback.
-
I'd like to discuss how to reliably differentiate a GraphQL query from a REST API request that has a compatible body/query string structure. This originates from #489.
The issue
In order for
graphql.*
handlers to work, they determine if the captured HTTP request is compatible with the GraphQL specification, specifically:GET
request with aquery
query string parameter.POST
request with aquery
property in its JSON body.Upon retrieval, the
query
is parsed using thegraphql
package to determine if the query itself is valid against the GraphQL specification. If there's noquery
, or it's invalid, the request is not captured by thegraphql.*
handler and is bypassed.The issue arises from regular REST API requests that also have the
query
but are not meant to be GraphQL queries. For example, you may have the following request:Since the aforementioned request satisfies one of the predicates for a
graphql.*
handler, MSW will attempt to parse itsbody.query
string as a GraphQL query declaration string. That operation will fail, and the exception will be thrown (?).Specification
There's nothing in the GraphQL specification that would reliably tell apart a GraphQL query and a seemingly compatible REST API request.
One of the solutions that may help:
graphql.operation
handler to limit requests interception to a certain endpoint. This way the consumer explicitly declares a certain endpoint as a GraphQL endpoint, so MSW can assume that requests to that endpoints are either valid or invalid GraphQL queries, but not regular REST API requests.Beta Was this translation helpful? Give feedback.
All reactions