set cookies inside a lambda serverless with apollo-server-lambda
I am migrating from apollo-server to the serverless version. Is there a way I can access the response object or another way to set cookies?
context: ({ event, context }) => ({
headers: event.headers,
functionName: context.functionName,
event,
context,
}),
I was expecting in the context to have access to the res object like it was in the apollo-server.
You need a way to set the response headers in your resolvers.
What you can do is to set a value to the context object in your resolver.
const resolver = (parent, args, { context }) => {
context.addHeaders = [{ key: 'customheader', value: 'headervalue'}]
}
You can catch the context in willSendResponse
event in the server lifecycle by creating a Apollo Server plugin. You can then add your headers from customHeaders
property to the GraphQLResponse
object.
const customHeadersPlugin = {
requestDidStart(requestContext) {
return {
willSendResponse(requestContext) {
const {
context: { addHeaders = [] }
} = requestContext.context
addHeaders.forEach(({ key, value }) => {
requestContext.response.http.headers.append(key, value)
})
return requestContext
}
}
}
}
You need to load the plugin in Apollo Server.
const server = new ApolloServer({
typeDefs,
resolvers,
plugins: [customHeadersPlugin],
context: ({ context }) => ({
context
})
})
Now you've got a way to modify the response headers in your resolvers. To be able to set a cookie you can either set the Set-Cookie
header manually with a cookie string or using a cookie library.
Thanks to Trevor Scheer of the Apollo GraphQL team for pointing me in the right direction when I needed to implement this myself.
I couldn't find a way to do that using apollo-server-lambda, so what a I did was use apollo-server-express and serverless-http in conjuction. The code below is using import/export because I am using typescript.
serverless-http accepts a variety of express-like frameworks.
import express from 'express'; // <-- IMPORTANT
import serverlessHttp from 'serverless-http'; // <-- IMPORTANT
import { ApolloServer } from 'apollo-server-express'; // <-- IMPORTANT
import typeDef from './typeDef';
import resolvers from './resolvers';
export const server = new ApolloServer({
typeDef,
resolvers,
context: async ({ req, res }) => {
/**
* you can do anything here like check if req has a session,
* check if the session is valid, etc...
*/
return {
// things that it'll be available to the resolvers
req,
res,
};
},
});
const app = express(); // <-- IMPORTANT
server.applyMiddleware({ app }); // <-- IMPORTANT
// IMPORTANT
// by the way, you can name the handler whatever you want
export const graphqlHandler = serverlessHttp(app, {
/**
* **** IMPORTANT ****
* this request() function is important because
* it adds the lambda's event and context object
* into the express's req object so you can access
* inside the resolvers or routes if your not using apollo
*/
request(req, event, context) {
req.event = event;
req.context = context;
},
});
Now for instance you can use res.cookie() inside the resolver
import uuidv4 from 'uuid/v4';
export default async (parent, args, context) => {
// ... function code
const sessionID = uuidv4();
// a example of setting the cookie
context.res.cookie('session', sessionID, {
httpOnly: true,
secure: true,
path: '/',
maxAge: 1000 * 60 * 60 * 24 * 7,
});
}
another useful resource
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With