Paiman Rasoli
Paiman Rasoli

Reputation: 1214

Change graphql context to http context

I have a global guard which is use for private routes and implemented with passport-jwt this guard works correctly in REST API but I have some graphql routes and when I send a request it gives the error which logIn is undefined, I found the problem is because of difference of context in graphql is there any way to change graphql excution to http execution context. I have tried many ways but still, there is an error in passport-jwt.

// access token global guard

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

@Injectable()
export class AtGuard extends AuthGuard('jwt') {
   constructor(private reflector: Reflector) {
    super();
   }

canActivate(context: ExecutionContext) {
  const isPublic = this.reflector.getAllAndOverride('isPublic', [
    context.getHandler(),
    context.getClass(),
 ]);
 // if public decorator use skip the validation
 if (isPublic) return true;
  // check context
  if (context.getType<GqlContextType>() === 'graphql') {
    const ctx = GqlExecutionContext.create(context);
    return super.canActivate(ctx);
 }
  // correctly work for REST API
  return super.canActivate(context);
   }
 }

The errors which I from above code:

enter image description here

another way instead of passing ctx in function I did like this:

 if (context.getType<GqlContextType>() === 'graphql') {
  const ctx = GqlExecutionContext.create(context);
  return super.canActivate(ctx.getContext());
}

but get error which says context.switchToHttp is not a function.

enter image description here

codes in app.module.file

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthModule } from './auth/auth.module';
import { GraphQLModule } from '@nestjs/graphql';
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { join } from 'path';
import { TaskModule } from './task/task.module';
import { APP_GUARD } from '@nestjs/core';
import { AtGuard } from './common/guards/at.guard';

@Module({
 imports: [
   ConfigModule.forRoot({
   isGlobal: true,
}),
TypeOrmModule.forRoot({
  type: 'mysql',
  host: 'localhost',
  port: 3306,
  ssl: false,
  username: 'root',
  password: '',
  database: 'coursera',
  synchronize: true,
  entities: ['dist/**/*.entity{.ts,.js}'],
}),
AuthModule, // REST API BASE
TaskModule, // GraphQl base
GraphQLModule.forRoot<ApolloDriverConfig>({
  driver: ApolloDriver,
  debug: false,
  playground: true,
  autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
}),
 ],
 providers: [
   {
     provide: APP_GUARD,
     useClass: AtGuard,
   },
  ],
 })
 export class AppModule {}

I expected to get an unauthorized error but I believe there is something wrong with this file. I would appreciate any help. thanks in advance.

Upvotes: 0

Views: 1265

Answers (1)

Paiman Rasoli
Paiman Rasoli

Reputation: 1214

Wow, I solved it. now I use the same guard for both API routes and graphql resolvers, the changes which I did. extract the request and response // app.module

    GraphQLModule.forRoot<ApolloDriverConfig>({
    driver: ApolloDriver,
    debug: false,
    playground: true,
    autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
    context: ({ req, res }) => ({
       req,
       res,
     }),
   }),

// in guard create my own object and send as params.

    // check context
if (context.getType<GqlContextType>() === 'graphql') {
  const ctx = GqlExecutionContext.create(context);
  const myargs = ctx.getArgByIndex(2);
  const customStructure = {
    ...myargs?.req,
    ...myargs?.res,
    switchToHttp() {
      const getRequest = () => {
        return myargs?.req;
      };
      const getResponse = () => {
        return myargs?.res;
      };

      return { getRequest, getResponse };
    },
  };

  return super.canActivate(customStructure);
}

Now I send a graphql request without sending JWT. enter image description here

Now I send a graphql request with setting JWT in headers. enter image description here

Upvotes: 0

Related Questions