Function signature when using AWS Lambda

Hi,

I’m trying to set up a service using F# and AWS Lambda. As I’m looking around at examples, I see a couple of different ways of setting up the functions that will be called. One way to do it is like this: https://github.com/bslatner/aws-serverless-lambda-fsharp-template/blob/master/src/FSharpLambda/Lambda.fs

In that example, the handling functions take in some domain type, plus an ILambdaContext.

Here’s another way to do it: https://github.com/serverless/serverless/blob/067bb12b08e644348455c5764b656437f475db51/lib/plugins/create/templates/aws-fsharp/Handler.fs

In that example, no ILambdaContext is passed in.

Does anybody know if there’s any reason to do it one way or the other?

Thanks!

1 Like

Still learning how to build AWS Lambda functions myself and for now I’m using official AWS templates as a starting point. You can read the Command line tooling part of this article to see how to install and use those templates.

I’ve been using F# in AWS Lambda for about a year now, and while I’m not an expert, perhaps I can at least help you get off to a good start.

I got my start pretty much totally got my start from this Github repo, https://github.com/FSharpBristol/FSharp-Template-for-Aws-Lambda which rather than bookmarking, I just repeatedly locate by googling “f# lambda template”.

Typically you can create a handler function such as seen in Script.fs in that repo, but I will add a custom record type for arguments, like

let handler(myCustomArgs, context:ILambdaContext) = 
    printfn "Here are my args! %A" myCustomArgs

I wish I had a better understanding of the serialization library used - I believe it is performed by something included with the AWS SDK/Lambda packages that you get from nuget. So far my object/record structures that i have used for function arguments have been pretty simple, so I have been saved from having to learn the particulars of what might be a single-use (from my perspective) serialization library.

I did have to include one more odd tidbit somewhere I believe one instance anywhere in my project’s .fs files

[<assembly: LambdaSerializer(typedefof<Amazon.Lambda.Serialization.Json.JsonSerializer>)>]
do()

… and I’ve totally forgotten the reasons why over the course of a year, but my guess would be to ensure that some skip-level reference gets properly included in your build output.

Also, I’ve found some pretty big improvements on these methods recently, which I’ll post in a subsequent message…

The biggest issue I discovered over time with the previous method of Lambda design in F# was in difficulty controlling the HTTP Result codes returned by my functions. I believe the previous strategy required you to do quite a bit of custom data mapping in API Gateway, such that APIGW could parse some part of your response to deduce the HTTP Result Code to be returned to the client, which sounded quite undesirable to me.

A better (in my opinion, and depending on your use case) way to design your lambda functions is using what AWS calls “Lambda Proxy Integration” which I think is somewhat recently added.

This feature is enabled in the API Gateway on (I believe) a per-Resource-and-HTTP-Verb basis. You click a resource, then click a verb, then click on “Integration Request” and you should see a checkbox labeled “Use Lamba Proxy Integration” to enable this feature. (and of course deploy the changes)

Once this is enabled (and you add package Amazon.Lambda.APIGatewayEvents), you can write lambda functions more like:

let handler(request:APIGatewayProxyRequest, context:ILambdaContext) : APIGatewayProxyResponse =
... // do the things

with the kicker being that AWS no longer controls the (de)serialization, so as an alternative you can deserialize the request.Body in any way you please (and you can remove that assembly-level attribute that I mentioned in the previous message). Also if you google the full names of either of these request/response types and just quickly peruse their source, you can see that they both give you control over the full complement of HTTP Artifacts, accessing the headers in the request and setting them in the response. Controlling the HTTP result codes, and so on. The whole Lambda experience begins to feel much more like working with typical web frameworks.

In fact, to take it one step further, there’s this


which, IF I’m reading it correctly (and that’s a BIG “if,” because I’ve never done/used this before), it looks like you can indeed integrate a conventional web framework into Lambda, with a bit of configuration, such that the web application handles all of the routing to the various code functions, just like it would if the web framework and attendant code were running in a non-Lambda context.

So my guess is that this would allow you to dump an entire existing (or new) web app into a single lambda, with a single small bit of API Gateway configuration, and then just keep pushing code as your project expands and grows, but without (as far as I can see) needing to touch the initial AWS part of the configuration much ever, if at all. This would truly be a god-send for infrastructure haters such as myself.

One other thing I just thought of - I’ve written all of this under the assumption that you’ll be using API Gateway to trigger Lambda. Saw a list recently showing that AWS had added proxy integrations for maybe 6-8 other AWS services that can trigger your Lambda as well. Presumably the steps would all be the same, save for different nuget packages, and different object types in your “handler” function’s signature.

Hope this helps. It’s a little bit confusing/overwhelming to start, but I’ve come to really like Lambda quite a lot, and F# has been a fabulous pairing for it.

I typed out a massive amount of info, but never directly answered your question. Knowing nothing about a project’s goals or requirements, I would strongly recommend the solution in your first link.

Hello,

You have an example here also if needed : https://github.com/aws/aws-lambda-dotnet/tree/master/Libraries/test

Yes, you can use any conventional web framework with AWS Lambda as long as they are triggered by API Gateway. In the article we both linked to it explains how to install a template for Giraffe. You could of course use any other framework you like.

Thanks everybody! Really appreciate all the help.

1 Like