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.
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
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!
I have two schema files.
@apollo/client": "^3.3.11"
@apollo/react-hooks": "^4.0.0"
@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"
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
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!
}
@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
}
}
}
`;
npx graphql-codegen --config codegen.yml
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.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With