Welcome to the final lesson of this course on building serverless applications! So far, you have learned how to use AWS Lambda, API Gateway, and Step Functions to create and deploy serverless workflows. In this lesson, we will take your skills a step further by showing you how to use API Gateway to start Step Function executions directly — without needing a Lambda function in between.
This approach can make your applications faster and more cost-effective, since you avoid the extra step and cost of running Lambda just to start a workflow. You will learn how to use mapping templates to control the request and response, validate input, handle errors, and even route to different workflows — all using the Velocity Template Language (VTL).
By the end of this lesson, you will be able to build a robust API that starts Step Function executions with dynamic input and strong validation, all without writing any Lambda code.
Before we dive in, let’s quickly remind ourselves what mapping templates are and why they matter.
A mapping template in API Gateway is a way to transform the incoming request or outgoing response. It lets you change the shape of the data, add or remove fields, and even add logic — using a language called Velocity Template Language (VTL).
In previous lessons, you may have seen mapping templates used to format data for Lambda functions. In this lesson, we will use them to talk directly to Step Functions, letting us control exactly how the API request is turned into a Step Function execution.
When starting a Step Function execution, you often want each execution to have a unique name. This helps you track and manage each workflow run.
Let’s see how to do this using a request mapping template in API Gateway.
First, we use the $util.autoId() function in VTL to generate a random string. We can combine this with a prefix, like "order-", to create a unique execution name.
Here’s how you can set this up in your mapping template:
Explanation:
#set($inputRoot = $util.parseJson($input.body))parses the incoming JSON body so you can access its fields."name": "order-$util.autoId()"creates a unique execution name likeorder-abc123xyz."input": "$util.escapeJavaScript($input.body)"passes the original request body as input to the Step Function.
Example Output:
This ensures every execution has a unique name, which is important for tracking and debugging.
It’s important to make sure the incoming request has all the required fields before starting a workflow. For example, you might require a customerId in the request body.
You can use VTL’s #if directive to check for required fields and return an error if something is missing.
Here’s how you can add validation to your mapping template:
Explanation:
#if(!$inputRoot.customerId || $inputRoot.customerId == "")checks ifcustomerIdis missing or empty.- If it is, we set the response status to 400 and return an error message.
- If not, we proceed to start the Step Function execution as before.
Example Output (when customerId is missing):
This helps prevent invalid requests from starting workflows, saving resources and making your API more reliable.
When the Step Function execution starts, the response from AWS is not always user-friendly. You can use a response mapping template to transform the response and add helpful information.
For example, you might want to include:
- The execution ARN
- The execution name
- A timestamp for when the execution started
- A status field
Here’s how you can do this in your response mapping template:
Explanation:
$inputRoot.executionArnand$inputRoot.namecome from the Step Functions response.$util.time.nowISO8601()adds the current timestamp in a standard format."status": "RUNNING"gives a clear status for the client.
Example Output:
This makes your API responses easier to understand and use.
Sometimes, starting a Step Function execution can fail. For example, the state machine might not exist, or you might try to use a duplicate execution name.
You can handle these errors in your API by mapping them to appropriate HTTP status codes and messages.
Here’s how you can set up error responses in your API Gateway integration:
Explanation:
- The
defaultresponse handles successful executions. - The
4\d{2}pattern matches client errors (like validation failures) and returns a 400 status. - The
5\d{2}pattern matches server errors and returns a 500 status with an error message.
Example Output (for a duplicate execution name):
Example Output (for an internal error):
This makes your API more robust and user-friendly by providing clear error messages.
Sometimes, you want your API to start different workflows based on a parameter in the request. For example, you might have different workflows for orders, refunds, or inventory updates.
You can read a workflow_type parameter from the request body, validate it, and use it to customize the Step Function input and execution name.
Here’s how you can do this in your request mapping template:
Explanation:
- We set a default
workflowTypeto"order". - If the request includes a valid
workflow_type(like"refund"or"inventory"), we use that instead. - The execution name and input are customized based on the workflow type.
- We still validate that
customerIdis present.
Example Output (for a refund workflow):
In this lesson, you learned how to use API Gateway’s direct integration with Step Functions to build a flexible, robust API — without needing Lambda functions. You saw how to:
- Generate unique execution names using
VTL - Validate input and return helpful error messages
- Transform Step Functions responses to be more user-friendly
- Handle errors gracefully with custom status codes and messages
- Route requests dynamically based on workflow type
You have now reached the end of this course on building serverless applications. Congratulations on making it this far! You are now ready to put these concepts into practice with the hands-on exercises that follow. Great work, and keep building!
