Writing Code for Lambda Event Handlers
This tutorial references the code in the aws-connectedcar-dotnet-serverless repository. If you're new to this course, see the introduction for information about setting up your workstation and getting the sample code.
Continuing our look at writing code for Lambdas, in this tutorial we’re going to show how to implement the event handling methods.
Adding Library References
Before you can write any code for Lambdas you have to add the necessary AWS libraries to your project references. For the Lambdas we’re working with, which are triggered by API Gateway proxy events, you need to add the library references shown below:
In these references, line 8 shows the AWS library for the API Gateway-specific events. Lines 9-10 show the basic Lambda libraries, and lines 13-15 show the configuration, dependency injection, and serialization libraries used. Lastly, lines 16-17 show the two libraries from the ConnectedCar.Core repository, for the code we covered in the previous tutorial.
Writing Event Handling Methods
Lambdas can act as handlers for a variety of different AWS event triggers, and each type of event trigger requires a specific Lambda method signature. Most of the Lambdas in the sample code are triggered by API Gateway proxy integration events. The CreateDealer method in the AdminFunctions class is a good example, as shown below. This is the event handler for our familiar “/admin/dealers” (POST) endpoint:
You can see in this code that the first input parameter is an APIGatewayProxyRequest and the output is an APIGatewayProxyResponse. This is the method signature to use for Lambdas that handle events for an API Gateway proxy integration. This example responds to an HTTP POST method and as a result it creates an item in DynamoDB. The response includes an HTTP 201 status code as well as an HTTP header value that includes the resource path at which the newly created entity can be referenced. This is the REST convention for POST actions.
GET actions return serialized JSON in the body of the request, as you can see in the GetDealers method of the same AdminFunctions class, for example:
Another thing to note is that for .Net Lambdas the method name for the event handler must correspond to that specified in the Lambda resource in the CloudFormation template. Line 80 in the template below shows the Handler property for the CreateDealer Lambda that corresponds to the first method shown above. The value for this property must include the Lambda assembly name, qualified class name, and method name, all delimited by double colons:
Because the Handler property shown above specifies a method rather than a class (as in Java), when writing .Net Lambdas you can combine as many methods into a single class as you wish. In the sample code, we've opted to combine the Lambda methods into classes that correspond to the three APIs. So you’ll see that there’s an AdminFunctions class, a VehicleFunctions class, and a CustomerFunctions class.
Using Delegates for Error-Handling & Logging
If you look again at the code for the CreateDealer method, you’ll see that we’re wrapping our event handling logic in a Func delegate, which is passed as a parameter to the Process method, shown below on line 24:
The Lambda classes in the sample code use this delegate pattern as a way to factor out exception handling and logging from the event handler methods. Here’s the implementation for the Process method in the BaseRequestFunctions class, in which you can see that the first input parameter is the Func that is constructed in all the calling Lambdas:
Writing Convenience Methods for Serialization
To keep the event handling code for the Lambdas clean, we’ve added these two convenience methods that deserialize request bodies and serialize responses to the BaseRequestFunctions class:
As you can see above, these .Net Lambdas use the Newtonsoft JSON library, for which there’s some configuration required in code. Line 121 in the Deserialization method above shows the use of the jsonSerializerSettings parameter. This settings object requires a string-escape-handling setting and a Newtonsoft Enum converter assigned to it, as shown below:
Writing Convenience Methods for Parsing Headers & Parameters
Values for HTTP headers and HTTP path and query parameters are all accessed through dictionaries in the APIGatewayProxyRequest. Here’s three convenience methods in the sample code that parse and validate these values:
Here’s another convenience method example that parses a query parameter and converts it to a StateCodeEnum value:
This tutorial references the code in the aws-connectedcar-java-serverless repository. If you're new to this course, see the introduction for information about setting up your workstation and getting the sample code.
Continuing our look at writing code for Lambdas, in this tutorial we’re going to show how to implement the event handling methods.
Adding Library References
Before you can write any code for Lambdas you have to add the necessary AWS libraries to your project references. For the Lambdas we’re working with, which are triggered by API Gateway proxy events, you need to add the library references shown below:
In these references, lines 30-39 show the basic Lambda libraries, and lines 40-54 show the configuration, dependency injection, and checkpoint restore (CRAC) libraries used. Lastly, lines 20-29 show the two libraries from the ConnectedCar.Core repository, for the code we covered in the previous tutorial.
Writing Event Handling Methods
Lambdas can act as handlers for a variety of different AWS event triggers, and each type of event trigger requires a specific Lambda method signature. Most of the Lambdas in the sample code are triggered by API Gateway proxy integration events. The CreateDealerFunction class is a good example, as shown below. This is the event handler for our familiar “/admin/dealers” (POST) endpoint:
You can see in this code that the first input parameter is an APIGatewayProxyRequest and the output is an APIGatewayProxyResponse. This is the method signature to use for Lambdas that handle events for an API Gateway proxy integration. This example responds to an HTTP POST method and as a result it creates an item in DynamoDB. The response includes an HTTP 201 status code as well as an HTTP header value that includes the resource path at which the newly created entity can be referenced. This is the REST convention for POST actions.
GET actions return serialized JSON in the body of the request, as you can see in the GetDealersFunction class, for example:
Another thing to note is that the class name for the event handler must correspond to that specified in the Lambda resource in the CloudFormation template. Line 80 in the template below shows the Handler property for the CreateDealer Lambda that corresponds to the fully-qualified name of the class shown above:
Using Functional Interfaces for Error-Handling & Logging
If you look again at the code for the CreateDealerFunction class, you’ll see that we’re wrapping our event handling logic in a code block, which is passed as a functional interface to the process method, shown below on line 26:
The Lambda classes in the Java sample code use this functional interface pattern as a way to factor out exception handling and logging from the event handler methods. Here’s the implementation for the process method in the BaseRequestFunction class, in which you can see that the first input parameter is the ProcessFunc code block that is constructed by all the calling Lambdas:
Writing Convenience Methods for Serialization
To keep the event handling code for the Lambdas clean, we’ve added these two convenience methods that deserialize request bodies and serialize responses to the BaseRequestFunction class:
Writing Convenience Methods for Parsing Headers & Parameters
Values for HTTP headers and HTTP path and query parameters are all accessed through dictionaries in the APIGatewayProxyRequest. Here’s three convenience methods in the sample code that parse and validate these values:
Here’s another convenience method example that parses a query parameter and converts it to a StateCodeEnum value: