AWS

AWS Lambda exposed via ApiGateway

 

What are we talking about this time?

This time we are going to talk about how to expose our AWS lambda function over HTTP.  This is actually fairly simple to do so this will not be a big post, and will certainly build on what we saw in the last post where I introduced how to create and publish a new AWS lambda function.

Initial setup

If you did not read the very first part of this series of posts, I urge you to go and read that one now as it shows you how to get started with AWS, and create an IAM user : https://sachabarbs.wordpress.com/2018/08/30/aws-initial-setup/

Where is the code

The code for this post can be found here in GitHub : https://github.com/sachabarber/AWS/tree/master/Compute/Lambda.ApiGateway.DemoApp

What is AWS API Gateway?

Amazon API Gateway is an AWS service that enables developers to create, publish, maintain, monitor, and secure APIs at any scale. You can create APIs that access AWS or other web services, as well as data stored in the AWS Cloud.

image

In practical terms, API Gateway lets you create, configure, and host a RESTful API to enable applications to access the AWS Cloud. For example, an application can call an API in API Gateway to upload a user’s annual income and expense data to Amazon Simple Storage Service or Amazon DynamoDB, process the data in AWS Lambda to compute tax owed, and file a tax return via the IRS website.

As shown in the diagram, an app (or client application) gains programmatic access to AWS services, or a website on the internet, through one or more APIs, which are hosted in API Gateway. The app is at the API’s frontend. The integrated AWS services and websites are located at the API’s backend. In API Gateway, the frontend is encapsulated by method requests and method responses, and the backend is encapsulated by integration requests and integration responses.

With Amazon API Gateway, you can build an API to provide your users with an integrated and consistent developer experience to build AWS cloud-based applications.

https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html up on date 07/10/18

Writing a Lambda that Is exposes via API Gateway

Ok so now that we know what an API Gateway is, how do we write a AWS Lambda to use it? Well as before there are APIGatewayEvents that can be used inside of a Lambda function. Lets see the relevant code shall we:

using System;
using System.Collections.Generic;
using System.Net;
using Amazon.Lambda.APIGatewayEvents;
using Amazon.Lambda.Core;
using Newtonsoft.Json;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]

namespace Lambda.ApiGateway.DemoApp
{
    public class Function
    {

        ITimeProcessor processor = new TimeProcessor();

        /// <summary>
        /// Default constructor. This constructor is used by Lambda to construct
        /// the instance. When invoked in a Lambda environment
        /// the AWS credentials will come from the IAM role associated with the
        /// function and the AWS region will be set to the
        /// region the Lambda function is executed in.
        /// </summary>
        public Function()
        {

        }

        public APIGatewayProxyResponse FunctionHandler(
            APIGatewayProxyRequest apigProxyEvent, ILambdaContext context)
        {
            LogMessage(context, "Processing request started");
            APIGatewayProxyResponse response;
            try
            {
                var result = processor.CurrentTimeUTC();
                response = CreateResponse(result);

                LogMessage(context, "Processing request succeeded.");
            }
            catch (Exception ex)
            {
                LogMessage(context, 
                    string.Format("Processing request failed - {0}", ex.Message));
                response = CreateResponse(null);
            }

            return response;
        }

        APIGatewayProxyResponse CreateResponse(DateTime? result)
        {
            int statusCode = (result != null) ?
                (int)HttpStatusCode.OK :
                (int)HttpStatusCode.InternalServerError;

            string body = (result != null) ?
                JsonConvert.SerializeObject(result) : string.Empty;

            var response = new APIGatewayProxyResponse
            {
                StatusCode = statusCode,
                Body = body,
                Headers = new Dictionary<string, string>
                {
                    { "Content-Type", "application/json" },
                    { "Access-Control-Allow-Origin", "*" }
                }
            };
            return response;
        }

        /// <summary>
        /// Logs messages to cloud watch
        /// </summary>
        void LogMessage(ILambdaContext ctx, string msg)
        {
            ctx.Logger.LogLine(
                string.Format("{0}:{1} - {2}",
                    ctx.AwsRequestId,
                    ctx.FunctionName,
                    msg));
        }

    }
}

It can be seen that we need to use a specialized APIGatewayProxyRequest/APIGatewayProxyResponse pair

In this example we are exposing the AWS Lambda as a GET only operation. If you wanted to accept POST/DELETE/PUT data you could use the APIGatewayProxyRequest.Body to get the data representing the request.

Ok, so now that we have the code, and lets assume that the Lambda has been published to AWS (see the last article for a detailed explanation of how to do that). For now lets assume we have published the above code to AWS, and we have it available in the AWS console, we would now need to configure the API Gateway part of it.

Which  starts with just telling the ApiGateway trigger which stage to run in. This is shown below

imageOnce we have configured the ApiGateway trigger for the published lambda, we should see it shown something like the screen shot below. We then need to move on to setting up the actual ApiGateway resources themselves and how they relate to the Lambda call.

image

We can do this either by following the link shown within the Api Gateway section of our lambda as shown above, or via the AWS console where we just search for the Api Gateway. Both paths are valid, and should lead you to a screen something like the one below. It is from this screen that we will add new resources.

imageSo we wish (at least for this demo) to create a GET resource that will call our Lambda. We can do this by using the Actions menu, and creating a new GET from the drop down options. We then setup the GET resource to call the lambda (the one for this demo). This is all shown in the screen shot below

imageOnce we have added the resource we should be able to test it out using the Test button (the one shown below with the lightning bolt on it). This will test the Api resource. So for this demo this should call the Lambda and GET a new time returned to the Api Gateway call, and we should see a status code of 200 (Ok)

imageSo if that tests out just fine, we are almost there. All we need to do now ensure that the Api Gateway is deployed. This can be done using the “Deploy API” menu option from the Api Gateway portal, as shown below.

imageWith all that done, we should be able to test our deployed Api Gateway pointing to our Lambda, so lets grab the public endpoint for the Api Gateway, which we can do my examining the Stages menu, then finding our resource (GET in this case) and getting hold of the Invoke Url.

imageSo for me this looks like this

imageCool looks like its working.

See ya later, not goodbye

Ok that’s it for now until the next post

3 thoughts on “AWS Lambda exposed via ApiGateway

  1. Ugh. You hard coded ‘content-type’ rather than passing it via your request. Second, ‘access-allow-orgins’ should be in a separate cors class where you should be doing checking; right now you are allowing ALL traffic through so effectively, I can act as a proxy for your server and DDS you. Finally, you are not handling security locally so there is no synchronization of the roles/authorities between the proxy and endpoint leading to elevated privileges.

    1. Orobel

      Yeah sure I could have passed it through via request no problem on that one.

      For the 2nd point about it being separate CORS class this feels like a opinion thing

      With this series of posts, I am trying not to get too involved with the perfect post, its more a beginners guide.

      I am sure there will be more work, more reading, more coding required, but it’s more of a show me the starting places for getting up and running

      Thanks for your comments though

      1. Well CORS is alot more than what you have. You left out the security component to CORS as well as potential for blacklisting/whitelisting. This is why you have it be a separate class.

Leave a comment