apollo-server-integrations / apollo-server-integration-aws-lambda

An integration to use AWS Lambda as a hosting service with Apollo Server
MIT License
46 stars 9 forks source link

Cannot read property 'method' of undefined #80

Closed przemeklach closed 1 year ago

przemeklach commented 1 year ago

I have deployed a lambda using the cdk as follows:

const helloFunction = new NodejsFunction(this, 'lambda', {
            entry: path.join(__dirname, "lambda.ts"),
            handler: "handler"
        });
        new LambdaRestApi(this, 'apigw', {
            handler: helloFunction,
        });

My lambda is based on the example in the readme.

import {ApolloServer} from '@apollo/server';
import {handlers, startServerAndCreateLambdaHandler} from '@as-integrations/aws-lambda';

const typeDefs = #graphql
type Hello {
    value: String
}

type Query {
    hello(name: String): Hello
}

schema {
    query: Query
}

const resolvers = {
    Query: {
        hello: () => 'world',
    },
}

const server = new ApolloServer({
    typeDefs,
    resolvers,
    introspection: true,
})
console.log('###? running lambda')

export const handler = startServerAndCreateLambdaHandler(
    server,
    handlers.createAPIGatewayProxyEventV2RequestHandler(), {
        middleware: [
            async (event) => {
                console.log('###? received event=' + JSON.stringify(event))
            }
        ]
    });

When I try to hit it using postman I get the following error:

Cannot read property 'method' of undefined

The request does appear to get to the lambda because the logging I have in there shows up. I can see the 'running lambda' output as well as the 'event' that gets logged as part of the middleware.

Something is going wrong inside startServerAndCreateLambdaHandler() and the above error is returned.

rodrigomf24 commented 1 year ago

I am facing the same error after upgrading to the latest version

BlenderDude commented 1 year ago

Helped you out with a quick edit to add backticks for the code blocks. The main issue is that the REST Api utilizes the V1 style event, and you are calling the library with the V2 style. Update your call to:

export const handler = startServerAndCreateLambdaHandler(
    server,
    handlers.createAPIGatewayProxyEventRequestHandler(),
    {
      middleware: [
        async (event) => {
          console.log('###? received event=' + JSON.stringify(event))
        }
      ]
  }
);

Or (if you're just exploring), I recommend using the new function URL's to get up and going then transfer to the HTTP API Gateway (Note, this is different than the REST one you have setup) when ready.

NOTE with Function URLs and the HTTP Api, you want to keep the original createAPIGatewayProxyEventV2RequestHandler() you currently have, as those two services use the new event type.

This CDK code should help set that up:


const helloFunction = new NodejsFunction(this, 'lambda', {
    entry: path.join(__dirname, "lambda.ts"),
    handler: "handler"
});

const fnUrl = helloFunction.addFunctionUrl();

new CfnOutput(this, 'TheUrl', {
  value: fnUrl.url,
});

This will create the function and output the URL you can call it at after cdk deploy completes.

przemeklach commented 1 year ago

Excellent, createAPIGatewayProxyEventRequestHandler worked.

This might be getting a bit out of scope here but what about subscriptions? LambdaRestApi() will handle queries and mutations but subscriptions would require a WebSocket API, no? Would subscription clients have to connect to two separate apis? They would first hit the WebSocket API to create the ws connection and then hit the LambdaRestApi to register the subscription along with the socket they are on?

BlenderDude commented 1 year ago

If you want lambda to handle queries and mutations, and something else to handle subscriptions (lambda will not support websockets directly), you can set this up in your client code.

You can have https://abc.xyz/graphql set for queries and mutations, and wss://websockets.abc.xyz set for subscriptions.

Implementation of such a setup would be out-of-scope for this library though as Lambda does not support incoming websockets.

BlenderDude commented 1 year ago

If you're looking for pointers though, I recommend looking into AWS Fargate. That setup would look liked Application Load Balancer -> Target Group -> Fargate. It is a 24/7 cost, so at that point you may want to consider running queries, mutations, and subscriptions all on one Fargate instance.

If you want further architecture guidance I reccommend stopping by the Apollo GraphQL Discord! https://discord.gg/graphos

jerang commented 1 year ago

Helped you out with a quick edit to add backticks for the code blocks. The main issue is that the REST Api utilizes the V1 style event, and you are calling the library with the V2 style. Update your call to:

export const handler = startServerAndCreateLambdaHandler(
    server,
    handlers.createAPIGatewayProxyEventRequestHandler(),
    {
      middleware: [
        async (event) => {
          console.log('###? received event=' + JSON.stringify(event))
        }
      ]
  }
);

@BlenderDude thanks for pointing this out; this would be helpful to have in the README.