Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apollo Server 2.0 #32

Closed
prabak opened this issue Jun 18, 2018 · 27 comments
Closed

Apollo Server 2.0 #32

prabak opened this issue Jun 18, 2018 · 27 comments
Labels

Comments

@prabak
Copy link

prabak commented Jun 18, 2018

Does this package support Apollo Server 2.0 or the older version? I installed their release candidate for express (apollo-server-express@rc). graphqlExpress is no longer available. import { graphqlExpress } from 'apollo-server-express'; How would I go about using nestjs/graphql with Apollo Server 2.0?

thank you

@kamilmysliwiec
Copy link
Member

The apollo@2.0 is not stable yet. We'll support it once it hits the final release.

@nikis05
Copy link

nikis05 commented Jul 20, 2018

v2 is now stable, any advice on how to use it?

@viiiprock
Copy link

Yeah, I'll move to nest js until it support Apollo 2

@diego-d5000
Copy link

I'm using this nestjs module with Apollo 2 in the following way:

app.module.js

import { Module } from '@nestjs/common';
import { GraphQLFactory, GraphQLModule } from '@nestjs/graphql';
import { ApolloServer } from 'apollo-server-express';
import { LostPetsResolver } from 'lost-pets/lost-pets.resolvers';
import { LostPetsService } from './lost-pets/lost-pets.service';

@Module({
  imports: [GraphQLModule],
  providers: [LostPetsService, LostPetsResolver], // Provide services and resolvers
})
export class AppModule {
  // Inject graphQLFactory as in Nestjs Docs
  constructor(private readonly graphQLFactory: GraphQLFactory) { }

  configureGraphQL(app: any) {
    // Same as nestjs docs - graphql guide
    const typeDefs = this.graphQLFactory.mergeTypesByPaths('./**/*.graphql');
    const schema = this.graphQLFactory.createSchema({ typeDefs });

    // this changed. Apollo lib internally apply app.use(...)
    // and other middlewares to work
    // but it needs app object
    const server = new ApolloServer({ schema });
    server.applyMiddleware({ app });
  }
}

And then I give the app object to this method:

main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // With Nestjs context get the app module to call our configure method
  const appModule = app.get(AppModule);
  appModule.configureGraphQL(app);

  await app.listen(3000);
}
bootstrap();

Thanks.

@viiiprock
Copy link

viiiprock commented Jul 29, 2018

@diego-d5000 I haven't start with Nest yet but watching on it. So, based on your setup, how to expose graphql endpoint? Is it like:

  configure(consumer: MiddlewareConsumer) {
    consumer.apply(this.configureGraphQL).forRoutes('/graphql');
  }

@diego-d5000
Copy link

diego-d5000 commented Jul 29, 2018

@viiiprock You can't apply this configureGraphQL method in that way because isn't a middleware, it doesn't receive req,res,next params. I'm navigating through Apollo 2 code, but I don't find any middleware like function/method yet to do that. Default Apollo 2 route is "/graphql", but you could change it in applyMiddleware method:

const server = new ApolloServer({ schema });
const path = '/api/graphql';
server.applyMiddleware({ app, path });

@viiiprock
Copy link

great, I should make a try. Thanks @diego-d5000

@kyle-mccarthy
Copy link

@diego-d5000 do you have an issue with additional headers being sent when loading the graphql playground? I am seeing Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client in my app logs when visiting the URL the playground lives at.

@viiiprock
Copy link

viiiprock commented Aug 6, 2018

@kyle-mccarthy I do, seems it came from playground, but you could try

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // With Nestjs context get the app module to call our configure method
  const appModule = app.get(AppModule);
  appModule.configureGraphQL(app);
  app.use('/graphql', () => {}); // Add route here
  await app.listen(3000);
}
bootstrap();

And it will do the trick.
I don't use Playground anyway, Insomnia is better ;)

@diego-d5000
Copy link

diego-d5000 commented Aug 7, 2018

Nice. Thanks @viiiprock, It seems that it's a graphql-playground issue:
graphql/graphql-playground#557

@zuohuadong
Copy link

+1
v2 is now stable, any advice on how to use it?

@agborkowski
Copy link

agborkowski commented Aug 9, 2018

@diego-d5000 wrote up how to do it, works like harm or just pull request to nest graphql module new version :)

@arjitkhullar
Copy link

How about graphql-subscriptions.

@cschroeter
Copy link

cschroeter commented Aug 10, 2018

@arjitkhullar Here is an example including subscription handling:

import { Module } from '@nestjs/common';
import { GraphQLFactory, GraphQLModule } from '@nestjs/graphql';
import { ApolloServer } from 'apollo-server-express';
import { LostPetsResolver } from 'lost-pets/lost-pets.resolvers';
import { LostPetsService } from './lost-pets/lost-pets.service';

@Module({
  imports: [GraphQLModule],
  providers: [LostPetsService, LostPetsResolver], // Provide services and resolvers
})
export class AppModule {
  // Inject graphQLFactory as in Nestjs Docs
  constructor(private readonly graphQLFactory: GraphQLFactory) { }

  configureGraphQL(app: any, httpServer: any) {
    // Same as nestjs docs - graphql guide
    const typeDefs = this.graphQLFactory.mergeTypesByPaths('./**/*.graphql');
    const schema = this.graphQLFactory.createSchema({ typeDefs });

    // this changed. Apollo lib internally apply app.use(...)
    // and other middlewares to work
    // but it needs app object
    const server = new ApolloServer({ schema });
    server.applyMiddleware({ app });
    server.installSubscriptionHandlers(httpServer);
  }
}
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // With Nestjs context get the app module to call our configure method
  const appModule = app.get(AppModule);
  const httpServer = app.getHttpServer();
  appModule.configureGraphQL(app, httpServer);

  await app.listen(3000);
}
bootstrap();

@cschroeter
Copy link

Unfortunately if you use nestjs/passport it can no extract headers from the execution context. Ending up an internal error
TypeError: Cannot read property 'headers' of undefined", " at JwtStrategy._jwtFromRequest (/Users/cschroeter/Workspace/Edomo/edomo-middleware/node_modules/passport-jwt/lib/extract_jwt.js:58:21)

@zuohuadong
Copy link

@kamilmysliwiec v2 is now stable.

@krivochenko
Copy link

@cschroeter I encountered with the same issue when I tried to use @nestjs/passport. Just for test I implemented simple guard:

import { CanActivate, Injectable } from '@nestjs/common';

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(context) {
    const httpContext = context.switchToHttp();
    console.log(httpContext.getRequest());
    return true;
  }
}

and console.log output is undefined. By the same reason passport can't get headers from request. Do you have any solution? Thanks for help.

@kamilmysliwiec
Copy link
Member

Apollo v2 integration is now available. Also, the docs + example have been updated as well https://docs.nestjs.com/graphql/quick-start

@sofyan-ahmad
Copy link

@cschroeter I encountered with the same issue when I tried to use @nestjs/passport. Just for test I implemented simple guard:

import { CanActivate, Injectable } from '@nestjs/common';

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(context) {
    const httpContext = context.switchToHttp();
    console.log(httpContext.getRequest());
    return true;
  }
}

and console.log output is undefined. By the same reason passport can't get headers from request. Do you have any solution? Thanks for help.

I have the same issue, any solutions for this?

@kamilmysliwiec
Copy link
Member

@sofyanhadia just look at the docs https://docs.nestjs.com/graphql/tooling "Execution Context"

@w0wka91
Copy link

w0wka91 commented Sep 12, 2018

@sofyanhadia #48

@cschroeter
Copy link

cschroeter commented Sep 12, 2018

Using the AuthGuard within the GraphQL context is not possible. The context is not aware of any request object. So the JWT module tries to extract the Authorization header from the request object which is undefined. I'm not sure how to switch to original request object provided by the epxress instance, as already mentioned in #48. So right now I don't see any possibility to guard your GraphQL endpoints, which is kinda bad, i guess

@viiiprock
Copy link

@cschroeter
I don't get it, why need instance? Didn't the Apollo provide original request object by the context ? With Nest, it wrapped around GraphQLModule.forRoot({...context: async({req}) => ..... })
And the AuthGuard is really simple to implement.

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    const ctx = GqlExecutionContext.create(context);
    // you can get context by using `ctx.getContext()`
    return ctx && true;
  }
}

before update, I did something quite tricky, but it worked like a charm

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {

    // => get the context object with `context.getArgs()[2]`;

  }

@cschroeter
Copy link

@viiiprock Sure you can access your context within the AuthGuard - no problem. But you can not access your request headers for example. You would need to extract them in the ApplicationModule from the req and then implement your authentication by urself instead of reusing the @nestjs/passport and @nestjs/jwtmodule.

@viiiprock
Copy link

got it , I don't use those stuff, I implemented jwt my self with jsowebtoken

@mnlttt
Copy link

mnlttt commented Sep 13, 2018

@cschroeter there's how I've upgraded:

import * as jwt from 'jsonwebtoken';
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';

@Injectable()
export class AuthGuard implements CanActivate {
    constructor(private readonly authService: AuthService) {}

    canActivate(
        context: ExecutionContext,
    ): boolean | Promise<boolean> | Observable<boolean> {
        const ctx = GqlExecutionContext.create(context);
        const request = ctx.getContext().request;

        const token = request.headers.authorization
            ? (request.headers.authorization as string).split(' ')
            : null;

        if (process.env.NODE_ENV === 'development') {
            return true;
        }

        if (token && token[1]) {
            const decoded: any = jwt.verify(token[1], process.env.SECRET);

            return !!this.authService.findById(decoded.id);
        }
    }
}
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
@Module({
    imports: [
        GraphQLModule.forRoot({
            typePaths: ['./**/*.gql'],
            debug: true,
            playground: true,
            tracing: true,
            path: '/api/graphql',
            context: ({ req, res }) => ({
                request: req,
            }),
            rootValue: ({ req }) => ({ req }),
        }),
    ],
})
export class GQLModule {}

@lock
Copy link

lock bot commented Apr 25, 2020

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Apr 25, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests