Learning @ nestjs/graphql

  • Comparison between GraphQL and REST

Rely on

  • @nestjs/ GraphQL is a separate NPM package
  • graphql-tools
  • graphql
  • apollo-server-express
  • apollo-server-fastify

GraphQLModule and forRoot ()

The connection between Nestjs and GraphQL is via the GraphQLModule, where the parameters in forRoot are the relevant nips passed to ApolloServer

import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';

@Module({
  imports: [
    GraphQLModule.forRoot({}),
  ],
})
export class AppModule {}
Copy the code

What is the first rule when writing GraphQL code?

  • All use TypeScript code
  • Use GraphQL’s native schema

Here are some suggestions for GraphQL coding

The code is preferred

What is code first? If you’re used to writing code in TypeScript, you can use TypeScript to map to GraphQL Schema files. The code-first advantage is that we can write code in the TypeScript language. In NestJS we have an automatic generator. Add autoSchemaFile directly to the graphqlModule. forRoot({}) configuration item to automatically generate Schema files to the specified path.

GraphQLModule.forRoot({
  autoSchemaFile: join(process.cwd(), 'src/schema.gql'),}),Copy the code

Schema preference

Shema first rule: Write graphQL files directly. It is also very easy to identify GraphQL and configure typePaths to the specified file path.

GraphQLModule.forRoot({
  typePaths: ['./**/*.graphql'],}).Copy the code

Schema first is not enough to write code; we also need type definitions to constrain (types and interfaces) our TypeScript code. NestJS has solved this problem and can also generate directly. There are two ways to generate.

  • automatic
GraphQLModule.forRoot({
  typePaths: ['./**/*.graphql'],
  definitions: {
    path: join(process.cwd(), 'src/graphql.ts'),
    outputAs: 'class',}}),Copy the code
  • manual
// generate-typings.ts
import { GraphQLDefinitionsFactory } from '@nestjs/graphql';
import { join } from 'path';

const definitionsFactory = new GraphQLDefinitionsFactory();
definitionsFactory.generate({
  typePaths: ['./src/**/*.graphql'],
  path: join(process.cwd(), 'src/graphql.ts'),
  outputAs: 'class'});Copy the code

GraphQL Resolver

Resolvers are just like Controllers, but the idea is different.

  • Resolver is a class modified by Resolver. The contents of the class are the operations related to the GraphQL query. These operations include:
    • Query Query, decorated with the Query decorator
    • Mutation, modified with Mutation modifier
    • Subscription, decorated with the Subscription decorator

In Resolver, the logic processing of response is actually done according to parameters.

The Resolver inner class learns a function name, which is used directly when querying, and passes the corresponding parameters

import { NotFoundException } from '@nestjs/common';
import { Args, Mutation, Query, Resolver, Subscription } from '@nestjs/graphql';
import { PubSub } from 'apollo-server-express';
import { NewRecipeInput } from './dto/new-recipe.input';
import { RecipesArgs } from './dto/recipes.args';
import { Recipe } from './models/recipe';
import { RecipesService } from './recipes.service';

const pubSub = new PubSub();

@Resolver(of= > Recipe)
export class RecipesResolver {
  constructor(private readonly recipesService: RecipesService) {}

  @Query(returns= > Recipe)
  async recipe(@Args('id') id: string) :Promise<Recipe> {
    const recipe = await this.recipesService.findOneById(id);
    if(! recipe) {throw new NotFoundException(id);
    }
    return recipe;
  }

  @Query(returns= > [Recipe])
  recipes(@Args() recipesArgs: RecipesArgs): Promise<Recipe[]> {
    return this.recipesService.findAll(recipesArgs);
  }

  @Mutation(returns= > Recipe)
  async addRecipe(
    @Args('newRecipeData') newRecipeData: NewRecipeInput,
  ): Promise<Recipe> {
    const recipe = await this.recipesService.create(newRecipeData);
    pubSub.publish('recipeAdded', { recipeAdded: recipe });
    return recipe;
  }

  @Mutation(returns= > Boolean)
  async removeRecipe(@Args('id') id: string) {
    return this.recipesService.remove(id);
  }

  @Subscription(returns= > Recipe)
  recipeAdded() {
    return pubSub.asyncIterator('recipeAdded'); }}Copy the code

reference

  • Apollo-Server PubSub