Msw: graphql.link() doesn't intercept request

Created on 18 Aug 2020  路  9Comments  路  Source: mswjs/msw

Environment

| Name | Version |
| ---- | ------- |
| msw | 0.20.5 |
| node | 12.18.3 |
| OS | Ubuntu 20.04 |

Request handlers


  const serloApi = graphql.link('https://api.serlo.org/graphql')
  global.server.use(
    serloApi.query('_cacheKeys', async(req, res, ctx) =>{
      return res(
        ctx.data(
          await server.executeOperation({
            query: worker.queryLiteral,
          } as GraphQLRequest)
        )
      )
    })
  )
})

Actual request

import { GraphQLClient, gql } from 'graphql-request'
...
 private query = gql`{ _cacheKeys (first: 5, after: ...
await this.grahQLClient.request(this.query).then(async (data) =>  console.log('data: ', data))
...

Current behavior

The request by-passes the interceptor and goes to the actual server, which responds with 400 (since the feature doesn't exit yet).

Cannot query field "_cacheKeys" on type "Query".: {"response":{"errors":[{"message":"Cannot query field \"_cacheKeys\" on type \"Query\".","locations":[{"line":2,"column":7}],"extensions":{"code":"GRAPHQL_VALIDATION_FAILED"}}],"status":400},"request":{"query":"\n    { _cacheKeys (first: 5, after: \"\") { edges { cursor node } nodes totalCount  pageInfo { hasNextPage hasPreviousPage startCursor endCursor } } }\n  "}}

Expected behavior

To get the same response that I have when I mock the GraphQL server using the rest object

    data:  {
      _cacheKeys: {
        edges: [ [Object], [Object], [Object], [Object], [Object] ],
        nodes: [ 'key0', 'key1', 'key2', 'key3', 'key4' ],
        totalCount: 25,
        pageInfo: {
          hasNextPage: true,
          hasPreviousPage: false,
          startCursor: 'a2V5MA==',
          endCursor: 'a2V5NA=='
        }
      }
    }

To Reproduce

  1. git clone https://github.com/hugotiburtino/api.serlo.org.git (commit 80b09a)
  2. yarn install
  3. yarn test __tests__/worker.ts
graphql bug node

All 9 comments

Hi @hugotiburtino thanks for opening the issue :).

I have looked at your code and I think that your implementation is right. The problem I think is how graphql requests are handled in the parseQuery function

https://github.com/mswjs/msw/blob/2478051041092ccc376f8938e3b14fcc404135a6/src/graphql.ts#L76-L91.

The operation name from parse function is null for your case because _cacheKeys is a field name.

This makes me worry about another thing, in a single graphql request multiple query can be send but I think that this not handled.

A GraphQL request must be named in order to be matched with MSW. In your example you have an untitled request.

-{ _cacheKeys: {} }
+query GetCacheKeys { _cacheKeys: {} }

You use the name of the query when creating a request handler:

import { graphql } from 'msw'

graphql.query('GetCacheKeys', resolver)

We are currently elaborating on supporting an operation-based interception (#184), so stay tuned for updates.

@marcosvega91, I think you are right. Would you be interested in adding a new integration test to MSW to illustrate that we fail to handle a scenario when a single request contains multiple named GraphQL queries?

Thanks, that solved my issue

@marcosvega91, I think you are right. Would you be interested in adding a new integration test to MSW to illustrate that we fail to handle a scenario when a single request contains multiple named GraphQL queries?

Yes I'll create a test case :)

I have looked better to the spec and there is no official support for multi query in a single operation so I think that we are good for now 馃槃

I think there was a confusion over query name and fields. Each query has a single name, but may request multiple fields.

# `GetUser` is the name
query GetUser($userId: String!) {
  # `user` is a field
  user: {
    firstName
    lastName
  }
  # `subscriptions` is a field
  subscriptions: {
    filterBy(userId: $userId) {
      validUntil
    }
  }
}

Yes I thought that a single fetch with multiple operations could be possibile. Do we want to add a test case with your example?

I think there is no need. That test is going to assert that given JSON produces the respective response body. We already have such test.

Was this page helpful?
0 / 5 - 0 ratings