Skip to content

Recipes lab ​

Nine patterns you meet in real APIs, each built once in Mock Studio and tested once in ApiWorkbench. Every recipe is a folder in the collection, so you can run one, read how the mock does it, change it, and run it again.

Level: intermediate · Time: 10 minutes per recipe · Before this: Todo API lab

Download ​

Set up ​

  1. In Mock Studio, select Import, choose Mock Studio project file and pick recipes.mockstudio.json. Select Start server. The mock is at http://localhost:4040.

  2. In ApiWorkbench, select Import, choose recipes.apiworkbench.json and select Import.

  3. Run the whole collection once from its ⋯ menu with Run collection. All 17 sends should pass. (There are 15 requests; the polling request sends itself three times.)

#RecipeThe patternMock Studio featureApiWorkbench feature
1PagingFollow the next linkRules on a query parameterCapture a link, use it as the URL
2EchoPut request data in the answerTemplates: {{body.name}}, {{uuid}}JSON field tests
3ETagAsk only if it changedRule on a header, a 304 responseCapture a header, send it back
4VersioningPick a version by headerRule on a headerRequest headers
5Token refreshRecover from an expired tokenRules in orderBearer auth, captures
6WebhooksBe the receiverA plain 204, the Live logDynamic variables
7PollingAsk until it is doneSequenceA script with setNextRequest
8ValidationOne request, every ruleRegex rulesA data file and a script
9CORSThe browser's preflightCORS switchOPTIONS and header tests

The pattern. Lists come a page at a time. A good API tells you where the next page is, and a good client follows that link instead of building URLs itself.

The mock. List articles (paged) uses Conditional rules on the query parameter page: 2 and 3 get their own responses, anything else gets page 1. Each page includes next; the last page has "next": null.

The tests.

RequestDoesChecks
First pageGET /articles, captures nextPage = body.nextpage is 1, first id is 1
Follow the next linkGET {{baseUrl}}{{nextPage}}page is 2, first id is 3
Past the last pageGET /articles?page=3next is null, items is empty

The second request has no page number written in it: the URL comes from the first response. If the API changes how it pages, this test keeps working.

Try it. Add a page 4 rule in the mock and change page 3's next to point at it. Run the folder: nothing in ApiWorkbench needs to change for the second request.

2. Echo: put request data into the response ​

The pattern. A create endpoint usually returns what you sent, plus what the server added: an id and a timestamp.

The mock. Echo answers POST /echo with templates:

json
{
  "hello": "{{body.name}}",
  "city": "{{body.city}}",
  "requestId": "{{uuid}}",
  "receivedAt": "{{now}}"
}

The tests. Send {"name": "Ada", "city": "Chennai"} and check that hello is Ada and city is Chennai. requestId changes every time, so the test checks only that it is there (Body contains requestId), never its value.

Try it. Send a body without city. The mock leaves {{body.city}} as written, which is how Mock Studio shows a token it could not fill. See Dynamic templating.

3. ETag: ask only if it changed ​

The pattern. The server labels a resource with an ETag. The client sends that label back in If-None-Match; if nothing changed, the server answers 304 Not Modified with no body, and the client keeps its saved copy. Less data, faster pages.

The mock. Profile (ETag) has two responses. With the rule Header If-None-Match equals "v7", it sends 304 and no body. Otherwise it sends the profile with the header ETag: "v7".

The tests.

RequestDoesChecks
First fetchGET /profile, captures etag = header.ETag200, ETag contains v7
Fetch again with If-None-MatchSends If-None-Match: {{etag}}304

The quotes are part of the ETag. The capture keeps them, so the value sent back matches exactly.

Try it. In the mock, change every "v7" to "v8", as a server would after an edit, and run the folder. The second request still gets 304, because it sends back whatever the first one captured. Only the first request's ETag contains v7 test fails: it checks a fixed label, which is exactly what changed.

4. Versioning: pick a version with a header ​

The pattern. When an API changes the shape of a response, old clients must keep working. One common way: the new shape only for clients that ask for it, here with Accept-Version: 2.

The mock. Greeting (versioned) has a rule on the header Accept-Version. Version 1 says "message": "Hello"; version 2 says "message": { "text": "Hello", "lang": "en" }.

The tests. One request without the header checks message is Hello. One with the header checks message.text is Hello. Together they prove version 2 exists and version 1 still works, which is the promise a versioned API makes.

5. Token refresh: recover from an expired token ​

The pattern. Access tokens expire. The client sees a 401, trades its refresh token for a new access token, and tries again.

The mock. Secure report checks its rules in order:

OrderConditionAnswer
1Authorization equals Bearer expired-token401 token_expired, with a WWW-Authenticate header
2Authorization exists200, the report
3(fallback)401 missing_token

Refresh token gives a new accessToken for the refresh token refresh-123, and 401 for anything else.

The tests. Call with the expired token and expect 401. Call Get a new token, which captures accessToken = body.accessToken. Retry with Bearer Token {{accessToken}} and expect 200.

Rule order matters: if rule 2 came first, the expired token would match "exists" and get the report. See Conditional rules.

Try it. Point your own app at the mock with the token expired-token. Does it refresh and retry by itself, or show the user an error?

6. Webhooks: be the receiver ​

The pattern. A webhook is a request a service sends to you when something happens: a payment succeeded, a build finished. To build the receiver, you need to see exactly what arrives.

The mock. Payment webhook simply answers 204 to POST /webhooks/payments. The useful part is Mock Studio's Live log, which shows the headers and body of each event.

The tests. ApiWorkbench plays the sending service: a POST with an X-Signature header and an event body. {{$randomInt}} gives each event a different id.

json
{
  "event": "payment.succeeded",
  "id": "evt_{{$randomInt}}",
  "amount": 1999,
  "currency": "INR"
}

Send it, then open Live in Mock Studio and select the request to read it.

Try it. To receive webhooks from a real service on the internet, the mock needs a public address. See Public internet (tunnel), and stop the tunnel when you are done.

7. Polling: ask until it is done ​

The pattern. Slow work starts a job and returns at once. The client asks for its status until it says done.

The mock. Job status uses Sequence (round-robin): queued, then running, then done, then round again.

The tests. Wait for the job to finish has a post-response script that sends the same request again until the status is done, at most 10 times:

js
const body = pm.response.json();
const tries = Number(pm.collectionVariables.get('pollTries') || 0) + 1;
pm.collectionVariables.set('pollTries', String(tries));
if (body.status !== 'done' && tries < 10) {
  postman.setNextRequest('Wait for the job to finish');
} else {
  pm.collectionVariables.set('pollTries', '0');
  pm.test('job finished within 10 tries', function () {
    pm.expect(body.status).to.eql('done');
  });
}

postman.setNextRequest works in a run, so use Run folder on Polling. The results show the request three times, and the last one passes the test. Always put a limit on a loop like this: a job that never finishes should fail the test, not hang the run. See Script cookbook.

8. Validation: one request, every rule ​

The pattern. A sign-up form has rules: a real-looking email, a password of at least 8 characters. Each broken rule needs its own clear error.

The mock. Sign up uses matches regex conditions, checked top to bottom:

OrderConditionsAnswer
1email matches ^[^@\s]+@[^@\s]+\.[^@\s]+$ and password matches ^.{8,}$201
2email matches that pattern and password exists422, field: password
3email exists422, field: email
4(fallback)400, missing fields

Mock Studio has no "does not match", so the rules run from the most valid to the least: anything that falls past rule 1 is broken in some way.

The tests. One request, {"email": "{{email}}", "password": "{{password}}"}, run once per row of signup-cases.csv:

csv
email,password,expectedStatus,expectedField
ada@example.com,correct-horse,201,
ada@example.com,short,422,password
not-an-email,correct-horse,422,email
ada@example,correct-horse,422,email
,correct-horse,400,

The post-response script reads expectedStatus and expectedField from the row and checks the response against them.

  1. Open the Validation folder's ⋯ menu and choose Run folder.

  2. Select Load data file and pick signup-cases.csv.

  3. Select Run. Five passes, one per row.

Try it. Add the row ada@@example.com,correct-horse,422,email. Does the regex catch it? Then add a rule to the mock that refuses passwords made only of digits, and a row to prove it. See Data-driven testing.

9. CORS: the browser's preflight ​

The pattern. Before a web page on one site calls an API on another, the browser asks permission with an OPTIONS request, the preflight. If the API's answer does not allow it, the browser blocks the call, however correct the API is.

The mock. Nothing to build: with CORS on in the project settings (the default), Mock Studio answers every preflight with 204 and the Access-Control-Allow-… headers. See Auth, CORS and project settings.

The tests. Preflight check sends OPTIONS /articles with an Origin and an Access-Control-Request-Method: POST header, as a browser would, and checks the status and both Access-Control-Allow-… headers.

Try it. Turn CORS off in the project settings and run the folder again. The preflight no longer gets the CORS headers, and the header tests fail: that is what a browser would block.

Check yourself ​

QuizRecipes lab

Question 1 of 6

Page 1 of a list answers with this. What should the client request next?

{ "page": 1, "items": [...], "next": "/articles?page=2" }
Score: 0

What you learned ​

  • Follow links the API gives you; capture them instead of building URLs.
  • Template tokens make a mock answer with the data you sent.
  • Rule order decides which response wins; put the most specific first.
  • A sequence makes retries and polling testable; a script can loop, with a limit.
  • One request plus a data file can prove every validation rule.

Next steps ​