Call APIs from Step Functions using SAM
Learn what's needed to trigger the HTTP endpoint task state from a Step Function to be able to eliminate the Lambda Functions you have to call APIs
Benoit Boure wrote an article last week on Calling External Endpoints With Step Functions and the CDK, but if you know me I love SAM and wanted to show the same setup but instead of using CDK we will be using SAM.
I will not go into the details of how it works since Benoit did a great job of explaining that in the post mentioned above.
We’ll be using the OpenWeather API to get the temperature of a place and check if we need to wear a warm jacket, light jacket or no jacket. Below is the state machine workflow diagram that we will be executing.
Link to complete example on GitHub
Steps to follow
1. Create EventBridge Connection
The HTTP task uses an EventBridge Connection to authenticate the request. For the OpenWeather API we need to provide the API Key as a query parameter and not as an Authorization header as you would typically do on other APIs. To accomplish this we add the InvocationHttParameters object where we add the query string parameter to the request with the name appid.
OpenWeatherConnection:
Type: AWS::Events::Connection
Properties:
Name: 'openweather-connection'
AuthorizationType: API_KEY
AuthParameters:
ApiKeyAuthParameters:
ApiKeyName: Authorization
ApiKeyValue: !Ref OpenWeatherAPIKey
InvocationHttpParameters:
QueryStringParameters:
- IsValueSecret: true
Key: appid
Value: !Ref OpenWeatherAPIKey
2. Create Step Function Execution Policy
There are several permissions needed to execute an endpoint using the HTTP task.
- It needs access to the secret that the EventBridge Connection creates in Secrets Manager.
- Permission to retrieve the connection credentials from the EventBridge Connection.
- Permission to execute the InvokeHTTPEndpoint. In this case the resource needs to be the ARN of the state machine that is executing it. To avoid a cyclical dependency in SAM we are parsing the ARN ourselves. I’m adding a wildcard at the end to account for the unique identifier that AWS adds to the end of generated resource names. We are also restricting the HTTP Invocation to only allow a GET to the OpenWeather API.
Policies:
- Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- secretsmanager:DescribeSecret
- secretsmanager:GetSecretValue
Resource: !GetAtt OpenWeatherConnection.SecretArn
- Effect: Allow
Action:
- events:RetrieveConnectionCredentials
Resource: !GetAtt OpenWeatherConnection.Arn
- Effect: Allow
Action:
- states:InvokeHTTPEndpoint
Resource: !Sub arn:aws:states:${AWS::Region}:${AWS::AccountId}:stateMachine:ShouldIWearAJacketStateMachine*
Condition:
StringEquals:
states:HTTPMethod: GET
StringLike:
states:HTTPEndpoint: !Ref OpenWeatherBaseUrl
3. Calling endpoint from the Step Function
With all that in place we can now add the step to our state machine as shown below.
We are specifying the HTTP method as GET, the connection ARN to our EventBridge Connection as the authentication, OpenWeather base URL and we are appending query parameters to get the temperature of the location and the units we want.
"Get Temperature": {
"Type": "Task",
"Resource": "arn:aws:states:::http:invoke",
"Parameters": {
"Method": "GET",
"Authentication": {
"ConnectionArn": "${OpenWeatherConnectionArn}"
},
"ApiEndpoint": "${OpenWeatherBaseUrl}",
"QueryParameters": {
"lat.$": "$.latitude",
"lon.$": "$.longitude",
"units": "imperial"
}
},
"ResultSelector": {
"temperature.$": "$.ResponseBody.main.temp"
}
}
Wrap Up
As you can see it is not that complicated to replace any Lambda Functions you have to call third party endpoints. The permissions can get a little bit complicated but once you understand them you can repeat them for other requests you need to do.