Skip to main content

Extending the GraphQL API

This guide explains how to add new queries, mutations, types, and OAuth scopes to the GraphQL API.

Architecture Overview

The GraphQL implementation is split between two packages:

PackagePurpose
packages/shared-graphql/Schema definitions (.graphql files), generated types, OAuth scope definitions
apps/web/src/lib/graphql/Resolvers, server configuration, Apollo Client

Adding a New Domain

To add a new domain (e.g., project/):

1. Create the Schema

Create packages/shared-graphql/src/schemas/project/schema.graphql with type definitions, inputs, responses, and query/mutation extensions.

2. Update Codegen Configuration

Add the schema path to packages/shared-graphql/codegen.ts in the schema array.

3. Generate Types

Run nx generate shared-graphql to regenerate TypeScript types.

4. Update Schema Loader

Add the new schema to apps/web/src/lib/graphql/schema.ts.

5. Create Resolvers

Create apps/web/src/lib/graphql/project/resolvers.ts with resolver implementations.

6. Register Resolvers

Add resolvers to apps/web/src/lib/graphql/resolvers.ts.

Adding a New Type

  1. Define TypeScript type in packages/shared-types/src/lib/core.ts
  2. Add GraphQL type to appropriate .graphql file in packages/shared-graphql/src/schemas/
  3. Run nx generate shared-graphql to regenerate types using GraphQL Code Generator
  4. Implement resolvers if needed

Adding a New Query

  1. Add query definition to the appropriate .graphql schema file using extend type Query
  2. Run nx generate shared-graphql
  3. Implement resolver in the domain's resolvers.ts
  4. Register in main resolvers.ts

Adding a New Mutation

  1. Add mutation definition to the appropriate .graphql schema file using extend type Mutation
  2. Run nx generate shared-graphql
  3. Implement resolver with input validation
  4. Register in main resolvers.ts

Adding a New OAuth Scope

1. Update Scope Type

Add the new scope to packages/shared-graphql/src/types.ts in the OAuthScope type.

2. Update Default Scopes (Optional)

If the scope should be granted to all authenticated users by default, add it to DEFAULT_SCOPES.

3. Use in Resolvers

Use requireScope(context, "your-scope:read") in resolver implementations.

NX Commands

CommandDescription
nx generate shared-graphqlGenerate TypeScript types from GraphQL schemas
nx build shared-graphqlBuild the shared-graphql package
nx lint shared-graphqlLint the shared-graphql package
nx test webTest the web app (includes GraphQL resolver tests)

Best Practices

  1. Keep schemas in shared-graphql - Schema definitions should be in packages/shared-graphql/src/schemas/
  2. Use .graphql files - Keep schema definitions in .graphql files for better tooling
  3. Run generate after schema changes - Always run nx generate shared-graphql after modifying schemas
  4. Use response wrappers - Return { data, error } objects instead of throwing errors
  5. Validate inputs - Check all input fields and return clear error messages
  6. Use scopes for authorization - Prepare for OAuth by using requireScope()
  7. Use database repositories - Put database logic in packages/shared-db, not resolvers

Reference Files

FilePurpose
packages/shared-graphql/src/types.tsOAuth scopes and context types
packages/shared-graphql/codegen.tsCode generation configuration
apps/web/src/lib/graphql/schema.tsSchema loader
apps/web/src/lib/graphql/resolvers.tsCombined resolvers
apps/web/src/lib/graphql/common/utils.tsHelper functions