DEV Community

loading...
Cover image for Building NestJS app boilerplate - Authentication, Validation, GraphQL and Prisma

Building NestJS app boilerplate - Authentication, Validation, GraphQL and Prisma

Nikita Kot
Software Engineer @ Cimpress || Bassist @ kafka. - https://kafkasteckou.bandcamp.com || Prague, Czech Republic
Updated on ・11 min read

The boilerplate app created by this tutorial is here.

⚠️⚠️⚠️ Update - 06 April 2020

NestJS version 7 was recently released. Many thanks to
johnbiundo who posted what changes have to be done for this version update. The github repository is also updated, you can check the changes I've made here.

Intro

NestJS is a relatively new framework in the Node world. Inspired by Angular and built on top of Express with full TypeScript support, it provides a scalable and maintainable architecture to your applications. NestJS also supports GraphQL - a robust query language for APIs with a dedicated, ready to use, @nestjs/graphql module (in fact, the module is just a wrapper around Apollo server).

In this tutorial we're going to build a boilerplate with all the basic features you will need to develop more complex applications. We will use Prisma as a database layer since it works extremely well with GraphQL APIs allowing you to map Prisma resolver to GraphQl API resolvers easily.

By the end of this article we will create a simple blog application, which will allow users to register, log-in and create posts.

Getting Started

NestJS

To start playing with NestJS you should have node (version >= 8.9.0) and npm installed. You can download and install Node from the official website.

After you have node and npm installed, let's install NestJS CLI and initialise a new project.

$ npm i -g @nestjs/cli
$ nest new nestjs-boilerplate
$ cd nestjs-boilerplate
Enter fullscreen mode Exit fullscreen mode

During the installation process you will be asked what package manager you want to use (yarn or npm). In this tutorial I'll be using npm, but if you prefer yarn, go for it.

Now let's run npm start. It will start the application on port 3000, so opening http://localhost:3000 in a browser will display a "Hello World!" message.

GraphQL

As mentioned above, we will use @nestjs/graphql module to setup GraphQL for our API.

$ npm i --save @nestjs/graphql apollo-server-express graphql-tools graphql
Enter fullscreen mode Exit fullscreen mode

After the packages are installed, let's create a configuration file for our GraphQL server.

$ touch src/graphql.options.ts
Enter fullscreen mode Exit fullscreen mode

The configuration will be passed to the underlying Apollo instance by NestJS. A more in depth documentation can be found here.

src/graphql.options.ts

import { GqlModuleOptions, GqlOptionsFactory } from '@nestjs/graphql';
import { Injectable } from '@nestjs/common';
import { join } from 'path';

@Injectable()
export class GraphqlOptions implements GqlOptionsFactory {
  createGqlOptions(): Promise<GqlModuleOptions> | GqlModuleOptions {
    return {
      context: ({ req, res }) => ({ req, res }),
      typePaths: ['./src/*/*.graphql'], // path for gql schema files
      installSubscriptionHandlers: true,
      resolverValidationOptions: {
        requireResolversForResolveType: false,
      },
      definitions: { // will generate .ts types from gql schema files
        path: join(process.cwd(), 'src/graphql.schema.generated.ts'),
        outputAs: 'class',
      },
      debug: true,
      introspection: true,
      playground: true,
      cors: false,
    };
  }
}
Enter fullscreen mode Exit fullscreen mode

Then register GraphQLModule and pass the configuration in application's main AppModule module.

src/app.module.ts

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

@Module({
  imports: [
    GraphQLModule.forRootAsync({
      useClass: GraphqlOptions,
    }),
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

You may have noticed I removed AppController and AppService from the main module. We don't need them since we will be using GraphQL instead of a REST api. The corresponding files can be deleted as well.

To test this setup out, let's create a simple graphql API schema.

$ mkdir src/schema 
$ touch src/schema/gql-api.graphql
Enter fullscreen mode Exit fullscreen mode

src/schema/gql-api.graphql

type Author {
    id: Int!
    firstName: String
    lastName: String
    posts: [Post]
}

type Post {
    id: Int!
    title: String!
    votes: Int
}

type Query {
    author(id: Int!): Author
}
Enter fullscreen mode Exit fullscreen mode

Running npm start will do two things:

  • Generate src/graphql.schema.generated.ts with typescript types which can be used in our source code.
  • Launch the server on port 3000.

We can now navigate to http://localhost:3000/graphql (default GraphQL API path) to see the GraphQL Playground.

graphql playground

Prisma

To run Prisma we need to install Docker, you can follow the installation guide here.

Linux users - you need to install docker-compose separately.

We will be running two containers - one for the actual database and a second one for the prisma service.

Create a docker compose configuration file in the root project directory.

$ touch docker-compose.yml
Enter fullscreen mode Exit fullscreen mode

And put the following configuration there.

docker-compose.yml

version: '3'
services:
  prisma:
    image: prismagraphql/prisma:1.34
    ports:
      - '4466:4466'
    environment:
      PRISMA_CONFIG: |
        port: 4466
        databases:
          default:
            connector: postgres
            host: postgres
            port: 5432
            user: prisma
            password: prisma
  postgres:
    image: postgres:10.3
    environment:
      POSTGRES_USER: prisma
      POSTGRES_PASSWORD: prisma
    volumes:
      - postgres:/var/lib/postgresql/data
volumes:
  postgres: ~
Enter fullscreen mode Exit fullscreen mode

Run docker compose in the root directory of the project. Docker compose will download images and start containers.

$ docker-compose up -d
Enter fullscreen mode Exit fullscreen mode

The Prisma server is now connected to the local Postgres instance and runs on port 4466. Opening http://localhost:4466 in a browser will open the Prisma GraphQL playground.

Now let's install the Prisma CLI and the Prisma client helper library.

$ npm install -g prisma 
$ npm install --save prisma-client-lib
Enter fullscreen mode Exit fullscreen mode

And initialise Prisma in our project root folder.

$ prisma init --endpoint http://localhost:4466
Enter fullscreen mode Exit fullscreen mode

Prisma initialisation will create the datamodel.prisma and prisma.yml files in the root of our project. The datamodel.prisma file contains the database schema and prisma.yml contains the prisma client configurations.

Add the following code to prisma.yml to generate typescript-client so we can query our database.

prisma.yml

endpoint: http://localhost:4466
datamodel: datamodel.prisma
generate:
  - generator: typescript-client
    output: ./generated/prisma-client/
Enter fullscreen mode Exit fullscreen mode

Then run prisma deploy to deploy your service. It will initialise the schema specified in datamodel.prisma and generate the prisma client.

$ prisma deploy
Enter fullscreen mode Exit fullscreen mode

Go to http://localhost:4466/_admin to open the prisma admin tool, a slightly more convenient way to view and edit your data compared to the graphql playground.

Prisma Module

This step is pretty much optional as you can use the generated prisma client as it is in other modules/services etc. but making a prisma module will make it easier to configure or change something in the future.

Let's use the NestJS CLI to create a prisma module and a service. The CLI will automatically create the files boilerplate's files and do the initial module metadata setup for us.

$ nest g module prisma 
$ nest g service prisma
Enter fullscreen mode Exit fullscreen mode

Then let's setup PrismaService.

src/prisma/prisma.service.ts

import { Injectable } from '@nestjs/common';
import { Prisma } from '../../generated/prisma-client';

@Injectable()
export class PrismaService {
  client: Prisma;

  constructor() {
    this.client = new Prisma();
  }
}
Enter fullscreen mode Exit fullscreen mode

And export it in src/prisma/prisma.module.ts.

import { Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';

@Module({
  providers: [PrismaService],
  exports: [PrismaService],
})
export class PrismaModule {}
Enter fullscreen mode Exit fullscreen mode

Great! We are done with the initial setup, let's now continue implementing authentication.

Shemas

Database schema

Let's store our boilerplate app schema in database/datamodel.prisma. We can also delete the old datamodel file in the root of the project with default schema.

$ rm datamodel.prisma
$ mkdir database
$ touch database/datamodel.prisma
Enter fullscreen mode Exit fullscreen mode

database/datamodel.prisma

type User {
    id: ID! @id
    email: String! @unique
    password: String!
    post: [Post!]!
    createdAt: DateTime! @createdAt
    updatedAt: DateTime! @updatedAt
}

type Post {
    id: ID! @id
    title: String!
    body: String
    author: User!
    createdAt: DateTime! @createdAt
    updatedAt: DateTime! @updatedAt
}
Enter fullscreen mode Exit fullscreen mode

Then let's modify prisma.yml and define path to our new schema.

prisma.yml

endpoint: http://localhost:4466
datamodel:
  - database/datamodel.prisma
generate:
  - generator: typescript-client
    output: ./generated/prisma-client/
Enter fullscreen mode Exit fullscreen mode

After deploying the schema, the prisma client will be automatically updated and you should see appropriate changes in prisma admin http://localhost:4466/_admin.

$ prisma deploy
Enter fullscreen mode Exit fullscreen mode

API schema

Let's put the following graphql API schema in src/schema/gql-api.graphql.

src/schema/gql-api.graphql

type User {
  id: ID!
  email: String!
  post: [Post!]!
  createdAt: String!
  updatedAt: String!
}

type Post {
  id: ID!
  title: String!
  body: String
  author: User!
}

input SignUpInput {
  email: String!
  password: String!
}

input LoginInput {
  email: String!
  password: String!
}

input PostInput {
  title: String!
  body: String
}

type AuthPayload {
  id: ID!
  email: String!
}

type Query {
  post(id: ID!): Post!
  posts: [Post!]!
}

type Mutation {
  signup(signUpInput: SignUpInput): AuthPayload!
  login(loginInput: LoginInput): AuthPayload!
  createPost(postInput: PostInput): Post!
}
Enter fullscreen mode Exit fullscreen mode

Now launch the app with npm start so it will generate typescript types from the schema above.

Modules

Auth Module

First, we need to install some additional packages to implement passport JWT in our NestJS app.

$ npm install --save @nestjs/passport passport @nestjs/jwt passport-jwt cookie-parser bcryptjs class-validator class-transformer
$ npm install @types/passport-jwt --save-dev
Enter fullscreen mode Exit fullscreen mode

Create AuthModule, AuthService, AuthResolver, JwtStrategy and GqlAuthGuard files.

$ nest g module auth 
$ nest g service auth
$ nest g resolver auth
$ touch src/auth/jwt.strategy.ts
$ touch src/auth/graphql-auth.guard.ts 
Enter fullscreen mode Exit fullscreen mode

src/auth/auth.service.ts

import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { User } from '../../generated/prisma-client';

@Injectable()
export class AuthService {
  constructor(private readonly prisma: PrismaService) {}

  async validate({ id }): Promise<User> {
    const user = await this.prisma.client.user({ id });
    if (!user) {
      throw Error('Authenticate validation error');
    }
    return user;
  }
}
Enter fullscreen mode Exit fullscreen mode

The validate method of the auth service will check if a user id from a JWT token is persisted in the database.

src/auth/jwt.strategy.ts

import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-jwt';
import { Request } from 'express';
import { AuthService } from './auth.service';

const cookieExtractor = (req: Request): string | null => {
  let token = null;
  if (req && req.cookies) {
    token = req.cookies.token;
  }
  return token;
};

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(private readonly authService: AuthService) {
    super({
      jwtFromRequest: cookieExtractor,
      secretOrKey: process.env.JWT_SECRET,
    });
  }

  validate(payload) {
    return this.authService.validate(payload);
  }
}
Enter fullscreen mode Exit fullscreen mode

Here we define where our token should be taken from and how to validate it. We will be passing the JWT secret via environment variable so you will be launching the app with JWT_SECRET=your_secret_here npm run start.

To be able to parse cookies we need to define global cookie-parser middleware.

src/main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as cookieParser from 'cookie-parser';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.use(cookieParser());
  await app.listen(3000);
}
bootstrap();
Enter fullscreen mode Exit fullscreen mode

Now let's create a validation class that we will use later and put some email/password validations there.

$ touch src/auth/sign-up-input.dto.ts
Enter fullscreen mode Exit fullscreen mode

src/auth/sign-up-input.dto.ts

import { IsEmail, MinLength } from 'class-validator';
import { SignUpInput } from '../graphql.schema.generated';

export class SignUpInputDto extends SignUpInput {
  @IsEmail()
  readonly email: string;

  @MinLength(6)
  readonly password: string;
}
Enter fullscreen mode Exit fullscreen mode

To make validation work, we need to globally define the validation pipe from @nestjs/common package.

src/app.module.ts

import { Module, ValidationPipe } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { GraphqlOptions } from './graphql.options';
import { PrismaModule } from './prisma/prisma.module';
import { AuthModule } from './auth/auth.module';
import { APP_PIPE } from '@nestjs/core';

@Module({
  imports: [
    GraphQLModule.forRootAsync({
      useClass: GraphqlOptions,
    }),
    PrismaModule,
    AuthModule,
  ],
  providers: [
    {
      provide: APP_PIPE,
      useClass: ValidationPipe,
    },
  ],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

To easily access request and user objects from the graphql context we can create decorators. More info about custom decorators can be found here.

src/shared/decorators/decorators.ts

import { createParamDecorator } from '@nestjs/common';
import { Response } from 'express';
import { User } from '../../../generated/prisma-client';

export const ResGql = createParamDecorator(
  (data, [root, args, ctx, info]): Response => ctx.res,
);

export const GqlUser = createParamDecorator(
  (data, [root, args, ctx, info]): User => ctx.req && ctx.req.user,
);
Enter fullscreen mode Exit fullscreen mode

src/auth/auth.resolver.ts

import * as bcryptjs from 'bcryptjs';
import { Response } from 'express';
import { Args, Mutation, Resolver } from '@nestjs/graphql';
import { LoginInput } from '../graphql.schema.generated';
import { ResGql } from '../shared/decorators/decorators';
import { JwtService } from '@nestjs/jwt';
import { PrismaService } from '../prisma/prisma.service';
import { SignUpInputDto } from './sign-up-input.dto';

@Resolver('Auth')
export class AuthResolver {
  constructor(
    private readonly jwt: JwtService,
    private readonly prisma: PrismaService,
  ) {}

  @Mutation()
  async login(
    @Args('loginInput') { email, password }: LoginInput,
    @ResGql() res: Response,
  ) {
    const user = await this.prisma.client.user({ email });
    if (!user) {
      throw Error('Email or password incorrect');
    }

    const valid = await bcryptjs.compare(password, user.password);
    if (!valid) {
      throw Error('Email or password incorrect');
    }

    const jwt = this.jwt.sign({ id: user.id });
    res.cookie('token', jwt, { httpOnly: true });

    return user;
  }

  @Mutation()
  async signup(
    @Args('signUpInput') signUpInputDto: SignUpInputDto,
    @ResGql() res: Response,
  ) {
    const emailExists = await this.prisma.client.$exists.user({
      email: signUpInputDto.email,
    });
    if (emailExists) {
      throw Error('Email is already in use');
    }
    const password = await bcryptjs.hash(signUpInputDto.password, 10);

    const user = await this.prisma.client.createUser({ ...signUpInputDto, password });

    const jwt = this.jwt.sign({ id: user.id });
    res.cookie('token', jwt, { httpOnly: true });

    return user;
  }
}
Enter fullscreen mode Exit fullscreen mode

And finally the authentication logic. We are using bcryptjs to hash
and secure out passwords and httpOnly cookie to prevent XSS attacks on
the client side.

If we want to make some endpoints accessible only for signed-up users we need
to create an authentication guard and then use it as a decorator above an endpoint
definition.

src/auth/graphql-auth.guard.ts

import { ExecutionContext, Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { GqlExecutionContext } from '@nestjs/graphql';

@Injectable()
export class GqlAuthGuard extends AuthGuard('jwt') {
  getRequest(context: ExecutionContext) {
    const ctx = GqlExecutionContext.create(context);
    return ctx.getContext().req;
  }
}
Enter fullscreen mode Exit fullscreen mode

Now let's wire up everything in AuthModule.

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthResolver } from './auth.resolver';
import { PrismaModule } from '../prisma/prisma.module';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';
import { JwtStrategy } from './jwt.strategy';

@Module({
  imports: [
    PrismaModule,
    PassportModule.register({
      defaultStrategy: 'jwt',
    }),
    JwtModule.register({
      secret: process.env.JWT_SECRET,
      signOptions: {
        expiresIn: 3600, // 1 hour
      },
    }),
  ],
  providers: [AuthService, AuthResolver, JwtStrategy],
})
export class AuthModule {}
Enter fullscreen mode Exit fullscreen mode

Cool, authentication is ready! Start the server and try to create a user, log-in and check cookies in a browser.
If you see token cookie everything works as expected.

Post module

Let's add some basic logic to our app. Authorized users will be able
to create posts that will be readable to everyone.

$ nest g module post
$ nest g resolver post
$ touch src/post/post-input.dto.ts
Enter fullscreen mode Exit fullscreen mode

First let's define resolvers for all Post fields and add a simple validation for createPost mutation.

src/post/post-input.dto.ts

import { IsString, MaxLength, MinLength } from 'class-validator';
import { PostInput } from '../graphql.schema.generated';

export class PostInputDto extends PostInput {
  @IsString()
  @MinLength(10)
  @MaxLength(60)
  readonly title: string;
}
Enter fullscreen mode Exit fullscreen mode

src/post/post.resolver.ts

import {
  Args,
  Mutation,
  Parent,
  Query,
  ResolveProperty,
  Resolver,
} from '@nestjs/graphql';
import { PrismaService } from '../prisma/prisma.service';
import { Post } from '../graphql.schema.generated';
import { GqlUser } from '../shared/decorators/decorators';
import { User } from '../../generated/prisma-client';
import { UseGuards } from '@nestjs/common';
import { GqlAuthGuard } from '../auth/graphql-auth.guard';
import { PostInputDto } from './post-input.dto';

@Resolver('Post')
export class PostResolver {
  constructor(private readonly prisma: PrismaService) {}

  @Query()
  async post(@Args('id') id: string) {
    return this.prisma.client.post({ id });
  }

  @Query()
  async posts() {
    return this.prisma.client.posts();
  }

  @ResolveProperty()
  async author(@Parent() { id }: Post) {
    return this.prisma.client.post({ id }).author();
  }

  @Mutation()
  @UseGuards(GqlAuthGuard)
  async createPost(
    @Args('postInput') { title, body }: PostInputDto,
    @GqlUser() user: User,
  ) {
    return this.prisma.client.createPost({
      title,
      body,
      author: { connect: { id: user.id } },
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

And don't forget to define everything in the module.

src/post/post.module.ts

import { Module } from '@nestjs/common';
import { PostResolver } from './post.resolver';
import { PrismaModule } from '../prisma/prisma.module';

@Module({
  providers: [PostResolver],
  imports: [PrismaModule],
})
export class PostModule {}
Enter fullscreen mode Exit fullscreen mode

User Module

Although we don't have any user mutations, we still need to define user resolvers so graphql can resolve our queries correctly.

$ nest g module user 
$ nest g resolver user
Enter fullscreen mode Exit fullscreen mode

src/user/user.resolver.ts

import { Parent, ResolveProperty, Resolver } from '@nestjs/graphql';
import { PrismaService } from '../prisma/prisma.service';
import { User } from '../graphql.schema.generated';

@Resolver('User')
export class UserResolver {
  constructor(private readonly prisma: PrismaService) {}

  @ResolveProperty()
  async post(@Parent() { id }: User) {
    return this.prisma.client.user({ id }).post();
  }
}
Enter fullscreen mode Exit fullscreen mode

And of course UserModule.

src/user/user.module.ts

import { Module } from '@nestjs/common';
import { UserResolver } from './user.resolver';
import { PrismaModule } from '../prisma/prisma.module';

@Module({
  providers: [UserResolver],
  imports: [PrismaModule],
})
export class UserModule {}
Enter fullscreen mode Exit fullscreen mode

Sample Queries

To test your application you can run these simple queries.

Signing-up

mutation {
  signup(signUpInput: { email: "user@email.com", password: "pasword" }) {
    id
    email
  }
}
Enter fullscreen mode Exit fullscreen mode

Logging-in

mutation {
  login(loginInput: { email: "user@email.com", password: "pasword" }) {
    id
    email
  }
}
Enter fullscreen mode Exit fullscreen mode

Creating a post

mutation {
  createPost(postInput: { title: "Post Title", body: "Post Body" }) {
    id
    title
    author {
      id
      email
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Retrieving all posts

query {
  posts {
    title
    author {
      email
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

We are finally done with our app boilerplate! Check nestjs documentation to add more useful features to your application. When deploying to production environment don't forget to secure your Prisma layer and database.

You can find the final code here.

Discussion (19)

Collapse
johnbiundo profile image
John Biundo

Nikita, thanks for the great tutorial. I am running this 1.5 years after you wrote it 😄 and with Nest v7. So there were a couple of issues I had to fix:

Installing graphql@latest (15.0) caused some sort of problem for me. I haven't quite sorted it out, so I fell back to ^14.6.0 to avoid that problem.

With Nest 7, there's a breaking change to createParamDecorator. Here's the change I made to src/shared/decorators/decorators.ts to make it work:

import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';

import { Response } from 'express';
import { User } from '../../../generated/prisma-client';

export const ResGql = createParamDecorator(
  (data: unknown, context: ExecutionContext): Response =>
    GqlExecutionContext.create(context).getContext().res,
);

export const GqlUser = createParamDecorator(
  (data: unknown, context: ExecutionContext): User => {
    const ctx = GqlExecutionContext.create(context).getContext();
    return ctx.req && ctx.req.user;
  },
);
Collapse
nikitakot profile image
Nikita Kot Author • Edited

Hi John! Thanks for sharing this! I'll update the article and the repo in near future. By the way, there is prisma 2 beta release out, haven't checked it yet, but I'm pretty sure some bigger changes have to be done for the upgrade too.

Collapse
johnbiundo profile image
John Biundo

Sounds good. Figured I'd post the code that worked for me as a stop gap in case others run into it.

Collapse
valerebron profile image
Valère BRON

Hi Nikita Gr8 Article ... but Express can't write token'cookie !

this line of code seems ok : "res.cookie('token', jwt, { httpOnly: true });" in auth.resolver.ts,
and the token is correctly generated but no cookie is created in client side...

Collapse
nikitakot profile image
Nikita Kot Author

P.S. If you are not using graphql playground and calling the server from a front-end application served from another server (different domain/port/etc.) you need to enable cors on the nestjs server (not described in the article). To do it simply add these lines to your main.ts file to the bootstrap function.

app.enableCors({
    credentials: true,
    origin: true,
  });
Collapse
valerebron profile image
Valère BRON

Cors was the problem yes, thanks again for these speed responses !

Collapse
nikitakot profile image
Nikita Kot Author

Please check your graphql playground settings in the browser. You should have "request.credentials": "same-origin" set there to allow CORS.

Collapse
valerebron profile image
Valère BRON • Edited

Indeed, that works

Collapse
abumalick profile image
abumalick

Thank you very much for your tutorial, it was very helpful.

In Nest v7 you don't really need to create custom Decorators, you can use the @Context decorator from graphql package:

import {Args, Context, Mutation, Resolver} from '@nestjs/graphql'

// and in your mutation:
@Mutation()
  async login(
    @Args('loginInput') { email, password }: LoginInput,
    @Context('res') res: Response,
  ) {
Enter fullscreen mode Exit fullscreen mode

Thank you again

Collapse
valeronlol profile image
Valerii Kuzivanov • Edited

Great article Nikita, but authorization doesnt work properly due to problems with cookiest. I can see Set-Cookie header, but it does not add cookie to your browser storage.
github.com/apollographql/apollo-cl...

Collapse
nikitakot profile image
Nikita Kot Author

Thanks! About authorisation - take a look at src/main.ts. I'm using external cookieParser library to parse cookies. You sure you also installed it?

Collapse
edertxodw profile image
Edertxo

That help me a lot, thanks! :D

Collapse
elie222 profile image
Elie

Is this the best approach for log out?

  @Mutation(() => Boolean)
  async logOut(@ResGql() res: Response) {
    res.cookie('token', '', { httpOnly: true })
    return true
  }
Collapse
nikitakot profile image
Nikita Kot Author

Hi Elie,

This looks like as the easiest solution. Or you can implement something like token blacklist. More here.

Collapse
arrrrny profile image
Arrrrny

Nice post. It would be great if you have the same article using Apollo since it is the default graphql server for the nest.

Collapse
paulcuixan profile image
Paul Cuichan • Edited

I have this problem. how can I solve that
dev-to-uploads.s3.amazonaws.com/i/...

Collapse
nikitakot profile image
Nikita Kot Author

looks like you didn't generate typescript types from the gql schema, re-check the GraphQL part of the article

Collapse
paulcuixan profile image
Paul Cuichan

thanks

Collapse
sgarza profile image
Sergio de la Garza

Seems that the Prisma's client generation API changed and it no longer generates the GraphQL schemas. I have the same issue. Any ideas?