Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle cookies inside apollo-server-lambda

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.

like image 753
Popa Alex Avatar asked Aug 22 '19 12:08

Popa Alex


2 Answers

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.

like image 196
shahin8r Avatar answered Sep 23 '22 23:09

shahin8r


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

like image 40
Lucas Cavalcanti Avatar answered Sep 20 '22 23:09

Lucas Cavalcanti