Hello friends.
I try to realize a graphql subscription in lambda with createHandler function but it doesn’t work. I use serverless to deploy and serverless-offline to develop. And I use neo4j/graphql library to autogenerate the graphql resolvers.
The handler fonction is created by this code :
import { createServer } from "http";
import express from "express";
import { ApolloServer, gql } from "apollo-server-lambda";
import { WebSocketServer } from "ws";
import { useServer } from "graphql-ws/lib/use/ws";
import DatabaseManager from "../../services/database/DatabaseManager";
import { Neo4jGraphQL, Neo4jGraphQLSubscriptionsSingleInstancePlugin } from "@neo4j/graphql";
import { ApolloServerPluginDrainHttpServer } from "apollo-server-core";
const typeDefs = gql`
type Movie {
title: String!
description: String!
}
`;
const driver = DatabaseManager.driver;
const neoSchema = new Neo4jGraphQL({
typeDefs,
driver,
plugins: {
subscriptions: new Neo4jGraphQLSubscriptionsSingleInstancePlugin(),
},
});
const app = express();
const httpServer = createServer(app);
const wsServer = new WebSocketServer({
server: httpServer,
path: "/graphql",
});
const initServer = () => {
return neoSchema.getSchema().then(async (schema) => {
const serverCleanup = useServer({ schema }, wsServer);
const server = new ApolloServer({
schema,
context: ({ event }) => ({ req: { headers: event.headers } }),
plugins: [
ApolloServerPluginDrainHttpServer({
httpServer,
}),
{
async serverWillStart() {
return {
async drainServer() {
await serverCleanup.dispose();
},
};
},
},
],
});
// If I try :
//await server.start()
//I have this error => //Error: When using an ApolloServer subclass from a serverless framework package, you don't need to call start(); just call createHandler().
// If I try :
//server.applyMiddleware({app})
// I have this error => //Error: You must `await server.start()` before calling `server.applyMiddleware()`
// Then i try to use expressAppFromMiddleware() function to passed app server as middleware.
const handlerMiddleware = server.createHandler({
expressGetMiddlewareOptions: {
cors: {
origin: "*",
credentials: true,
},
},
expressAppFromMiddleware(middleware) {
app.use(middleware);
return app;
},
});
return handlerMiddleware;
});
};
export const handler = async (event: any, context: any, callback: any) => {
const serverHandler = await initServer();
return serverHandler({ ...event }, context, callback);
};
When i use Studio, I can see the root subscription
I tested to create Movies with Postman (POST http ://localhost:4242/channel-subscription)
with graphQL body :
mutation CreateMovies($input: [MovieCreateInput!]!) {
createMovies(input: $input) {
movies {
description
title
}
}
}
and with variables :
{
"input": [
{
"title": "new film",
"description": "I am description"
}
]
}
The result of createdMovie is : Status 200 OK
And the response is :
{
"data": {
"createMovies": {
"movies": [
{
"description": "I am description",
"title": "new film"
}
]
}
}
}
Queries also works.
But when I try to realize Subscription with Postman (POST http ://localhost:4242/channel-subscription)
with graphQL body :
subscription MovieCreated($where: MovieSubscriptionWhere) {
movieCreated(where: $where) {
event
timestamp
createdMovie {
title
description
}
}
}
and with variables :
{
"where": {
"title": "title of new film for subscription test"
}
}
the result of subscription return:
{
“errors”: [
{
“message”: “Payload is undefined. Can’t call subscriptions resolver directly.”,
“rentals”: [
{
“line”: 2,
column: 3
}
],
“path”: [
“movieCreated”
],
“extensions”: {
“code”: “INTERNAL_SERVER_ERROR”,
“exception”: {
“stacktrace”: [
“Error: Payload is undefined. Can’t call subscriptions resolver directly.”,
" at subscriptionResolve (/Users/Aymeric/my-projects/node_modules/@neo4j/graphql/dist/schema/resolvers/subscriptions/subscribe.js:30:15)“,
" at /Users/Aymeric/my-projects/node_modules/@neo4j/graphql/dist/schema/resolvers/wrapper.js:114:12”,
" at field.resolve (/Users/Aymeric/my-projects/node_modules/apollo-server-core/dist/utils/schemaInstrumentation.js:56:26)“,
" at executeField (/Users/Aymeric/my-projects/node_modules/graphql/execution/execute.js:481:20)”,
" at executeFields (/Users/Aymeric/my-projects/node_modules/graphql/execution/execute.js:413:20)“,
" at executeOperation (/Users/Aymeric/my-projects/node_modules/graphql/execution/execute.js:358:14)”,
" at execute (/Users/Aymeric/my-projects/node_modules/graphql/execution/execute.js:136:20)“,
" at execute (/Users/Aymeric/my-projects/node_modules/apollo-server-core/dist/requestPipeline.js:205:48)”,
" at processGraphQLRequest (/Users/Aymeric/my-projects/node_modules/apollo-server-core/dist/requestPipeline.js:148:34)“,
" at processTicksAndRejections (internal/process/task_queues.js:95:5)”,
" at async processHTTPRequest (/Users/Aymeric/my-projects/node_modules/apollo-server-core/dist/runHttpQuery.js:221:30)"
]
}
}
}
],
“data”: null
I think I have a problem with expressAppFromMiddleware , but I don’t understand where is my error
I specify the code in my serverless.yml who create the function is :
functions:
channel-subscription:
handler: ./src/functions/channel-subscription.handler
description: test subscription with appolo server
events:
- http:
path: /channel-subscription
method: post
cors: true
- http:
path: /graphql
method: post
cors: true