Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to throw errors from inside a serverless lambda

Can someone help me understand how to throw authentication errors in a graphQL lambda app? I'm using graphQL-yoga with serverless and I can authenticate a request and either return a user that I get from the jwt, a {} for no token, or throw an authentication error if the token is old. When I throw an error it gets caught in the catch statement of my authenticate block, but I have no idea how to actually return that from the lambda.

const lambda = new GraphQLServerLambda({
  typeDefs,
  context: ({ event, context }) =>
    authenticate(event.headers.Authorization)
      .then(user => ({ db: mainDb, user}))
      .catch(e => {
        console.log('Caught the auth error here');
        throw e;
      }),
   Query: { \\ some queries here.... },
   Mutation: { \\ some mutations here...}
 });

How can I either format the error or throw it from the right spot so that I get an actual formatted error? Instead I get a Unexpected token I in JSON... error in the client. Clearly I need to do some sort of formatting during my throw but it isn't totally obvious to me how to do that.

If it is helpful, here in my exports part. I'm trying everything from try/catch to then/catch and at this point I have seemed to already miss catching the error. Is there a better way to be doing this? The main thing I need is the ability to either authenticate, reject bad tokens, and otherwise just return a {} for a non-logged in user. I'm having the hardest time finding custom authorizers that allow non-logged in users so that's why I am doing the auth directly in my graphQL endpoint

exports.server = (event, context, callback) => {
  try {
    return lambda
      .graphqlHandler(event, context, callback)
      .then(b => b)
      .catch(e => console.log(`can't catch it here ${e}`));
  } catch (e) {
    console.log('or here');
    callback(e);
  }
};
like image 965
Coherent Avatar asked May 09 '18 12:05

Coherent


People also ask

How do you throw errors in Lambda?

Here is the proper way to throw, catch, and format errors that are generated in a lambda function with serverless. The trick is to create a modified callback which gets passed into the graphQL Handler. When the function gets resolved, it will run through any code that you want.

How do you handle errors in Lambda API gateway?

Make sure that you also set up the corresponding error code ( 400 ) on the method response. Otherwise, API Gateway throws an invalid configuration error response at runtime. At runtime, API Gateway matches the Lambda error's errorMessage against the pattern of the regular expression on the selectionPattern property.

Can we throw exception from lambda expression?

A lambda expression cannot throw any checked exception until its corresponding functional interface declares a throws clause. An exception thrown by any lambda expression can be of the same type or sub-type of the exception declared in the throws clause of its functional interface.


2 Answers

One option to customize your error message would be to create a new instance of the Error class.

An example would be:

.catch(e => {
  console.log('Caught the auth error here');
  throw new Error('Authentication Failed');
 }),

Because the first parameter of the callback function is going to be the error message, you could also stick a generic error directly into the handler function:

 callback("An error happened!");

You can also use a middleware such as Middy to help with error handling:

https://github.com/middyjs/middy/blob/master/docs/middlewares.md#httperrorhandler

A helpful link on NodeJS error handling:

https://www.joyent.com/node-js/production/design/errors

like image 152
Seanvm Avatar answered Nov 06 '22 20:11

Seanvm


I finally got it! Here is the proper way to throw, catch, and format errors that are generated in a lambda function with serverless. The trick is to create a modified callback which gets passed into the graphQL Handler. When the function gets resolved, it will run through any code that you want.

Also, Seanvm was right that looking into the type of lambda function is important- serverless sets up a proxy-lambda function by default which necessitates formatting the output like I do below and passing null as the error.

exports.server = (event, context, callback) => {
  const modifiedCallback = (error, output) => {
    if (output.body.includes('401')) {
      callback(null, {
        statusCode: 401,
        headers: { 'Content-Type': 'application/javascript' },
        body: JSON.stringify({ message: 'Unauthorized' })
      });
    } else {
      callback(error, output);
    }
  };
  return lambda.graphqlHandler(event, context, modifiedCallback);
};
like image 37
Coherent Avatar answered Nov 06 '22 20:11

Coherent