ardatan / graphql-mesh

🕸️ GraphQL Federation Framework for any API services such as REST, OpenAPI, Swagger, SOAP, gRPC and more...
https://the-guild.dev/graphql/mesh
MIT License
3.29k stars 345 forks source link

Additional resolver doesn't work after mutation #3180

Open NicolasMahe opened 2 years ago

NicolasMahe commented 2 years ago

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:

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:

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.

antho1404 commented 2 years ago

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.

ardatan commented 2 years ago

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