Skip to content

Flows: load and user journeys ​

A flow is a list of requests, called steps, that Mock Studio sends for you: log in, fetch something, create something. One virtual user runs the steps in order like a person using an app. Many virtual users run them at the same time to produce load. While a flow runs you see how fast and how reliably the server answers.

Use flows to:

  • check a whole journey through your mock in one click, instead of calling endpoints one by one;
  • see how a flaky or slow mock behaves under many calls;
  • send realistic concurrent traffic to another server you own, by setting a target URL.

Create a flow ​

  1. Select Flows in the rail.

  2. On the No flows yet screen, choose one of:

    • Build from endpoints makes a flow called All endpoints with one step for every enabled endpoint.
    • Blank flow makes a flow with a single GET /health step for you to edit.
  3. Type a name in Flow name, such as Checkout journey.

Later, use the New flow button in the list of flows, which offers Blank flow and From all endpoints. Each flow's menu has Duplicate and Delete. Flows are saved in the project file with your endpoints.

When a flow is built from endpoints, each step is made callable: a path parameter such as :id becomes {{vu}}, * becomes sample, POST, PUT and PATCH steps get a small JSON body, and endpoints that require auth get a header with the value Bearer test.

Steps ​

The Steps section lists the requests one virtual user makes in a round. One round through all the steps is called an iteration.

Select Add step to add a step from one of your endpoints, or Custom request for a blank step. Each step has a row of main fields and a details area for the name, headers, body and extract, which you open with the button at the end of the row.

FieldWhat it isExample
CheckboxInclude this step in runs. Untick it to skip the step without deleting it.
MethodGET, POST, PUT, PATCH, DELETE, HEAD or OPTIONSPOST
PathAdded to the target URL. A full http:// or https:// URL is used as it is./orders/{{vars.orderId}}
ExpectStatus codes that count as success200
Step name (optional)Shown in the results. Empty uses the method and path.Log in
HeadersOne per line, as Name: valueAuthorization: Bearer {{vars.token}}
Extract into variablesOne per line, as name = sourcetoken = body.token
BodyData sent with the request{"email": "{{faker.email}}"}

Use Move up, Move down and Remove step to arrange the list.

A body that starts with { or [ is sent as application/json, and any other body as text/plain, unless Headers sets a Content-Type.

Expect: which statuses count as success ​

You typeSuccess means
nothingAny status below 400
200Exactly 200
2xxAny status from 200 to 299
200,201,404Any of the listed codes
2xx,404Any 2xx status, or 404

Any other status makes the step failed. So does a timeout, which is 30 seconds with no reply, or a connection error.

To test an error case on purpose, expect the error: a step that should be rejected can have Expect 401.

Extract: keep a value for later steps ​

Extract into variables saves part of a step's reply under a name. Write one line per value, as name = source.

SourceReadsExample line
body.<path>A field of the JSON replytoken = body.token
body.<path> with a numberAn item of a list, counting from 0id = body.items.0.id
header.<name>A response headeretag = header.etag
statusThe status codecode = status

A later step uses the value as {{vars.name}}, for example {{vars.token}}. Extracted values are reset at the start of every iteration, and each virtual user has its own.

If a value cannot be found, the variable is not set, and {{vars.name}} is sent as typed.

Tokens in steps ​

Path, Headers and Body can use these tokens:

TokenReplaced with
{{vars.<name>}}A value extracted by an earlier step in the same iteration
{{vu}}The virtual user's number, starting at 1
{{iteration}}The round number for that user, starting at 1
{{uuid}}, {{now}}, {{timestamp}}, {{randomInt(1,9)}}, {{faker.name}} and the other generated-value tokensA fresh value for each request

{{vu}} gives each user a different value, for example /users/{{vu}} or an email of user{{vu}}@example.com. The request tokens used in responses, such as {{params.id}} and {{body.email}}, have no meaning in a step and are left as typed. See Dynamic templating for the generated-value tokens.

Load profile ​

The Load profile section sets how much traffic to send.

SettingDefaultWhat it does
Virtual users5How many simulated users run the steps at the same time, from 1 to 1000.
Iterations / user10How many rounds each user makes. Ignored when a duration is set.
Duration (s)0Run for this many seconds instead of a number of iterations. 0 means use iterations.
Ramp-up (s)0Spread user start times over this many seconds instead of starting everyone at once.
Think time (ms)0A pause after each step, like a person reading a page.
Target base URLemptyThe server to call. Empty means this project's mock.

Iterations or duration. With iterations, the total number of requests is known in advance:

text
requests = virtual users × iterations × enabled steps
5 users × 10 iterations × 3 steps = 150 requests

With a duration, users repeat the steps until the time is up. The ramp-up time counts toward the duration.

Ramp-up. With 10 users and a ramp-up of 10 seconds, one new user starts each second. Use it to watch how the server copes as load grows, instead of hitting it with everyone at once.

Think time. In One by one mode the pause comes after every step. In All at once mode it comes after each round.

Step mode ​

ModeHow one iteration runsUse it for
One by oneSteps run in order, each waiting for the previous reply. Later steps can use extracted values.User journeys: log in, then use the token
All at onceEvery step of the round is sent at the same moment. Extracted values are not passed between steps.Bursts of parallel calls, like a page that loads several things together

Stop iteration on first failed step applies to One by one mode and is on by default. When a step fails, the user skips the rest of that round and starts the next one. Keep it on when later steps depend on an earlier one: if login fails, there is no token for the next step.

Target base URL ​

Leave Target base URL empty to run the flow against this project's mock at http://127.0.0.1: and its port. If the server is stopped, Run flow starts it for you.

Type an address, such as http://localhost:3000, to send the flow to another server. Each step's path is added to it.

WARNING

A flow with many users sends a lot of traffic. Only target servers you own or have permission to load-test. Sending load at someone else's service can get your address blocked and may break their terms of use.

Worked example: a login journey ​

This flow uses the sample project My First Mock API. Each user logs in, reads a user and creates a user.

Set One by one, 5 Virtual users and 10 Iterations / user, then add three steps:

StepMethod and pathDetails
Log inPOST /loginBody {"password": "secret"}, Expect 200, Extract token = body.token
Get userGET /users/{{vu}}Headers Authorization: Bearer {{vars.token}}, Expect 200
Create userPOST /usersBody {"name": "{{faker.name}}", "email": "{{faker.email}}"}, Expect 201

Select Run flow. The run sends 5 × 10 × 3 = 150 requests. The first step captures the token the mock returns, and the second sends it back in a header.

Now break it on purpose: change the body of Log in to {"password": "wrong"} and run again. The login step gets 401, which is not in its Expect, so it fails. With Stop iteration on first failed step on, the other two steps are skipped: the results show 50 calls, all failed, with the error Unexpected status 401.

Run and stop ​

Select Run flow to start. Select Stop to end early: requests already in flight finish, and the results so far stay on screen. A status line shows how long the run has taken and how many iterations are done, then Finished or Stopped at the end.

Read the results ​

The Results section updates live. The numbers reset when you run the flow again and are not saved.

Summary ​

TileMeaning
RequestsTotal requests sent so far, including failed ones.
Req / secThroughput: requests finished per second, on average, since the run started.
FailedFailed requests and the error rate as a percentage.
p50The median response time.
p9595% of requests were faster than this.
p9999% of requests were faster than this.
AvgThe mean response time.
Active usersVirtual users running right now. It climbs during ramp-up and drops to 0 at the end.

What p50, p95 and p99 mean ​

These are percentiles. Line up every response time from fastest to slowest:

  • p50, the median, is the one in the middle. Half the requests were faster and half slower. It is the typical response time.
  • p95 is the time that 95% of requests beat. Only the slowest 1 in 20 took longer. It is a good guide to what most users feel.
  • p99 is the time that 99% of requests beat. Only 1 in 100 took longer. It shows the worst delays a few users hit.

Example. A run reports p50 12 ms, p95 80 ms and p99 250 ms. A typical request took 12 ms. Nineteen in twenty finished within 80 ms. One in a hundred took a quarter of a second or more.

The average can hide slow requests. One 5-second reply among 99 fast ones barely moves the average but shows up at once in p99. Compare Avg with p50 and p95: when the average is well above the median, a few requests are much slower than the rest.

Percentiles are measured to the nearest millisecond below one second, and in coarser steps above that.

Throughput chart ​

Throughput (requests / second) draws one bar per second of the run, split into OK and Failed. Hover a bar for the exact numbers. The chart shows the last 2 minutes.

Per step ​

The Per step table gives the same numbers for each step, so you can spot which endpoint is slow or failing.

ColumnMeaning
StepThe step's name, or its method and path.
CallsRequests sent for this step.
FailedCalls with an unexpected status, a timeout or a connection error.
Avg, p50, p95, p99Response times in milliseconds.
MaxThe slowest single call.

Under each step you also see how many calls got each status code, such as 200 ×1,500, and the reasons calls failed, such as Unexpected status 401 (×210). Up to five different error messages are kept per step.

Common error messages ​

MessageMeaning
Unexpected status 401The reply's status is not in the step's Expect.
Timed out after 30sNo reply within 30 seconds, for example from a Hang fault.
Connection failed: …The server could not be reached or dropped the connection.
This flow has no enabled steps.Every step is unticked, or there are none.

Things to keep in mind ​

  • The mock and the load come from the same computer. The numbers describe your mock on your machine, not the speed of the real API it stands in for.
  • Delays and faults show up in the results. A response with an 800 ms delay gives a p50 near 800 ms. That makes flows a quick way to confirm that a latency or fault setting does what you intended.
  • The Live log keeps 500 requests. During a large run, the Live section shows only the latest ones.
  • Sequence responses are shared. An endpoint using Sequence (round-robin) has one counter for all virtual users, so users take turns through the same sequence.

For the ideas behind load numbers, see Load testing. For journeys with assertions on real APIs, see Workflow testing and the ApiWorkbench runner.

Next steps ​