API Gateway Lab

Exercise 1 - Mock APIs with Swagger

To get our hands dirty and quickly see it working, let's deploy an API from a Swagger definition file that just uses the pre-built demo Pet Store endpoint.

You should see an in-built swagger definition file like so (culled for brevity):

{
  "swagger": "2.0",
  "info": {
    "description": "Your first API with Amazon API Gateway. This is a sample API that integrates via HTTP with our demo Pet Store endpoints",
    "title": "PetStore"
  },
  "schemes": [
    "https"
  ],
  "paths": {
    "/": {
      "get": {
        "tags": [
          "pets"
        ],
        "description": "PetStore HTML web page containing API usage information",
        ...
        ...
        ...
{
  "type": "dog",
  "price": 249.99
} 
{
  "pet": {
    "type": "dog",
    "price": 249.99
  },
  "message": "success"
}
{
  "id": 1,
  "type": "dog",
  "price": 249.99
}

We've just successfully created an API Gateway integreated with an HTTP bakend.

Exercise 2 - Lambda Proxy Integration

Now let's create an API Gateway to expose the functionality of one of our Lambda functions that we created in the previous workshops. Let's pick the SimpleTaxCalculator Lambda function and expose that as a service.

Step 1 - Pick Lambda

Step 2 - Configure API Gateway

Now let's pick API Gateway as a trigger for our Lambda microservice.

This will have created a new API Gateway endpoint at which our SampleTaxCalculator microservice is now exposed.

Step 3 - Test

{
  "productPrice": 20,
  "taxRate": 10,
  "surchargeRate": 1
}
{
  "message": "Internal server error"
}

Look at logs to see the disconnect between how a browser sends a web request and how our Lambda function expects its input. So we need to update our original Lambda microservice to understand how a browser sends a request.

'use strict';

console.log('Loading tax calculator function...');

exports.handler = (event, context, callback) => {
    console.log('Received event: ', JSON.stringify(event, null, 2));
    
    try {
        let productPrice, taxRate, surchargeRate = null;
        
        if (event.body !== null && event.body !== undefined) {
            let body = JSON.parse(event.body)
            
            productPrice = body.productPrice;
            taxRate = body.taxRate;
            surchargeRate = body.surchargeRate;
        }
        else {
            productPrice = event.productPrice;
            taxRate = event.taxRate;
            surchargeRate = event.surchargeRate;
        }

        console.log(`Product price: $${productPrice}`);
        console.log(`Tax rate: ${taxRate}%`);
        console.log(`Surcharge rate: ${surchargeRate}%`);

        let tax = productPrice * (taxRate / 100.00);
        let surcharge = productPrice * (surchargeRate / 100.00);
        let finalPrice = productPrice + tax + surcharge;

        console.log(`Final price with tax: $${finalPrice}`);
        
        let returnValue = {
            price: finalPrice,
            state: "CA"
        }

        var response = {
            statusCode: 200,
            headers: {
                "x-custom-header" : "Some custom header value"
            },
            body: JSON.stringify(returnValue)
        };
    
        // On success, invoke the callback like so (2 arguments)
        // first one being null.
        callback(null, response); // Return calculated tax
    }
    catch(e) {
        console.log(e);
        
        // On failure, invoke the callback like so (a single argument)
        // with a helpful error message.
        callback('ERROR: Something went wrong!');
    }
    
    console.log("Done calculating tax.");
};

Original SimpleTaxCalculator.js

Comprehension Aid

To help better understand and visualize what we changed from the original SimpleTaxCalculator.js in order to get this to work with a web request from API Gateway, I've included a diff here:

console.log('Received event: ', JSON.stringify(event, null, 2));
     
     try {
-        console.log(`Product price: $${event.productPrice}`);
-        console.log(`Tax rate: ${event.taxRate}%`);
-        console.log(`Surcharge rate: ${event.surchargeRate}%`);
+        let productPrice, taxRate, surchargeRate = null;
         
-        let tax = event.productPrice * (event.taxRate / 100.00);
-        let surcharge = event.productPrice * (event.surchargeRate / 100.00);
-        let finalPrice = event.productPrice + tax + surcharge;
+        if (event.body !== null && event.body !== undefined) {
+            let body = JSON.parse(event.body)
+            
+            productPrice = body.productPrice;
+            taxRate = body.taxRate;
+            surchargeRate = body.surchargeRate;
+        }
+        else {
+            productPrice = event.productPrice;
+            taxRate = event.taxRate;
+            surchargeRate = event.surchargeRate;
+        }
+
+        console.log(`Product price: $${productPrice}`);
+        console.log(`Tax rate: ${taxRate}%`);
+        console.log(`Surcharge rate: ${surchargeRate}%`);
+
+        let tax = productPrice * (taxRate / 100.00);
+        let surcharge = productPrice * (surchargeRate / 100.00);
+        let finalPrice = productPrice + tax + surcharge;
 
         console.log(`Final price with tax: $${finalPrice}`);
         
         let returnValue = {
-            price: finalPrice
+            price: finalPrice,
+            state: "CA"
         }
 
+        var response = {
+            statusCode: 200,
+            headers: {
+                "x-custom-header" : "Some custom header value"
+            },
+            body: JSON.stringify(returnValue)
+        };
+    
         // On success, invoke the callback like so (2 arguments)
         // first one being null.
-        callback(null, returnValue); // Return calculated tax
+        callback(null, response); // Return calculated tax
     }
     catch(e) {
         console.log(e);

SimpleTaxCalculator.js - Src Control Diff