Testing HTTP Triggers in Simulation
During development, you can test your HTTP trigger workflows locally using the cre workflow simulate command. The simulator allows you to provide test payloads without setting up authorization keys or JWT authentication.
This guide focuses specifically on HTTP trigger simulation with detailed examples and scenarios. For a general overview of workflow simulation covering all trigger types, see Simulating Workflows.
Prerequisites
Before running a simulation:
- CRE CLI installed: You need the CRE CLI to run simulations. See CLI Installation if you haven't installed it yet.
- CRE account & authentication: You must have a CRE account and be logged in with the CLI. See Create your account and Log in with the CLI for instructions.
- HTTP trigger configured: Your workflow must have an HTTP trigger handler registered. See Configuration & Handler for setup instructions.
Basic simulation
To simulate a workflow with an HTTP trigger, run the simulate command from your project root:
cre workflow simulate <workflow-folder> --target <target-name>
Example:
cre workflow simulate my-http-workflow --target staging-settings
The simulator will detect your HTTP trigger and prompt you to select it from available triggers.
Providing input data
You have three ways to provide JSON input to your HTTP trigger during simulation:
1. Interactive mode (default)
When you run the simulation without input flags, the CLI prompts you to enter JSON data:
$ cre workflow simulate my-http-workflow --target staging-settings
# Select the HTTP trigger when prompted
? Select a trigger to simulate: HTTP Trigger
# Enter your JSON input:
? Enter JSON input for the HTTP trigger:
{"userId": "123", "action": "purchase", "amount": 50}
The simulator converts your JSON into a payload and passes it to your callback function.
2. Inline JSON string
For non-interactive execution (useful for CI/CD or scripting), pass JSON directly using the --http-payload flag along with --non-interactive and --trigger-index:
cre workflow simulate my-http-workflow --non-interactive --trigger-index 0 --http-payload '{"userId":"123","action":"purchase","amount":50}' --target staging-settings
3. Input from file
For complex payloads or reusable test data, store your JSON in a file and reference it in non-interactive mode.
Option 1: File in workflow folder
Create the payload file in your workflow directory:
my-http-workflow/test-payload.json:
{
"userId": "123",
"action": "purchase",
"amount": 50,
"metadata": {
"timestamp": "2025-11-10T10:00:00Z",
"source": "mobile-app"
}
}
Simulate:
cre workflow simulate my-http-workflow --non-interactive --trigger-index 0 --http-payload test-payload.json --target staging-settings
Option 2: File at project root
Create the payload file at your project root. Simulate (using ../ to reference the parent directory):
cre workflow simulate my-http-workflow --non-interactive --trigger-index 0 --http-payload ../test-payload.json --target staging-settings
Example workflow simulation
Let's simulate a complete workflow that processes HTTP requests.
Setup your config file:
For this example, create a config.staging.json file with:
{
"minimumAmount": 10
}
This configuration sets the minimum purchase amount to 10, which we'll test with different scenarios.
Workflow code:
| 1 | //go:build wasip1 |
| 2 | |
| 3 | package main |
| 4 | |
| 5 | import ( |
| 6 | "encoding/json" |
| 7 | "fmt" |
| 8 | "log/slog" |
| 9 | |
| 10 | "github.com/smartcontractkit/cre-sdk-go/capabilities/networking/http" |
| 11 | "github.com/smartcontractkit/cre-sdk-go/cre" |
| 12 | "github.com/smartcontractkit/cre-sdk-go/cre/wasm" |
| 13 | ) |
| 14 | |
| 15 | type Config struct { |
| 16 | MinimumAmount int `json:"minimumAmount"` |
| 17 | } |
| 18 | |
| 19 | type RequestData struct { |
| 20 | UserID string `json:"userId"` |
| 21 | Action string `json:"action"` |
| 22 | Amount *int `json:"amount"` // Pointer to detect missing field |
| 23 | } |
| 24 | |
| 25 | func onHttpTrigger(config *Config, runtime cre.Runtime, payload *http.Payload) (string, error) { |
| 26 | var data RequestData |
| 27 | if err := json.Unmarshal(payload.Input, &data); err != nil { |
| 28 | return "", fmt.Errorf("failed to parse input: %w", err) |
| 29 | } |
| 30 | |
| 31 | // Validate required fields |
| 32 | if data.UserID == "" || data.Action == "" || data.Amount == nil { |
| 33 | runtime.Logger().Info("Missing required fields") |
| 34 | return "Error: Missing required fields (userId, action, amount)", nil |
| 35 | } |
| 36 | |
| 37 | runtime.Logger().Info("Processing request", "action", data.Action, "userId", data.UserID) |
| 38 | |
| 39 | if *data.Amount < config.MinimumAmount { |
| 40 | runtime.Logger().Info("Amount below minimum", "amount", *data.Amount, "minimum", config.MinimumAmount) |
| 41 | return "Amount too low", nil |
| 42 | } |
| 43 | |
| 44 | runtime.Logger().Info("Processing amount", "amount", *data.Amount) |
| 45 | return fmt.Sprintf("Successfully processed %s", data.Action), nil |
| 46 | } |
| 47 | |
| 48 | func InitWorkflow(config *Config, logger *slog.Logger, secretsProvider cre.SecretsProvider) (cre.Workflow[*Config], error) { |
| 49 | httpTrigger := http.Trigger(&http.Config{}) // Empty config OK for simulation |
| 50 | |
| 51 | return cre.Workflow[*Config]{ |
| 52 | cre.Handler(httpTrigger, onHttpTrigger), |
| 53 | }, nil |
| 54 | } |
| 55 | |
| 56 | func main() { |
| 57 | wasm.NewRunner(cre.ParseJSON[Config]).Run(InitWorkflow) |
| 58 | } |
| 59 | |
Run the simulation:
cre workflow simulate my-http-workflow --non-interactive --trigger-index 0 --http-payload '{"userId":"user_123","action":"purchase","amount":100}' --target staging-settings
Expected output:
Workflow compiled
2025-11-10T11:28:25Z [SIMULATION] Simulator Initialized
2025-11-10T11:28:25Z [SIMULATION] Running trigger [email protected]
2025-11-10T11:28:25Z [USER LOG] Processing purchase for user user_123
2025-11-10T11:28:25Z [USER LOG] Processing amount: 100
Workflow Simulation Result:
"Successfully processed purchase"
2025-11-10T11:28:25Z [SIMULATION] Execution finished signal received
2025-11-10T11:28:25Z [SIMULATION] Skipping WorkflowEngineV2
Testing different scenarios
Use simulation to test various input scenarios:
Valid request
cre workflow simulate my-http-workflow --non-interactive --trigger-index 0 --http-payload '{"userId":"123","action":"purchase","amount":100}' --target staging-settings
Invalid input (below minimum)
cre workflow simulate my-http-workflow --non-interactive --trigger-index 0 --http-payload '{"userId":"123","action":"purchase","amount":5}' --target staging-settings
Expected output:
Workflow compiled
2025-11-10T11:34:38Z [SIMULATION] Simulator Initialized
2025-11-10T11:34:38Z [SIMULATION] Running trigger [email protected]
2025-11-10T11:34:38Z [USER LOG] Processing purchase for user 123
2025-11-10T11:34:38Z [USER LOG] Amount 5 below minimum 10
Workflow Simulation Result:
"Amount too low"
2025-11-10T11:34:38Z [SIMULATION] Execution finished signal received
2025-11-10T11:34:38Z [SIMULATION] Skipping WorkflowEngineV2
Missing fields
cre workflow simulate my-http-workflow --non-interactive --trigger-index 0 --http-payload '{"userId":"123","action":"purchase"}' --target staging-settings
Expected output:
Workflow compiled
2025-11-10T11:37:57Z [SIMULATION] Simulator Initialized
2025-11-10T11:37:57Z [SIMULATION] Running trigger [email protected]
2025-11-10T11:37:57Z [USER LOG] Missing required fields
Workflow Simulation Result:
"Error: Missing required fields (userId, action, amount)"
2025-11-10T11:37:57Z [SIMULATION] Execution finished signal received
2025-11-10T11:37:57Z [SIMULATION] Skipping WorkflowEngineV2
This helps you verify error handling and edge cases before deployment.
Simulation vs production behavior
| Aspect | Simulation | Production |
|---|---|---|
| Authorization | Not required (empty config allowed) | Required (authorizedKeys must be set) |
| Signature verification | Skipped | Strictly enforced |
| Execution | Immediate, synchronous | Asynchronous via DON |
| Logs | Printed to terminal | Available in CRE UI |
Next steps
Once you've tested your workflow locally:
- Add authorization: Configure
authorizedKeysin your HTTP trigger for production - Deploy your workflow: Use
cre workflow deployto register it - Trigger it in production: Follow the Triggering Deployed Workflows guide