apollo-server-lambda example not working

Created on 20 Dec 2018  路  2Comments  路  Source: apollographql/apollo-server

Intended Outcome: To deploy an apollo-server to AWS Lambda based off the example provided in the Apollo docs, here is my code below:

//graphql.js

const {ApolloServer, gql} = require('apollo-server-lambda');


 const typeDefs = gql`
    type Query {
      hello: String
    }
 `;

 const resolvers = {
  Query: {
    hello: () => 'Zansi is Alive!!'
  },
 };

 const server = new ApolloServer({
   typeDefs,
   resolvers,
   context: ({event,context}) => ({
      headers: event.headers,
      functionName: context.functionName,
      event,
      context,
   }),
   });

 exports.graphqlHandler = server.createHandler({
  cors: {
    origin: '*',
    methods: 'POST',
    allowHeaders: [
      'Content-Type',
      'Origin',
      'Accept'
    ]
  },
 });

Operating System: Windows 10
Yarn Version: 1.1.0
Dependencies: apollo-server-lambda: "^2.3.1"

Actual outcome: when I invoke the function locally or deploy it I get the following response:

{
    "body": "Apollo Server supports only GET/POST requests.",
    "statusCode": 405,
    "headers": {
        "Allow": "GET, POST",
        "Access-Control-Allow-Methods": "POST",
        "Access-Control-Allow-Headers": "Content-Type,Origin,Accept",        
        "Access-Control-Allow-Origin": "*"
    }
}

How to reproduce: Run the following in your terminal:

$ serverless install --url https://github.com/AnomalyInnovations/serverless-nodejs-starter --name my-project

then run npm install and after that install apollo-server-lambda. Create a graphql.js file and copy the code above into it.

Then run:
serverless invoke local --function graphql

Any help would be greatly appreciated.

Most helpful comment

Apologies, I was invoking the function locally like a REST API.

For anyone who encounters a similar problem, make sure to run : $ sls offline and playground should open at localhost://3000.

Furthermore, when you deploy you might run into an error message saying "missing authentication token", to solve this make sure your serverless.yml for the functions part looks something like this:

functions:
  graphql:
    handler: graphql.graphqlHandler
    environment:
      SLS_DEBUG: true
    events:
      - http:
          path: graphql
          method: post 
          cors: true
          integration: lambda-proxy


      - http:
          path: graphql
          method: get 
          cors: true
          integration: lambda-proxy

Reason being is that API Gateway does not have access to your URL's stage and resources it is using.

All 2 comments

Apologies, I was invoking the function locally like a REST API.

For anyone who encounters a similar problem, make sure to run : $ sls offline and playground should open at localhost://3000.

Furthermore, when you deploy you might run into an error message saying "missing authentication token", to solve this make sure your serverless.yml for the functions part looks something like this:

functions:
  graphql:
    handler: graphql.graphqlHandler
    environment:
      SLS_DEBUG: true
    events:
      - http:
          path: graphql
          method: post 
          cors: true
          integration: lambda-proxy


      - http:
          path: graphql
          method: get 
          cors: true
          integration: lambda-proxy

Reason being is that API Gateway does not have access to your URL's stage and resources it is using.

What I found confusing is that for me this "apollo-server-lambda" and the ".createHandler(...)" thing looked like it could really do lambda.invoke() calls with it but instead it assumes HTTP requests.

In order to use lambda.invoke, like you would for example if you try to use apollo-link-lambda, you have to do something like this:

const handler = server.createHandler();
export const lambdaHandler = (event, context, callback) => {
    event.httpMethod = event.httpMethod || "POST";
    event.headers = {
        "content-type": "application/json",
        ...(event.headers ||聽{}),
    };

    if(!event.body && event.query){
        event.body = JSON.stringify({
            query: event.query,
            variables: event.variables
        });

    }

    return handler(event, context, (er, res) => {

        if(res){
            callback(er, res.body);
        }
        else{
            callback(er, res);
        }

    });
}

This way you make a HTTP event out of the raw lambda-invoke and return the body of the HTTP body as Payload back to the calling lambda.invoke.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

disyam picture disyam  路  3Comments

jpcbarros picture jpcbarros  路  3Comments

hiucimon picture hiucimon  路  3Comments

manuelfink picture manuelfink  路  3Comments

attdona picture attdona  路  3Comments