Just wanted to post this here since it's something I have seen other users running into this issue I was having and not having a straight forward answer.
Essentially, if you want to do any work before or after running your ApolloServer handler like build or tear down connections, or a top level logging function, or stage checking for turning playground on or off, this code should let you do it.
I ran into this issue because if you have an RDS, you will know that you need to close your connection after your call is handled else there will be lots of connections open which will eventually force your database to reach it's connection limit. Probably not an issue on the development scale of things, but once in production, this is a huge nightmare.
Anyway, here it is. Feel free to ask any questions. I just wanted to post this here since I have seen multiple issues around this, and middleware isn't a thing yet/again.
EDIT: This only works for Lambda on Node 8.10
If you are using 6.10, you will need a little bit different setup (but I recommend using 8.10 instead)
const { ApolloServer } = require('apollo-server-lambda');
const schema = require('./graphql');
const buildGraphQlContext = ({ context, event }) => ({
context,
event,
});
const runHandler = (event, context, handler) =>
new Promise((resolve, reject) => {
const callback = (error, body) => (error ? reject(error) : resolve(body));
handler(event, context, callback);
});
const run = async (event, context) => {
// Create your connections here
const server = new ApolloServer({
context: buildGraphQlContext,
playground: { settings: { 'editor.cursorShape': 'block' } },
...schema,
});
const handler = server.createHandler({ cors: { credentials: true, origin: '*' } });
const response = await runHandler(event, context, handler);
// Destroy your connections here
return response;
};
exports.handler = run;
:+1:
Simply for avoiding callbacks. It would be nice if there was an alternative createHandler that was promise driven.
Nice work!
Thanks for providing this setup! I think this issue can live — even closed — as an example for those that it's already helped and we will be working on a Promise driven handler (which will hopefully be identical across all integrations — e.g. Expresss, Lambda, Koa, etc.) for Apollo Server 3.x.
@Prefinem Thank you very much for posting this :pray:
Hey all, I found this middleware library (https://github.com/middyjs/middy.) for lambda which I think can work with apollo-server-lambda. If both of them use the same way to terminate the function (either returning a promise or calling the lambda callback) it should work flawlessly. Something like:
const server = new ApolloServer({
schema: buildFederatedSchema([
{
typeDefs,
resolvers,
},
]),
context: async ({ request, context }) => {
// you can still use the apollo context, this will run after the before middlewares
},
});
const graphqlHandler = server.createHandler();
const handler = middy(graphqlHandler)
handler
.use(dbMiddleware())
.use(tokenCheck())
module.exports = handler
The benefit of this (aside from modularizing your before and after hooks) is that the apollo server is initialized once and not during every function call.
I havent tried it yet since we are currently working with azure right now but I did a frankenstein and wire up a middleware library similar to middy that works in azure. It is by no means ready for production, we have only spend a day working on it and havent even deployed it yet but it is a good start. https://github.com/Rapol/middizure. An example:
const server = new ApolloServer({
schema: buildFederatedSchema([
{
typeDefs,
resolvers,
},
]),
context: async ({ request, context }) => {
// you can still use the apollo context, this will run after the before middlewares
},
});
exports.graphqlHandler = withMiddlewares(server.createHandler(), [
databaseMiddleware({
databaseService,
}),
], { useCallback: true });
Most helpful comment
:+1:
Simply for avoiding callbacks. It would be nice if there was an alternative
createHandlerthat was promise driven.Nice work!