enisdenjo / graphql-yoga-nestjs

Nest GraphQL GraphQL Yoga driver

Home Page:https://the-guild.dev/graphql/yoga-server/docs/integrations/integration-with-nestjs

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Use sofa plugin

lukadriel7 opened this issue · comments

Hello, I am trying to use the sofa plugin with this library.
The swager docs works but when trying post requests (mutations) I receive an error indicating that the variables were not provided. I use a code first approach. I call the login migration.
My config is as follow :

app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthModule } from './auth/auth.module';
import { UsersModule } from './users/users.module';
import { PrismaModule } from './prisma/prisma.module';
import { GraphQLModule } from '@nestjs/graphql';
import { YogaDriverConfig, YogaDriver } from '@graphql-yoga/nestjs';
import { useSofaWithSwaggerUI } from '@graphql-yoga/plugin-sofa';
import { AcceptLanguageResolver, I18nModule, QueryResolver } from 'nestjs-i18n';
import { join } from 'path';
import { cwd } from 'process';

@Module({
    imports: [
        I18nModule.forRoot({
            fallbackLanguage: 'en',
            fallbacks: {
                'en-*': 'en',
                'fr-*': 'fr',
            },
            loaderOptions: {
                path: join(cwd(), 'src/i18n'),
            },
            typesOutputPath: join(cwd(), 'src/generated/i18n.generated.ts'),
            resolvers: [QueryResolver, AcceptLanguageResolver],
        }),
        GraphQLModule.forRoot<YogaDriverConfig>({
            driver: YogaDriver,
            autoSchemaFile: join(cwd(), 'src/schema.gql'),
            sortSchema: true,
            installSubscriptionHandlers: true,

            plugins: [
                useSofaWithSwaggerUI({
                    basePath: '/graphql/rest',
                    swaggerUIEndpoint: '/graphql/swagger',
                    servers: [
                        {
                            url: '/', // Specify Server's URL.
                            description: 'Development server',
                        },
                    ],
                    info: {
                        title: 'Example API',
                        version: '1.0.0',
                    },
                }),
            ],
        }),
        AuthModule,
        UsersModule,
        PrismaModule,
    ],
    controllers: [AppController],
    providers: [AppService],
})
export class AppModule {}

auth.resolver.ts

import { UseGuards } from '@nestjs/common';
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { PasswordlessUser } from 'src/users/models/user.model';
import { AuthService } from './auth.service';
import { CurrentUser } from './decorators/current-user.decorator';
import { LoginArgs } from './dtos/login.args';
import { RegisterArgs } from './dtos/register.args';
import { GqlLocalAuthGuard } from './guards/gql-local-auth.guard';

@Resolver()
export class AuthResolver {
    constructor(private readonly authService: AuthService) {}
    @UseGuards(GqlLocalAuthGuard)
    @Mutation(() => String)
    async login(
        @Args() loginArgs: LoginArgs,
        @CurrentUser() user: PasswordlessUser,
    ) {
        return this.authService.login(user);
    }

    @Mutation(() => String)
    async register(@Args() registerArgs: RegisterArgs) {
        const user = await this.authService.register(registerArgs);
        return this.authService.login(user);
    }

    @Query(() => Boolean)
    async loggedIn(@CurrentUser() user?: PasswordlessUser) {
        return user ? true : false;
    }
}

login.args.ts

import { ArgsType, Field } from '@nestjs/graphql';

@ArgsType()
export class LoginArgs {
    @Field(() => String)
    email: string;

    @Field(() => String)
    password: string;
}

auth.service.ts

import { Injectable } from '@nestjs/common';
import { PrismaService } from 'src/prisma/prisma.service';
import { JwtService } from '@nestjs/jwt';
import { User } from '@prisma/client';
import { RegisterArgs } from './dtos/register.args';
import { verify, hash } from 'argon2';
import { randomBytes } from 'crypto';
import { PasswordlessUser } from 'src/users/models/user.model';

@Injectable()
export class AuthService {
    constructor(
        private readonly prismaService: PrismaService,
        private readonly jwtService: JwtService,
    ) {}

    async validateUser(email: string, pass: string) {
        const user = await this.prismaService.user.findUnique({
            where: {
                email,
            },
        });
        if (user && verify(user.password, pass + user.salt)) {
            const { password, ...userResult } = user;
            return userResult;
        }
        return null;
    }

    async login(user: PasswordlessUser) {
        const payload = { sub: user.id };
        return this.jwtService.sign(payload);
    }

    async register(registerArgs: RegisterArgs) {
        const salt = randomBytes(16).toString('base64');
        const password = await hash(registerArgs.password + salt);
        const user = await this.prismaService.user.create({
            data: {
                ...registerArgs,
                password,
                salt,
            },
            select: {
                id: true,
                email: true,
                firstName: true,
                lastName: true,
            },
        });
        return user;
    }
}

Hey there, thanks for reporting this and sorry for the delay.

We've been working on releasing the v1 of this Nest+Yoga driver and it just shipped 🚢 !

This codebase has been moved to the official GraphQL Yoga repository, if you still need assistance, or are experiencing issues, after migrating to v1 - I kindly ask you to open an issue over there.