DEV Community

Cover image for Route Step Functions Input with a Choice State and No Lambda
miruky
miruky

Posted on

Route Step Functions Input with a Choice State and No Lambda

Introduction

Hi, I'm miruky.

Not every workflow decision needs a Lambda function. An AWS Step Functions Choice state can inspect execution input and select a branch, while Pass states can return fixed results without calling another service.

This Console run routes gold, standard, and an unmatched trial tier. Four short synchronous Express runs prove the priority branch, normal branch, explicit default branch, and a corrected-input recovery without retaining execution history in Step Functions.

The Console's synchronous Express request expires after 60 seconds. This definition contains no Task or Wait state, and each observed result is captured from the immediate response. Express pricing is based on execution count, duration, and memory; check the current terms before running it.

1. Create a minimal execution role

This validation keeps the state machine and all four executions in us-east-1; IAM itself is global.

The English AWS Console shows United States (N. Virginia) before the workflow is created.

The English AWS Console header shows United States (N. Virginia). This fixes the Region for the state machine and every execution.

In IAM, choose Roles and Create role. Select Custom trust policy, then use this trust relationship:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "states.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Continue without adding a permissions policy, and name the role miruky-nlanmycdwgncgejj. The custom trust route matters in the current Console: choosing the prebuilt Step Functions use case attached AWSLambdaRole during this validation, which would grant permissions this flow-only workflow does not need.

The IAM role details page shows the generated role name.

The role details heading shows miruky-nlanmycdwgncgejj, matching the generated name used throughout this run. The next crop checks that this flow-only role received no service-access policy.

The role has zero attached permissions policies.

The role details page shows Permissions policies (0). The trust policy above names only states.amazonaws.com, with no Lambda service principal. No account-derived role identifier appears in either public image.

2. Define the three-way workflow

Open AWS Step Functions, search for miruky-lskuhtkkfznglstd, and confirm no exact state-machine name exists. Begin creating a state machine and stop when its identity settings are visible.

The Step Functions list has no exact match for the generated state-machine name.

The exact filter for miruky-lskuhtkkfznglstd returns no state machine. This establishes the resource boundary before creation.

The state-machine creation dialog uses the generated name and Express workflow type.

The identity crop shows miruky-lskuhtkkfznglstd and Express. Workflow type cannot be changed after creation, so this choice belongs in the identity dialog rather than in a later correction.

In Workflow Studio, select JSONPath, switch to the code editor, and replace the definition with this Amazon States Language document:

{
  "Comment": "Route a tier without invoking a task service",
  "QueryLanguage": "JSONPath",
  "StartAt": "Route tier",
  "States": {
    "Route tier": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.tier",
          "StringEquals": "gold",
          "Next": "Priority path"
        },
        {
          "Variable": "$.tier",
          "StringEquals": "standard",
          "Next": "Standard path"
        }
      ],
      "Default": "Manual review"
    },
    "Priority path": {
      "Type": "Pass",
      "Result": { "route": "priority" },
      "End": true
    },
    "Standard path": {
      "Type": "Pass",
      "Result": { "route": "normal" },
      "End": true
    },
    "Manual review": {
      "Type": "Pass",
      "Result": { "route": "manual-review" },
      "End": true
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Workflow Studio renders one Choice state and three terminal Pass branches.

The rendered graph shows one Choice state feeding three terminal Pass states. The explicit QueryLanguage in the definition keeps the Variable, StringEquals, and Result fields in their JSONPath form.

The Default branch is deliberate. Without it, an input that matches no choice rule causes the Choice state to fail because it has nowhere to transition.

3. Create the Express Workflow

Open Config, choose the existing role miruky-nlanmycdwgncgejj, set execution logging to Off, and leave X-Ray tracing disabled. The role selector stays outside the public image because it can expose account-derived role metadata.

The Step Functions log level is set to OFF.

The Logging section shows Log level set to OFF. Disabling logging matters here because Express Workflow execution history otherwise comes from CloudWatch Logs.

The Enable X-Ray tracing checkbox is unchecked in Additional configuration.

The expanded Additional configuration section shows an unchecked Enable X-Ray tracing control. No trace collection is enabled for these runs.

After creation, confirm the definition is valid and the visual graph has no Task state. The route result will therefore come entirely from the selected Pass state.

The created state machine shows the Choice and three Pass states with no service integration.

The saved graph retains Route tier, Priority path, Standard path, and Manual review with no Task state. The synchronous response will return the selected Pass state's output directly.

4. Prove the gold and standard branches

Choose Start execution, select a synchronous Express run, name the initial execution miruky-rkykjdmpxjcugmzi, and use this input:

{
  "tier": "gold"
}
Enter fullscreen mode Exit fullscreen mode

Run the workflow synchronously. This input is designed to select Priority path.

The synchronous execution form contains only the fixed gold-tier input before the run.

The input-only crop shows {"tier":"gold"} before the execution starts. The generated execution name and all account-derived metadata remain outside the image.

The gold synchronous response returns the priority route.

The separate response-only crop shows route value priority. The Console's completion notification and the execution-details panel were checked privately together with the generated execution name. That fixed value is produced only by Priority path in the saved definition.

Start another synchronous run named miruky-ilodyrwakdqonsva with {"tier":"standard"}. This input is designed to select Standard path.

The synchronous execution form contains only the fixed standard-tier input before the run.

The input-only crop shows {"tier":"standard"} before the standard-tier execution starts. The next response isolates the result produced by that branch.

The standard synchronous response returns the normal route.

The separate response-only crop shows route value normal. That fixed result comes from Standard path. I checked the completion notification, generated execution name, input, and output privately. The unchanged workflow definition isolates the difference to the input tier.

Each execution evaluates the choice rules in their listed order. These two values match different rules, so their paths and outputs should remain unambiguous.

5. Prove the default branch

Start the final synchronous run named miruky-jbuilpzxinswmjfm with an unmatched tier:

{
  "tier": "trial"
}
Enter fullscreen mode Exit fullscreen mode

Neither StringEquals rule matches trial, so the explicit Default transition directs it to Manual review.

The synchronous execution form contains only the unmatched trial-tier input before the run.

The input-only crop shows {"tier":"trial"} before the trial-tier execution starts. The next response verifies the output from the unmatched-input path.

The trial synchronous response returns the manual-review route.

The separate response-only crop shows route value manual-review. That value exists only in the Manual review Pass state. I checked the completion notification, generated execution name, input, and output privately. This marker does not start a human-review process; it only proves that an unsupported tier did not enter either named tier path.

Correct only the input tier to gold and start one more synchronous run named miruky-qjsjnepxawdezgdi. The unchanged workflow should return {"route":"priority"} again.

The synchronous execution form contains only the corrected gold-tier input before the run.

The input-only crop shows the corrected {"tier":"gold"} value before the fourth execution starts. The next view pairs that corrected input with its immediate output.

The corrected gold execution input and synchronous output show the priority route.

The execution-details crop pairs corrected input gold with output route priority. I checked the completion notification and generated execution name privately. Changing only trial to gold recovers from the fallback path and confirms that the saved choice rules remain active.

After recording the fourth immediate response, inspect whether the Express workflow retained a later execution-history view.

The Console reports that logging is disabled and execution history requires logging.

The page reports Logging is disabled and explains that execution status and history require logging. The four results came from the immediate synchronous responses, not from a stored execution history.

Wrap-up

One Choice state routed inputs without compute code or a service integration. Gold returned priority, standard returned normal, the unmatched trial tier reached manual-review, and correcting that input to gold returned to priority. Logging remained off, so these validation runs did not create CloudWatch log resources or Step Functions execution history.

This pattern is useful when a workflow decision depends only on data already present in its input. A task service belongs in the design when a branch must perform work or fetch data, not merely to express a comparison that Step Functions already supports.

Thanks for reading this far.

See you in the next one.

Disclosure: This article was written with AI assistance and independently verified against the linked primary sources and observed results.

References

Top comments (0)