HTTP Workflows
In this guide, we'll take a look at a workflow that can receive HTTP requests, send HTTP requests and write output to the HTTP response object. Our workflow will handle inbound HTTP requests, invoke a backend API using an HTTP call, and write back the response to the client. As a result, we will learn how to use the following HTTP activities:
HttpEndpoint
SendHttpRequest
WriteHttpResponse
SetVariable
Before you start
For this guide, we will need the following:
An Elsa Server project
An Elsa Studio instance
docker pull elsaworkflows/elsa-studio-v3:latest docker run -t -i -e ASPNETCORE_ENVIRONMENT='Development' -e HTTP_PORTS=8080 -e ELSASERVER__URL=https://localhost:5001/elsa/api -p 14000:8080 elsaworkflows/elsa-studio-v3:latest
Please return here when you are ready.
Workflow Overview
We will define a new workflow called GetUser
. The purpose of the workflow is to handle inbound HTTP requests by fetching a user by a given user ID from a backend API and writing them back to the client in JSON format.
For the backend API, we will use reqres.in, which returns fake data using real HTTP responses.
Our workflow will parse the inbound HTTP request by getting the desired user ID from a route parameter and use that value to make an API call to reqres.
The following is an example of such an HTTP request that you can try right now from your browser: https://reqres.in/api/users/2
The response should look similar to this:
Our workflow will essentially be a proxy sitting in front of the reqres API and return a portion of the response.
Design Workflow
Follow these steps to create the workflow using Elsa Studio
Start Elsa Studio from your browser.
Create a new workflow called Get User
Add the following activities to the design surface:
HTTP Endpoint
Set Variable
HTTP Request (flow)
HTTP Response (for 200 OK)
HTTP Response (for 404 Not Found)
Create the following variables:
Name
Type
Storage
RouteData
ObjectDictionary
Workflow
UserId
string
Workflow
User
Object
Workflow
Configure the activities as follows:
HTTP Endpoint
Property
Value
Syntax
Path
users/{userid}
Default
Supported Methods
GET
Default
Property
Value
Route Data
RouteData
Property
Value
Trigger workflow
Checked
Set Variable
Property
Value
Syntax
Variable
UserId
Default
Value
return Variables.RouteData["userid"];
C#
HTTP Request (flow)
Property
Value
Syntax
Expected Status Codes
200, 404
Default
Url
`return $"https://reqres.in/api/users/{Variables.UserId}";`
C#
Method
GET
Default
Property
Value
Parsed Content
User
HTTP Response (200)
Property
Value
Syntax
Status Code
OK
Default
Content
getUser().data
JavaScript
HTTP Response (404)
Property
Value
Syntax
Status Code
NotFound
Default
Content
User not found
Default
Connect each activity to the next. Ensure that you connect the
200
and404
outcomes of the HTTP Request (flow) activity to the appropriate HTTP Response activity.Publish the workflow.
The final result should look like this:
Create C# Workflow
Follow these steps to create the workflow from code
Create GetUser.cs and add the following code:
Workflows/GetUser.cs
using System.Dynamic; using System.Net; using Elsa.Http; using Elsa.Http.Models; using Elsa.Workflows; using Elsa.Workflows.Activities; using Elsa.Workflows.Contracts; namespace WorkflowApp.Web.Workflows; public class GetUser : WorkflowBase { protected override void Build(IWorkflowBuilder builder) { var routeDataVariable = builder.WithVariable<IDictionary<string, object>>(); var userIdVariable = builder.WithVariable<string>(); var userVariable = builder.WithVariable<ExpandoObject>(); builder.Root = new Sequence { Activities = { new HttpEndpoint { Path = new("users/{userid}"), SupportedMethods = new(new[] { HttpMethods.Get }), CanStartWorkflow = true, RouteData = new(routeDataVariable) }, new SetVariable { Variable = userIdVariable, Value = new(context => { var routeData = routeDataVariable.Get(context)!; var userId = routeData["userid"].ToString(); return userId; }) }, new SendHttpRequest { Url = new(context => { var userId = userIdVariable.Get(context); return new Uri($"https://reqres.in/api/users/{userId}"); }), Method = new(HttpMethods.Get), ParsedContent = new(userVariable), ExpectedStatusCodes = { new HttpStatusCodeCase { StatusCode = StatusCodes.Status200OK, Activity = new WriteHttpResponse { Content = new(context => { var user = (dynamic)userVariable.Get(context)!; return user.data; }), StatusCode = new(HttpStatusCode.OK) } }, new HttpStatusCodeCase { StatusCode = StatusCodes.Status404NotFound, Activity = new WriteHttpResponse { Content = new("User not found"), StatusCode = new(HttpStatusCode.NotFound) } } } } } }; } }
Let's go over this workflow section by section.
Workflow Variables
Here, we defined 3 workflow variables.
The routeDataVariable
variable is used to capture route data output from the HTTP endpoint activity. This variable is a dictionary.
The userIdVariable
variable is used to store the user ID value that we get from the routeDataVariable
dictionary.
The userVariable
variable is used to capture the parsed response from the reqres API call. Since reqres returns JSON content and the capturing variable is of type ExpandoObject
, the SendHttpRequest
activity will parse the received JSON response into an ExpandoObject
.
HttpEndpoint Activity
Here we see the HttpEndpoint
activity being defined and configured to be a trigger by setting CanStartWorkflow
to true
.
We set its Path
property to respond to users/{userid}
. Notice that we are using a route parameter using the name userid
. This is the key we will use to grab the provided user ID from the inbound URL path.
To capture the route data, we assign the routeDataVariable
variable to the RouteData
output of the activity.
SetVariable Activity
Here we see the SetVariable
activity defined and configured to set the userIdVariable
variable to the dictionary entry with key "userid"
.
We set its Variable
property to reference the userIdVariable
variable and its Value
property to a callback that returns the received user ID from the route data dictionary.
SendHttpRequest Activity
The SendHttpRequest
activity is configured to send an HTTP request to the reqres API endpoint.
We set its Url
property to a URL that includes the received user ID.
To capture the response, we assign its ParsedContent
output to the userVariable
variable.
Since the caller of the workflow might provide user IDs that don't correspond to a user record in the reqres backend, we configure the activity to handle two possible HTTP status codes:
200 OK
404 Not Found
For each of these possible status codes, we assign an appropriate WriteHttpResponse
activity.
for the 200 case, the WriteHttpResponse activity access the data
field of the user response object received from reqres:
Run Workflow
Since the workflow uses the HTTP Endpoint activity, it will trigger when we send an HTTP request to the /api/workflows/users/{userId} path.
Try it out by navigating to http://localhost:13000/api/workflows/users/2.
Since the workflow uses the HttpEndpoint
activity, it will trigger when we send an HTTP request to the /workflows/users/{userId} path.
Try it out by navigating to https://localhost:5001/workflows/users/2.
The response should look similar to this:
Summary
In this guide, we learned how to define a workflow from code.
In this guide, we learned how to design a workflow using Elsa Studio.
We leveraged the HttpEndpoint
activity and used is as a trigger to start the workflow.
The workflow is able to read route parameters and store it in a variable, which we then used as an input to send an API call to the reqres API that in turn returns the requested user.
We have also seen how to handle various responses from reqres: 200 OK and 404 Not Found
The source code for this guide can be found here.
The workflow created in this guide can be found here.