Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

apollo client:codegen typescript with @client query fields

Sorry if this is a bit involved, but I'm really trying to close the last mile on being able to use Apollo Client for local as well as server state, with automatic Typescript everywhere. To wit, I have a query like this:

query NavigationBarQuery($userId: Int, $portfolioCompanyId: Int!) {
  user(id: $userId) {
    id
    firstName
    lastName
    company {
      ... on CompanyInterface {
        companyType
      }
    }
  }
}

That is being imported by my NavigationBar component like so:

import { NavigationBarQuery, NavigationBarQueryVariables } from '../../../graphql/generated/NavigationBarQuery';
import NAVIGATION_BAR_QUERY from '../../../graphql/NavigationBarQuery.graphql';

const NavigationBar = (vars: NavigationBarQueryVariables) => (
  <Query query={NAVIGATION_BAR_QUERY} variables={vars}>
    {({ loading, error, data, client }: QueryResult<INavigationBarClientQuery>) => {

     // etc.

Generation is performed with a local schema file (dumped from Graphene) like so:

apollo client:codegen --localSchemaFile ./build/schema.json --includes './src/graphql/**' --target typescript

This works great, I get TypeScript types and everything.

However, I'd like to include some local state, with a query like this:

query NavigationBarQuery($userId: Int, $portfolioCompanyId: Int!) {
  user(id: $userId) {
    id
    firstName
    lastName
    company {
      ... on CompanyInterface {
        companyType
      }
    }
  }
  showNavbarUserInfo @client
}

This query works just fine if I bypass TypeScript, but when I attempt to generate Typescript definitions for it, the generation script emits this error:

.../client/src/graphql/NavigationBarQuery.graphql: Cannot query field "showNavbarUserInfo" on type "Query".
{ ToolError: Validation of GraphQL query document failed
    at Object.validateQueryDocument (/Users/gavin/.config/yarn/global/node_modules/apollo-language-server/lib/errors/validation.js:32:19)
    at Object.generate [as default] (/Users/gavin/.config/yarn/global/node_modules/apollo/lib/generate.js:19:18)
    at write (/Users/gavin/.config/yarn/global/node_modules/apollo/lib/commands/client/codegen.js:64:54)
    at Task.task (/Users/gavin/.config/yarn/global/node_modules/apollo/lib/commands/client/codegen.js:83:46) name: 'ToolError' }

What, if anything, is the workaround for this? As per usual, looking for examples.

like image 965
Gavin Avatar asked Dec 18 '18 19:12

Gavin


Video Answer


2 Answers

Providing an updated answer here because @cnp's answer is missing examples and contains broken links.

My examples use the new Apollo CLI (https://github.com/apollographql/apollo-tooling) with npx, although it can also be installed locally and used without the npx command.

You need to extend your schema with local-only fields by adding a new SDL file. Using the example queries from the original question, you would add a file (e.g. schema.graphql) with the following content:

extend type NavigationBar {
  showNavbarUserInfo: Boolean!
}

Optional: if you're using VS Code's Apollo GraphQL extension, now would be a good time to let it know where to find the new SDL file by adding it to the includes properly in apollo.config.js:

module.exports = {
  client: {
    includes: ['./schema.graphql'],
  },
};

Now include the showNavbarUserInfo @client local field in one of your queries, then run your code gen command to include your original schema.json file and your new schema.graphql file:

npx apollo codegen:generate --localSchemaFile=schema.json,schema.graphql --target=typescript --includes=src/**/*.tsx --tagName=gql --addTypename --globalTypesFile=src/types/global-types.ts types
like image 68
Johnny Oshika Avatar answered Sep 18 '22 09:09

Johnny Oshika


I just worked through this so hopefully this will help someone. And if your name actually is "Someone" and you just happen to be looking for this information; this IS totally for you!

My setup:

I have two schema files.

  • One that is pulled down form my GraphQL Server
  • A local schema file that contains the extended properties for storing values locally

Dependencies

  • @apollo/client": "^3.3.11"
  • @apollo/react-hooks": "^4.0.0"

DevDependencies

  • @graphql-codegen/add": "^2.0.2"
  • @graphql-codegen/cli": "^1.20.1"
  • @graphql-codegen/typescript-apollo-client-helpers": "^1.1.2"
  • @graphql-codegen/typescript-operations": "^1.17.14"
  • @graphql-codegen/typescript-react-apollo": "^2.2.1"
  1. For better usage, I recommend creating a codegen.yml file (unless you've watched a lot of hacker movies and think it's WAY more cool to use the console for all these options. Or, if you just want to... I'm not judging.)
#./codegen.yml
# See: https://graphql-code-generator.com/docs/getting-started/codegen-config
overwrite: true
schema:
  - "https://my-dev-server.com/v1/graphql":
      headers:
        'Authorization': 'Bearer [TOKEN]'
generates:
  graphql/generated/generated.ts:
    # This is the defined client side schema file. It will first load the root schema defined above, and then load this (see: https://graphql-code-generator.com/docs/getting-started/schema-field#local-graphql-files)
    schema: graphql/client-schema.graphql
    # This is where the gql queries/subscripts/mutations reside
    documents: "graphql/queries/**/*.ts"
    plugins:
      - add:
          content: /* eslint-disable */
      - typescript
      - typescript-operations
      - typescript-react-apollo
    config:
      withHooks: true

  1. Setup local schema file. Call it what you like, just make sure you set the value correctly in the codegen.yml. I've called mine client-schema.graphql since I'm super clever....
#./client-schema.graphql

# see: https://www.apollographql.com/docs/react/local-state/managing-state-with-field-policies/
directive @client on FIELD

type LocalStateType {
  companyId: String
  contactId: String
}

extend type Users {
  localState: LocalStateType!
}
  1. Once the above is in place and depending on your IDE, intellisense should start picking up the changes. You will need to use the @client directive on your query(s); like so:
export const QUERY_USER_BY_ID = gql`
  query getUserDetails($Id: uuid!) {
    Users_by_pk(Id: $Id) {
      EmailAddress
      Id
      localState @client {
        companyId
        contactId
      }
    }
  }
`;
  1. Run the command to generate the goods:
  • npx graphql-codegen --config codegen.yml

KEY NOTES

  • I've noticed that there is no errors displayed if you set the path incorrectly for the client (client-schema.graphql) file. However, you'll know you have it wrong if you don't see the generated data in the output referencing the @client data.

References:

  • https://graphql-code-generator.com/docs/getting-started/codegen-config
  • https://graphql-code-generator.com/docs/getting-started/schema-field#local-graphql-files
  • https://www.apollographql.com/docs/react/local-state/managing-state-with-field-policies/
like image 21
anAgent Avatar answered Sep 19 '22 09:09

anAgent