graphql-mesh icon indicating copy to clipboard operation
graphql-mesh copied to clipboard

Additional resolver doesn't work after mutation

Open NicolasMahe opened this issue 2 years ago • 2 comments

Describe the bug

I get the error Expected undefined to be an input type when an additional resolver is executed after a mutation.

The same resolver works perfectly in a query.

This resolver is define in yaml and stitch some data from another source to the type return by the query or the mutation.

To Reproduce Steps to reproduce the behavior:

  • Setup with 2 sources. In my case it's a custom GraphQL API in Node and Postgraphile
  • Add a custom resolver to your .meshrc with an additional type def to a type you can query and create (for the mutation) on the custom GraphQL API server.
  • Make sure it's working by executing the query
  • Check the mutation, it should fail with Expected undefined to be an input type

Here is my partial .meshrc:

sources:
  - name: API
    handler:
      graphql:
        endpoint: ${API_URL}
  - name: Database
    handler:
      postgraphile:
        connectionString: ${DATABASE_URL}
additionalTypeDefs: |
  extend type Offer {
    makerAsset: Asset!
  }
additionalResolvers:
  - targetTypeName: Offer
    targetFieldName: makerAsset
    requiredSelectionSet: |
      {
        makerAssetId
      }
    sourceName: Database
    sourceTypeName: Query
    sourceFieldName: asset
    sourceArgs:
      id: '{root.makerAssetId}'

The query looks like (working):

query {
  offer(id: "a600728a-c4ce-4c9a-8530-ad323f8c87fe") {
    makerAsset {
      name
    }
  }
}

The not working mutation:

mutation createOffer($createOfferInput: OfferInput!) {
  createOffer(input: $createOfferInput) {
    id
    makerAssetId
    makerAsset {
      name
    }
  }
}

If I remove makerAsset, then it's working:

mutation createOffer($createOfferInput: OfferInput!) {
  createOffer(input: $createOfferInput) {
    id
    makerAssetId
  }
}

makerAssetId is returned with the right value

Environment:

  • OS: Mac Os
  • @graphql-mesh/cli: 0.43.6
  • @graphql-mesh/graphql: 0.20.3
  • @graphql-mesh/postgraphile: 0.16.1
  • NodeJS: v16

Additional context

I tried to replace the additional resolver with the typescript version but got the same problem.

Offer: {
    makerAsset: {
      selectionSet: `{
        makerAssetId
      }`,
      resolve: async (root, _args, context, info) => {
        try {
          const result = await context.Database.Query.asset({
            root,
            args: {
              id: root.makerAssetId,
            },
            context,
            info,
          })
          if (!result) throw new Error('result is false')
          return result
        } catch (error) {
          console.error(error)
          throw error
        }
      },
    },

The issue seems to come from the context.Database.Query.asset function. If I replace the functions and return directly a dummy object (eg {name: "hello"} ) it's working.

NicolasMahe avatar Nov 17 '21 10:11 NicolasMahe

I have a similar issue running a custom resolver across 2 sources (1 query + 1 mutation). This issue happens when I pass a variable to the initial request. This variable is passed to the subgraph creating a new operation that fails (certainly because the schema doesn't match the current type of the data anymore).

If it helps to debug/understand, by removing the operation created during the transformation here https://github.com/ardatan/graphql-tools/blob/a524d4da0ab768047c25bbaf8c9947ebabc035d0/packages/wrap/src/transforms/TransformInputObjectFields.ts#L87-L93, everything works as expected because it is not trying to transform the variable from the original request.

antho1404 avatar Dec 03 '21 03:12 antho1404

@yaacovCR any ideas? Maybe we have a bug in stitching that prevents query calls from a mutation somehow?

ardatan avatar Dec 28 '21 09:12 ardatan