Improved AWS Lambda JSON Serialization in C#

Maxime Beaudry
3 min readOct 25, 2019

--

AWS lambda functions are the foundation of serverless computing on AWS. They are useful to react to AWS events (SNS message published, file uploaded on S3, etc) but are also often used to just do some serverless computing. You invoke your lambda with some input, it computes something and returns the result. To be more precise, you invoke your lambda function with a JSON object and it will return another JSON object.

This article will first show you some of the limitations (or surprising behaviors) of the default .net AWS Lambda JSON serializer. It will then demonstrate how you can extend this serializer to have an improved JSON serializer.

Surprises with the default JSON serializer

As explained here in the “Serializing Lambda Functions” section, you can use the Amazon.Lambda.Serialization.Json nuget package to deserialize/serialize your lambda function inputs/outputs. This is based on the very popular JSON.NET library that you probably already use.

Let’s write a very simple lambda function that takes an object and returns an object:

As you can see, the function simply returns the input by modifying the message property and adding a responseTime property.

Let’s invoke the function with the following input:

{
"message": "Hello Lambda",
"volume": "High",
"requestTime": "2019-09-28T11:27:09.4268686Z"
}

And here’s the response (that was reformatted manually in multi-line format for easier reading):

{
"Message": "HELLO LAMBDA",
"Volume": 2,
"RequestTime": "2019-09-28T11:27:09.4268686Z",
"ResponseTime": "2019-09-28T08:43:15.8986554-04:00"
}

As you can see, there are a few surprises:

  • Enumerated types are serialized as integers: The volume was High in the request but it was 2 in the response. This is not very useful from the point of view of the caller. This is not the fault of the AWS serializer. It’s the default behavior of the JSON.NET serializer.
  • Response uses PascalCase: if you’re like me (and lots of programmers), you follow the Google guideline that says to format JSON documents using camelCase but you also follow the C# guideline that says to format class properties using PascalCase. Unfortunately, the default JSON.NET serializer preserves the casing of the C# properties in the resulting JSON document. So, if you follow the C# guideline, you will break the Google guideline with JSON.NET (by default). This is not a big deal for most people. But if you use theses JSON objects into an AWS step function, it can become a big deal. This is because the Amazon States Language is case sensitive. You therefore want the lambdas invoked by a step function to preserve the casing of the objects they return.
  • Timestamps in local format: a final, and less significant point, is that DateTime objects that are in Local format are not formatted in UTC (see the ResponseTime member). If you’re part of a team that has standardized on returning date-times in UTC format, this can be a problem.

As you can see, the default behavior of Amazon’s JsonSerializer is not ideal. In fact, it’s not really Amazon’s fault. It’s just the default behavior of JSON.NET.

How to fix it?

Luckily for us, there are extensibility options that can solve these issues. I did a first PR to add the possibility to set the serializer options and a second one to control the naming strategy. With these two improvements in place, it is possible to define your own JSON serializer with the desired options:

Note that you will need version 1.7.0 or higher of the Amazon.Lambda.Serialization.Json nuget package for this code to compile.

You can now use this serializer as the default serializer. To do so, replace the line:

[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]

By this one:

[assembly: LambdaSerializer(typeof(WellBehavedJsonSerializer))]

Once this is done, invoking the test function will return this:

{
"message": "HELLO LAMBDA",
"volume": "High",
"requestTime": "2019-09-28T11:27:09.4268686Z",
"responseTime": "2019-10-25T09:06:58.3326187Z"
}

So we now have a JSON object that:

  • uses camel case
  • serializes enums as strings
  • serializes DateTime in UTC

Conclusion

As you’ve seen, it’s easy to customize the behavior of the JSON serializer by:

  1. creating a class that derives from Amazon.Lambda.Serialization.Json.JsonSerializer
  2. customizing the serializer settings and naming strategy in the constructor
  3. changing the class used in the LambdaSerializerAttribute

With these tools in place, you are now able to go ahead and use the JSON formatting guidelines that your team has agreed on.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Maxime Beaudry
Maxime Beaudry

Written by Maxime Beaudry

Back end developer at LANDR Music

Responses (1)

Write a response