apollographql / graphql-tag

A JavaScript template literal tag that parses GraphQL queries
MIT License
2.33k stars 177 forks source link

String interpolation in local typedefs is not working. #528

Open NiklasMoss opened 3 years ago

NiklasMoss commented 3 years ago

What am I trying to do?

I'd like to dynamically define typedefs of local types based on props passed to my react component.

Why am I doing this?

I realise this is not the intended way of defining gql, however, I'm in the process of creating a React wrapper component around the Apollo Provider. The purpose of it is to make the process of mocking out data locally (as described here https://www.apollographql.com/docs/react/development-testing/client-schema-mocking/) more seamless with less boilerplate. I'm going for a declarative approach where the user can simply define an array of fields (name, graphQL type and optional implementation that will default to a sensible faker implementation for the graphQL type) that will make local fields available directly on the Query type as well as an array of types (name, fields and an optional nested type) which should make it possible to define arbitrary local schemas declaratively with no boilerplate.

What's the outcome at the moment?

Just to establish a baseline, the following is working just fine and allows me to run codegeneration from Apollo CLI and query the new local test field (with a @client directive) in my application

  const localTypeDefs = gql`
    extend type Query {
      test: String
    }
  `;

  const client = new ApolloClient({
    cache: new InMemoryCache(),
    uri: "https://localhost:4000/graphql",
    typeDefs: localTypeDefs,
    ...apolloClientOptions,
  });

If I change the qgl definition to look like this instead

  const name = "name";
  const graphQLType = "String";

  const localTypeDefs = gql`
    extend type Query {
      ${name}: ${graphQLType}
    }
  `;

I get the following error when running codegen Syntax Error: Expected Name, found ":". If I change the gql definition to this

  const testString = "test: String";

  const localTypeDefs = gql`
    extend type Query {
      ${testString}
    }
  `;

I get this error Syntax Error: Expected Name, found "}". on codegen. In general, it seems like everything after the interpolated string causes the compiler to emit this error on the next character. If I include the } in the testString, I get the error Syntax Error: Expected Name, found <EOF>..

Now, If I try to change to the function syntax instead so the localTypeDefs definition looks as follows:

  const testString = "test: String";

  const localTypeDefs = gql(`extend type Query { ${testString} } `);

The gql string is actually generated without any error, however, the codegeneration still fails with the error GraphQLError: Cannot query field "test" on type "Query" when I query for this field (the query hasn't change at all from the working baseline I posted at the top and if I change back to that without touching anything else, the codegen no longer complains about the query). Curiously, if I change the above back to the baseline implementation but keep the explicit function call instead of the implicit `` string as the following:

const localTypeDefs = gql(`
    extend type Query {
      test: String
    }
  `);

I still get the error GraphQLError: Cannot query field "test" on type "Query" but as soon as I change back to the base case, everything is working just fine.

jerelmiller commented 1 year ago

Hey @NiklasMoss 👋

Thanks for your patience on this issue. Are you still having problems or were you able to find a resolution? Out of curiosity, what codegen tool were you using for this?

FWIW, I was able to get a local schema with codegen working with GraphQL Code Generator and a local schema. Check out our Spotify showcase which has an example of this.

Here you can see the codegen config for the local schema which is able to generate types as expected. I realize the local schema here is in .graphql files instead of gql tags, but the approach should work similar either way.

Hope this helps! Any more info on the tooling you're using would be super helpful. Thanks!