Open cdepillabout opened 2 years ago
sam local start-api
leaves out some fields that aws-lambda-haskell-runtime
is expecting(I've sent a fix for this at https://github.com/theam/aws-lambda-haskell-runtime/pull/119.)
AWS SAM provides a command sam local start-api
for running an AWS APIGateway endpoint locally for development. This is described in the document Running API Gateway locally. The requests/events that are passed to aws-lambda-haskell-runtime
do not have all the fields that aws-lambda-haskell-runtime
is expecting.
For instance, in one terminal run:
$ sam local start-api
and then in another terminal run:
$ curl -v -X POST -H 'Content-Type: application/json' -d '{"name": "helll", "age": 39}' http://127.0.0.1:3000/hey
The Haskell application gets a request event that looks like the following:
{
"body": "{\"name\": \"helll\", \"age\": 39}",
"headers": {
"Accept": "*/*",
"Content-Length": "28",
"Content-Type": "application/json",
"Host": "127.0.0.1:3000",
"User-Agent": "curl/7.79.1",
"X-Forwarded-Port": "3000",
"X-Forwarded-Proto": "http"
},
"httpMethod": "POST",
"isBase64Encoded": false,
"multiValueHeaders": {
"Accept": [
"*/*"
],
"Content-Length": [
"28"
],
"Content-Type": [
"application/json"
],
"Host": [
"127.0.0.1:3000"
],
"User-Agent": [
"curl/7.79.1"
],
"X-Forwarded-Port": [
"3000"
],
"X-Forwarded-Proto": [
"http"
]
},
"multiValueQueryStringParameters": null,
"path": "/hey",
"pathParameters": null,
"queryStringParameters": null,
"requestContext": {
"accountId": "123456789012",
"apiId": "1234567890",
"domainName": "127.0.0.1:3000",
"extendedRequestId": null,
"httpMethod": "POST",
"identity": {
"accountId": null,
"apiKey": null,
"caller": null,
"cognitoAuthenticationProvider": null,
"cognitoAuthenticationType": null,
"cognitoIdentityPoolId": null,
"sourceIp": "127.0.0.1",
"user": null,
"userAgent": "Custom User Agent String",
"userArn": null
},
"path": "/hey",
"protocol": "HTTP/1.1",
"requestId": "eb84ba71-128a-494d-bfce-b5985e9146d8",
"requestTime": "07/May/2022:11:30:08 +0000",
"requestTimeEpoch": 1651923008,
"resourceId": "123456",
"resourcePath": "/hey",
"stage": "Prod"
},
"resource": "/hey",
"stageVariables": null,
"version": "1.0"
}
You can see that this is missing some fields that aws-lambda-haskell-runtime
is expecting (in addition to things like requestContext.extendedRequestId
being null
, when aws-lambda-haskell-runtime
expects it to not be null
).
body
of API Gateway requests always a String?From the AWS documentation (and playing around with sam local generate-event
and sam local start-api
) it appears that the body
field of an APIGatewayRequest
will always be a JSON String (possibly base64-encoded). I couldn't find a specification of exactly what an ApiGatewayRequest
needs to look like anywhere on the AWS site, but there are two pages that at least have examples of requests:
The previous comment also has an example of the body
field.
This isn't a problem, per se, but it was quite confusing that there is a instance FromJSON body => FromJSON ApiGatewayRequest body
, when body
can't be any arbitrary JSON blob, but body
really needs to be a JSON String. You can then potentially take the JSON String and decode it as JSON, but aws-lambda-haskell-runtime
doesn't seem to provide any support for this.
It seems like ApiGateway also has a feature for base64-encoding the body
field (and setting the corresponding field isBase64Encoded
to true
), but aws-lambda-haskell-runtime
doesn't have any sort of helper functions for decoding the body
field based on the value of isBase64Encoded
.
I've been trying to use aws-lambda-haskell-runtime with the AWS SAM CLI. I've run into multiple problems. I'll describe them in this issue. I'm new to AWS Lambda and AWS SAM, so you should take this issue with a grain of salt.
Resources
I learned about SAM from the AWS SAM Developer Guide. In particular,
Setup
I've setup an example Haskell application using
aws-lambda-haskell-runtime
. I've usedsam
to generate atemplate.yaml
file, and then edited to match my Haskell application.Here's my
sam
version:I believe I generated my
template.yaml
file with a command likesam init
, but I forget the specifics. You can find an example in the above resources section.My
template.yaml
looks like the following:The one thing to note here is that the value for
Resources.HeyWorldFunction.Properties.Handler
ishandler
. I use this function in my Haskell application.I have a
Makefile
for building this application that is used bysam build
:The only important target here is
build-HeyWorldFunction
(but it is not directly related to this issue).Here is the
.cabal
file for my application.bootstrap.cabal
:Here's my
app/Main.hs
file:This application can be built by running
sam build
. You can find the built application in the current directory at.aws-sam/build/HeyWorldFunction/bootstrap
.Problem 1:
sam local generate-event
leaves out some fields thataws-lambda-haskell-runtime
is expecting(I've sent a PR for this at https://github.com/theam/aws-lambda-haskell-runtime/pull/119.)
AWS SAM gives you a way to define example events in files, and then run your function passing it an event from a file. AWS SAM provides the command
sam local generate-event
to generate event files. This is described in the document Invoking functions locally.One problem is that the events that
sam local generate-event
generates don't have all the fields thatApiGatewayRequest
is expecting.For instance, here is an example of generating an event, and then the resulting event file:
This generates an API Gateway Lambda proxy event. Here is the resulting event file:
You can run the Haskell application built with
sam build
by running:If you do this, you'll see errors that
aws-lambda-haskell-runtime
is expecting more fields than are present in the above input event file. For example,aws-lambda-haskell-runtime
expects theextendedRequestId
field, but that is not defined in this event. There are a few other fields like this as well.