Tutorial
This comprehensive tutorial guides you through creating HTTP-based workflows in Elsa, covering all aspects of HTTP endpoint development from basic concepts to advanced patterns.
Overview
In this tutorial, you will learn how to:
Create HTTP endpoints that respond to GET, POST, PUT, and DELETE requests
Handle query parameters, headers, and request bodies
Parse and validate incoming data
Return appropriate HTTP responses with proper status codes
Implement error handling strategies
Test and debug HTTP workflows
By the end of this tutorial, you'll have a complete understanding of building production-ready HTTP workflows for RESTful API development.
Prerequisites
Before you start, ensure you have:
An Elsa Server project up and running
Elsa Studio installed and connected to your Elsa Server
Basic understanding of HTTP methods and REST principles
A tool for testing HTTP endpoints (Postman, curl, or similar)
Tutorial Scenario
We'll build a simple Task Management API with the following endpoints:
GET /workflows/tasks- List all tasks (with query parameters for filtering)GET /workflows/tasks/{id}- Get a specific task by IDPOST /workflows/tasks- Create a new taskPUT /workflows/tasks/{id}- Update an existing taskDELETE /workflows/tasks/{id}- Delete a task
This scenario will demonstrate real-world patterns you'll use when building HTTP workflows.
Part 1: Creating a GET Endpoint with Query Parameters
Let's start by creating a workflow that lists tasks with optional filtering via query parameters.
Test the Workflow
Publish the workflow
Test with different query parameters:
GET https://localhost:5001/workflows/tasks- Returns all tasksGET https://localhost:5001/workflows/tasks?status=active- Returns only active tasksGET https://localhost:5001/workflows/tasks?status=completed- Returns completed tasks
Expected Response
When you make a request to https://localhost:5001/workflows/tasks?status=active, you should receive a JSON response containing only the active tasks:
Part 2: Creating a GET Endpoint with Route Parameters
Now let's create a workflow that retrieves a specific task by ID using route parameters.
Add Conditional Response
Add a Decision activity to check if the task was found:
Condition
Variables.Task != null
C#
Connect two Write HTTP Response activities to the Decision outcomes:
For "True" outcome (Task Found):
Status Code
OK
Default
Content
Variables.Task
JavaScript
Content Type
application/json
Default
For "False" outcome (Task Not Found):
Status Code
NotFound
Default
Content
{"error": "Task not found", "taskId": "{{Variables.TaskId}}"}
Liquid
Content Type
application/json
Default
Part 3: Creating a POST Endpoint for Creating Resources
Let's create a workflow that handles POST requests to create new tasks.
Create Task (Valid Input)
For the "True" outcome, add a Set Variable activity:
Variable
NewTask
Default
Value
See code below
C#
C# Expression:
Then add a Write HTTP Response activity:
Status Code
Created
Default
Content
Variables.NewTask
JavaScript
Content Type
application/json
Default
Add a custom header:
Name:
LocationValue:
/workflows/tasks/{{Variables.NewTask.Id}}(Liquid)
Part 4: Creating a PUT Endpoint for Updates
Let's create a workflow that handles PUT requests to update existing tasks.
Update Task (If Found)
For the "True" outcome, add a Set Variable activity:
Variable
UpdatedTask
Default
Value
See code below
C#
C# Expression:
Then add a Write HTTP Response activity:
Status Code
OK
Default
Content
Variables.UpdatedTask
JavaScript
Content Type
application/json
Default
Part 5: Creating a DELETE Endpoint
Let's complete our CRUD operations with a DELETE endpoint.
Part 6: Working with Headers
Learn how to read and set HTTP headers in your workflows.
Reading Request Headers
To access request headers, use the HTTP Endpoint activity's Headers output:
Extract Header Values
Add Set Variable activities to extract specific headers:
For Authorization Header:
Variable
AuthToken
Default
Value
{{ Variables.Headers.Authorization ?? "No token provided" }}
Liquid
For User-Agent Header:
Variable
UserAgent
Default
Value
{{ Variables.Headers["User-Agent"] ?? "Unknown" }}
Liquid
Setting Response Headers
To set custom response headers, configure the Write HTTP Response activity:
Add custom headers:
X-Request-Id
{{guid()}}
Liquid
X-Response-Time
`{{now
date: "%Y-%m-%d %H:%M:%S"}}`
Cache-Control
no-cache, no-store, must-revalidate
Default
X-Api-Version
v3
Default
Part 7: Error Handling Strategies
Implement robust error handling to make your workflows production-ready.
Pattern 1: Try-Catch with Fault Activity
Create a workflow that handles exceptions gracefully:
Pattern 2: Validation and Early Returns
Validate input early and return appropriate error responses:
Pattern 3: Custom Error Status Codes
Use appropriate HTTP status codes for different error scenarios:
400 Bad Request
Invalid input data
Missing required fields, invalid format
401 Unauthorized
Missing or invalid authentication
No auth token provided
403 Forbidden
Insufficient permissions
User not allowed to perform action
404 Not Found
Resource doesn't exist
Task ID not found
409 Conflict
Resource state conflict
Task already exists
422 Unprocessable Entity
Semantic validation errors
Valid format but business rule violation
429 Too Many Requests
Rate limit exceeded
Too many API calls
500 Internal Server Error
Unexpected server errors
Database connection failure
503 Service Unavailable
Temporary service issues
Downstream service unavailable
Part 8: Advanced Request/Response Patterns
Content Negotiation
Handle different content types based on request headers:
CORS Headers
Enable Cross-Origin Resource Sharing (CORS) for browser-based clients:
Access-Control-Allow-Origin
https://yourdomain.com
Access-Control-Allow-Methods
GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers
Content-Type, Authorization
Access-Control-Max-Age
3600
CORS Security
Never use
*forAccess-Control-Allow-Originin production, especially with credentialsAlways specify the exact allowed origin domain(s)
For multiple domains, implement logic to validate and return the requesting origin
Consider security implications before enabling CORS
Pagination
Implement pagination for list endpoints:
Rate Limiting
Track and limit request rates per client:
Rate Limiting Considerations
Rate limiting in production requires careful implementation:
Infrastructure:
Use API Gateway features (Azure API Management, AWS API Gateway, Kong)
Implement with distributed cache (Redis, Memcached)
Use ASP.NET Core Rate Limiting middleware
Leverage CDN/WAF services (Cloudflare, etc.)
Client Identification:
⚠️ Avoid IP-based limiting alone: IPs can be shared (NAT, proxies, mobile networks)
✅ Prefer authenticated identifiers: User IDs, API keys, OAuth tokens
✅ Validate proxy headers: Only trust X-Forwarded-For from known proxies
✅ Combine methods: Use both authentication and IP for better accuracy
The example below demonstrates the concept but requires proper implementation.
Part 9: Testing Your HTTP Workflows
Using Postman
Create a Collection: Organize all your workflow endpoints
Set Environment Variables: Configure base URL, auth tokens
Write Tests: Add test scripts to validate responses
Example Postman test script:
Using cURL
Test your endpoints from the command line:
Using HTTP Files (REST Client)
Create a .http file for testing (replace {{baseUrl}} with your server URL):
Automated Testing with xUnit
Create integration tests for your workflows:
Part 10: Debugging and Troubleshooting
Using Elsa Studio for Debugging
Navigate to Workflow Instances: View all executions of your workflow
Inspect Activity Execution: See inputs/outputs for each activity
Check Journal Entries: View the execution timeline
Review Variables: Inspect variable values at each step
Common Issues and Solutions
Issue: 404 Not Found
Problem: Workflow endpoint not responding
Solutions:
Verify the workflow is Published
Check that "Trigger Workflow" is enabled on HTTP Endpoint
Ensure the path doesn't conflict with other routes
Verify Elsa Server is running and configured correctly
Issue: Request Body is Null
Problem: Cannot read POST/PUT request body
Solutions:
Set
Content-Type: application/jsonheaderEnsure JSON is valid
Use HTTP Endpoint's "Parsed Content" output
Check that body isn't consumed elsewhere in the pipeline
Issue: Headers Not Available
Problem: Cannot read request headers
Solutions:
Use HTTP Endpoint's "Headers" output variable
Check header names are case-insensitive
Verify headers are sent with the request
Issue: CORS Errors
Problem: Browser blocks requests from different origin
Solutions:
Add CORS headers to Write HTTP Response activity
Handle OPTIONS preflight requests
Configure Elsa Server CORS policy
Example CORS workflow configuration:
HTTP Endpoint Activity:
Write HTTP Response Activity:
Enabling Detailed Logging
Configure logging in your Elsa Server's appsettings.json:
Best Practices
1. Use Consistent Response Formats
Always return JSON in a consistent structure:
2. Validate All Inputs
Never trust client input. Always validate:
Required fields are present
Data types are correct
Values are within expected ranges
Formats match requirements (email, URL, etc.)
3. Use Appropriate HTTP Methods
GET: Retrieve resources (idempotent, no side effects)
POST: Create resources (non-idempotent)
PUT: Update entire resources (idempotent)
PATCH: Partial updates (may be idempotent)
DELETE: Remove resources (idempotent)
4. Return Proper Status Codes
Use semantic HTTP status codes to communicate results clearly.
5. Implement Security
Validate authentication tokens
Implement authorization checks
Sanitize inputs to prevent injection attacks
Use HTTPS in production
Rate limit requests
6. Version Your APIs
Include version in the path:
/workflows/v1/tasks/workflows/v2/tasks
Or use headers:
Accept: application/vnd.myapi.v1+json
7. Document Your Endpoints
Provide clear documentation for each endpoint:
Purpose and description
Request format and parameters
Response format and status codes
Example requests and responses
Error scenarios
8. Handle Timeouts
For long-running operations:
Return 202 Accepted immediately
Process asynchronously
Provide status endpoint to check progress
9. Use Workflow Variables Wisely
Name variables descriptively
Choose appropriate storage (Workflow Instance vs Activity)
Clean up large variables when no longer needed
10. Monitor and Log
Log important events
Track performance metrics
Monitor error rates
Set up alerts for critical issues
Real-World Example: Complete Task API
Here's a complete workflow combining all the patterns we've learned:
Workflow: Create Task with Full Validation
This workflow demonstrates:
Request body parsing
Comprehensive validation
Authentication check
Error handling
Proper response codes
Header management
Variables:
Headers(ObjectDictionary)RequestBody(Object)AuthToken(string)ValidationResult(Object)NewTask(Object)IsAuthenticated(bool)
Activities Flow:
HTTP Endpoint (POST
/workflows/tasks)Outputs: Headers, RequestBody
Extract Auth Token
AuthToken = Headers.Authorization
Validate Authentication
Check if token is valid
Branch: Authenticated / Unauthorized
Validate Request Body (if authenticated)
Check required fields
Validate formats
Check business rules
Decision: Valid Input?
True: Create task
False: Return validation errors
Create Task (if valid)
Generate ID
Set timestamps
Prepare response
Return Response
201 Created: With Location header
400 Bad Request: With validation errors
401 Unauthorized: If auth fails
Summary
Congratulations! You've completed the comprehensive HTTP Workflows tutorial. You now know how to:
✅ Create RESTful endpoints for all HTTP methods (GET, POST, PUT, DELETE)
✅ Handle route parameters and query strings
✅ Parse and validate request bodies
✅ Read and set HTTP headers
✅ Implement proper error handling
✅ Return appropriate HTTP status codes
✅ Test workflows using various tools
✅ Debug and troubleshoot issues
✅ Apply best practices for production-ready APIs
Next Steps
Now that you've mastered HTTP workflows, explore these advanced topics:
External Application Interaction: Integrate with external services
Custom Activities: Create reusable workflow components
Authentication: Secure your workflows
Testing & Debugging: Advanced debugging techniques
Distributed Hosting: Scale your workflows
Resources
Feedback
Found an issue or have suggestions for improving this tutorial? Please open an issue on our GitHub repository.
Happy workflow building! 🚀
Last updated