Lambda Go API Gateway Integration and Parameters

As part of a recent project, I was trying to get the parameters from a REST call on AWS API Gateway in a Go Lambda. I found the documentation to be a bit scattered and hard to find so I have documented what I learned. The answer is simple so hopefully this doc helps someone else who struggled with the docs.

API Gateway to Lambda Integration

There are two main ways of invoking a Lambda from an API Gateway endpoint. All of my code uses proxy integration. There’s a section here that describes the differences, and as far as I can tell proxy is generally the preferred approach.

REST Parameters

The particular problem I was trying to solve is getting access to parameters passed in the REST call in my Golang Lambda code. In this example I’m going to look only at GET calls, I’ll do an update on POST in a future write-up. There are two alternatives for adding parameters to REST GET calls.

https://example.com/rest/endpoint?param1=value1
https://example.com/rest/endpoint/value1

The first URL above uses a query parameter, where the parameter name is param and the value is value1. The second uses a path parameter which is unnamed and also has value1. API Gateway supports both parameter types. In both cases the parameter name has to be declared as part of the API Gateway definition. If you use the serverless framework then parameter definition for a path parameter looks like this.

functions:
  getInfo:
    handler: bin/info
    events:
      - http:
          path: info/{param1}
          method: get
          request:
            parameters:
              paths:
                param1: true

Accessing Parameters in Go

Lambda Go proxy integrations are invoked through a handler method. The first thing that I missed is that the Handler method has several possible signatures and only some of them have the parameters. Here’s a very simple Go Lambda with a handler that has access to parameters.

package main

import (
	"context"
	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
	"github.com/aws/aws-sdk-go/aws"
)

func handler(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
  param1 := request.QueryParameters["param1"]
}

func main() {
	lambda.Start(Handler)
}

Notice that the handler method has a request parameter of type events.APIGatewayProxyRequest, that’s the parameter that provides access to the information in the inbound API Gateway request. You can see the documentation here.

Query Parameter

Getting the value of a query parameter as shown in the first example above has two possible variations. Those variations come from the fact that query parameters are allowed to repeat, meaning that there could be multiple values for the same parameter name. Repeating looks like this http://example.com/rest/endpoint?param1=value1&param1=value2. Hopefully you’ll know if a parameter could be repeating. For single values do this:

rawParam1, found := request.QueryParameters["param1"]
if found {
  // query parameters are typically URL encoded so to get the value
  value, err := url.QueryUnescape(rawParam1)
  if nil != err {
    return handleError(err)
  }
  // ... now use the value as needed
}

Query parameters that can have multiple values can be retrieved through a separate property of the request object. The result is an array of strings.

rawParams, found := request.MultiValueQueryStringParameters["param1"]
if found {
  // ... now iterate through the array of values, unescaping each
}

Path Parameter

To get the value of a path parameter, as shown in the second example above, and check if it exists, do the following:

rawParam1, found := request.PathParameters["param1"]
if found {
  // path parameters are typically URL encoded so to get the value
  value, err := url.QueryUnescape(rawParam1)
  if nil != err {
    return handleError(err)
  }
  // ... now use the value as needed
}

Leave a Reply

Your email address will not be published. Required fields are marked *