Chapter 2: Building with Fauna + AWS
Creating lambda functions

Creating lambda functions

Create a new folder called src/functions. You put all your lambda function code in this folder. Create a new file src/functions/bookHotel.js and add the following code.

// bookHotel.js
 
'use strict';
 
// import faunadb driver
const faunadb = require('faunadb')
const q = faunadb.query;
 
// initialize fauna client
const serverClient = new faunadb.Client({ 
  secret: process.env.FAUNA_ROOT_KEY,
  domain: process.env.FAUNA_DOMAIN,
});
 
module.exports.handler = async (event, context) => {
 
  try {
    const newBooking = await serverClient.query(
      q.Create(
        q.Collection('Vacation'),
        { 
          data: {
            userId: event.userId,
            hotelBookingId: Math.random().toString(36).substring(2,12),
            status: 'pending',
          }
        },
      )
    );
 
    console.log('newBooking', JSON.stringify(newBooking));
 
    // Fake a delay for external API call
    await new Promise(resolve => setTimeout(resolve, 4000));
    const updateBooking = await serverClient.query(
      q.Update(
        q.Ref(q.Collection('Vacation'), newBooking['ref'].id),
        { 
          data: {
            status: 'confirmed',
          }
        },
      )
    )
 
    return {
      statusCode: 200,
      reservation: {
        id: newBooking['ref'].id,
        data: updateBooking.data
      },
      flightId: event.flightId
    };
  } catch (error) {
    throw new Error(error)
  }
};

This function creates a new vacation record in the collection. There is also a fake timer to mock any external API call.

Next, create a new file, src/functions/bookFlight.js and add the following code.

// bookFlight.js
'use strict';
 
// import faunadb driver
const faunadb = require('faunadb')
const q = faunadb.query;
 
// initialize fauna client
const serverClient = new faunadb.Client({ 
  secret: process.env.FAUNA_ROOT_KEY,
  domain: process.env.FAUNA_DOMAIN,
});
 
module.exports.handler = async (event, context) => {
  console.log('bookFlight', JSON.stringify(event, null, 2));
 
  // Fake a delay for external API call
  await new Promise(resolve => setTimeout(resolve, 3000));
 
  if (event.flightId === -1) {
    throw new Error(event.reservation.id);
  }
 
  try {
    const updateBooking = await serverClient.query(
      q.Update(
        q.Ref(q.Collection('Vacation'), event.reservation.id),
        { 
          data: {
            status: 'confirmed',
            flightStatus: 'confirmed',
          }
        },
      )
    )
    return {
      updateBooking,
      statusCode: 200
    };
  } catch (error) {
    throw new Error(error);
  }
};

Notice, that in the previous code block, when flightId is -1 the code throws an error. This is added to test the failed scenario. You have the option to pass the flightId in your event payload.

Finally, create another function to cancel hotel bookings.

// cancelHotel.js
'use strict';
 
// import faunadb driver
const faunadb = require('faunadb')
const q = faunadb.query;
 
// initialize fauna client
const serverClient = new faunadb.Client({ 
  secret: process.env.FAUNA_ROOT_KEY,
  domain: process.env.FAUNA_DOMAIN,
});
 
module.exports.handler = async (event, context) => {
  // Fake a delay for external API call
  // await new Promise(resolve => setTimeout(resolve, 10000));
 
  try {
    await serverClient.query(
      q.Update(
        q.Ref(q.Collection('Vacation'), JSON.parse(event.Cause).errorMessage),
        { 
          data: {
            status: 'cancelled',
          }
        },
      )
    )
    return { statusCode: 200 };
  } catch (error) {
    throw new Error(error);
  }
};

Next, you update the serverless.yml file to reflect these changes. Update the file as follows.

service: fauna-aws-workshop
 
frameworkVersion: '2.72.3'
 
# Specify donenv
useDotenv: true
 
# Add Fauna plugin
plugins:
  - serverless-dotenv-plugin
  - "@fauna-labs/serverless-fauna"
 
fauna:
  client:
    secret: ${env:FAUNA_ROOT_KEY}
    domain: ${env:FAUNA_DOMAIN}
  collections:
    Vacation: 
      name: Vacation
  indexes:
    vacations_by_userId:
      name: vacations_by_userId
      source: Vacation
      terms:
        fields:
          - data.userId
 
provider:
  name: aws
  runtime: nodejs14.x
  httpApi:
    cors: true
 
functions:
  bookHotel:
    handler: src/functions/bookHotel.handler
  bookFlight:
    handler: src/functions/bookFlight.handler
  cancelHotel:
    handler: src/functions/cancelHotel.handler

Deploy the stack by running sls deploy command.

When it finishes running the deployment script, visit your AWS console. Verify that you have three new lambda functions created from your AWS console.

Notice that no API event is specified in the functions section in the serverless.yml file. This is intentional because we do not want to execute these lambda functions directly by calling an API endpoint. We will execute the lambda functions through AWS Step function.

In the next section we will setup a Step function to orchestrate the Lambda functions.

Last updated on August 5, 2022