Use StepFunctions to simplify your serverless applications
Tags: aws, stepfunctions, serverless, simplify
Published: 2023-06-14 08:41:35

[AWS StepFunctions](https://docs.aws.amazon.com/step-functions/latest/dg/welcome.html) is a great orchestrating tool for your serverless applications. When you write lambda functions that only contain logic to perform a single task they are easier to test. Especially when there is no orchestration logic within your function. 

The orchestration is then performed by StepFunctions by defining a state machine. This state machine is nothing more than a JSON definition based on [Amazon State Language](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-amazon-states-language.html). It describes the flow between the functions for your specific use-case.

## Lets use an example

Lets say one of the input parameters is an object location on S3\. We will feed this to your state machine. A lambda function can then be used to read this object and perform some business logic on this data.

Or you can use the [AWS SDK Service](https://docs.aws.amazon.com/step-functions/latest/dg/supported-services-awssdk.html#use-awssdk-integ) integration. By using the service integration you can again simplify your business logic. Instead of needing to read an object from S3 and do some actions. You only need to do the action on the data that you receive. This will remove the need of mocking S3 GetObject calls in your unit tests. Next to that you do not have to pay for the time it takes to read the data from S3\. This is done outside of the scope of the lambda function, and therefor you do not have to pay for it.

## Sounds great, do you have an example for me?

Lets assume the following payload it given:

```json
{
  "Bucket": "my-bucket-name",
  "ObjectKey": "my-path/to-my-file.json"
}
```

And we have a the following task in our state machine:

```json
{
  "Read From S3": {
    "Type": "Task",
    "Resource": "arn:aws:states:::aws-sdk:s3:getObject",
    "Parameters": {
      "Bucket": "$.Bucket",
      "Key": "$.ObjectKey"
    },
    "OutputPath": "$.Body",
    "ResultPath": "$.ObjectBody",
    "Next": "My Lambda"
  }
}
```

This will perform a s3:getObject action on s3://my-bucket-name/my-path/to-my-file.json. The action returns the content of the file in the Body parameter. And we will place this content in the  ObjectBody parameter of the event. So the event will now look like:

```json
{
  "Bucket": "my-bucket-name",
  "ObjectKey": "my-path/to-my-file.json",
  "ObjectBody": "{\"Foo\": \"Bar\"}",
  "TransformedBody": "{\"Foo\": \"Bar\"}"
}
```

We can now invoke a lambda function to do something with this payload:

```json
{
  "My Lambda": {
    "Type": "Task",
    "Resource": "arn:aws:states:::lambda:invoke",
    "InputPath": "$.ObjectBody",
    "Parameters": {
      "FunctionName": "arn:aws:lambda:eu-west-1:123456789012:function:my-function"
    },
    "ResultPath": "$.TransformedBody",
    "Next": "Write to S3"
  }
}
```

Assume that in the lambda function we enriched the object with an extra parameter. So the event will look like this now:

```json
{
  "Bucket": "my-bucket-name",
  "ObjectKey": "my-path/to-my-file.json",
  "ObjectBody": "{\"Foo\": \"Bar\"}",
  "TransformedBody": "{\"Foo\": \"Bar\", \"Bar\": \"Foo\"}"
}
```

We can now store the transformed event on S3:

```json
{
  "Write to S3": {
    "Type": "Task",
    "Resource": "arn:aws:states:::aws-sdk:s3:putObject",
    "Parameters": {
      "Bucket": "$.Bucket",
      "Key": "$.ObjectKey",
      "Body.$": "$.TransformedBody"
    }
  },
  "End": true
}
```

And done, the existing object is updated with the extra parameter in the json structure.

## Conclusion 

You can use StepFunctions to remove the following from your lambda functions:

*   Orchestration logic
*   AWS API Calls

This enables you to focus on the task at hand, and simplifies the code that you need to write and maintain.

Photo by [Baskin Creative Studios](https://www.pexels.com/photo/time-lapse-photography-of-lake-1480807/)