Setup & resolvers
The GraphQL variant is a layer over the base template. The CLI copies the base template, then overwrites shared files with GraphQL-aware versions. The same AuthenticationService and UserService are used by both REST and GraphQL resolvers.
Module setup
Section titled “Module setup”AppModule in the GraphQL variant adds GraphQLModule with the Apollo driver:
GraphQLModule.forRootAsync<ApolloDriverConfig>({ driver: ApolloDriver, imports: [CommonModule], useFactory: ( graphqlConfiguration: ConfigType<typeof graphqlConfig>, userDataLoader: UserDataLoader, ) => ({ ...graphqlConfiguration, context: ({ req, res }) => { const loaders: IDataLoaders = { userLoader: userDataLoader.createLoader(), }; return { req, res, loaders }; }, }), inject: [graphqlConfig.KEY, UserDataLoader],})The context function is overridden to create a fresh set of DataLoaders per request.
Code-first schema
Section titled “Code-first schema”graphql.config.ts uses the code-first approach:
autoSchemaFile: join(process.cwd(), 'src/schema.gql'),sortSchema: true,debug: process.env.NODE_ENV !== 'production',TypeScript decorators on classes and fields define the schema. The schema file is generated automatically at startup and can be inspected for review.
Resolver anatomy
Section titled “Resolver anatomy”A resolver is a NestJS provider decorated with @Resolver. It injects services and maps GraphQL operations to them.
Authentication resolver
Section titled “Authentication resolver”@Resolver()export class AuthenticationResolver { constructor(private readonly authenticationService: AuthenticationService) {}
@UseGuards(LocalGuard) @Mutation(() => AuthResponseType) async login( @Context() ctx: { req: SessionRequest }, @CurrentUser() user: User, ): Promise<AuthResponseType> { return this.authenticationService.login(ctx.req, user); }}Login uses the same LocalGuard as the REST controller. The GraphQL guard maps args.loginInput onto request.body before Passport validates the credentials, so the resolver can use @CurrentUser() and the same AuthenticationService.login flow.
User resolver
Section titled “User resolver”@Resolver(() => UserType)export class UserResolver { constructor(private readonly userService: UserService) {}
@UseGuards(SessionAuthGuard) @Query(() => UserType) async currentUser(@CurrentUser() user: User): Promise<UserType> { return this.userService.findById(user.id); }}The same SessionAuthGuard and CurrentUser decorator work here because they detect GraphQL context.
Object types and inputs
Section titled “Object types and inputs”Object types define the schema output shape:
@ObjectType()export class UserType { @Field(() => ID) id: string;
@Field() email: string;
@Field() username: string;}Input types define the arguments for mutations:
@InputType()export class LoginInput { @Field() email: string;
@Field() password: string;}Running alongside REST
Section titled “Running alongside REST”The GraphQL variant still includes the REST authentication controller for OAuth callbacks. All other auth operations are exposed through the /graphql endpoint. Apollo Sandbox is available at /graphql in development.