Send REST requests
A scenario registers a REST service, adds requests to it, executes them and checks their responses (rest pack). This page is about what happens in between: the payload a request sends, the redirects it follows, the cookies it sends, and the headers a custom step gives it. To sign a request as a webhook is signed, or authorize it with a token, see Test webhooks and tokens.
The REST pack tests APIs. To test a web app’s pages, forms or sign-in, use the web-core pack: a real browser keeps cookies, follows redirects and submits forms, as the app’s users do (Test web apps).
Payloads from files
Section titled “Payloads from files”A payload starts from an example of the service’s OpenAPI specification, from an empty template the payload property steps fill, or from a file of the project, sent as it is:
Scenario Outline: A shop's order system registers the parcels it exports Given a POST request to /api/parcels And a request payload using an application/json requests/<order>.json resource When the request is executed Then the response status code is 201 And the response header Location is '/api/parcels/<reference>'
Examples: | order | reference | | order-7731 | PX-REG-1301 | | order-7732 | PX-REG-1302 |- The file is found like the other files steps name: relative to the
resourcesdirectories, or toaxx.yaml’s directory. - A JSON payload can still change. The payload property steps edit it, like a payload from an example. A property inside an object the payload lacks creates the object:
recipient.nameandrecipient.postcodefill an empty template’srecipient(ADR 0010). - A form payload file is a JSON object. With
application/x-www-form-urlencoded, its properties are sent form-encoded. - No OpenAPI specification is needed, which suits a callback or a webhook that the service has no contract for.
A fixture factory keeps such files in one place and checks them against a schema. The parcels example generates the two files above with requests/registrations.factory.yaml, from the ParcelRequest schema of the service’s OpenAPI contract.
Several requests in one scenario
Section titled “Several requests in one scenario”Requests are numbered in the order a scenario adds them. The first is the default, which steps without an ordinal use; every other request is added, executed and checked with its ordinal:
Scenario: A registered parcel can be looked up by its reference Given a POST request to /api/parcels And a request payload using an application/json content example And the request payload property reference is 'PX-REG-1401' And a 2nd ordered GET request to /api/parcels/PX-REG-1401 When the request is executed And the 2nd ordered request is executed Then the response status code is 201 And the 2nd ordered response status code is 200 And the response payload property reference is 'PX-REG-1401' for 2nd ordered response- Add a request before using it: a step that uses the 2nd request fails unless a 2nd was added before it.
axx validatesays so, with the step that adds it. - A second
a GET request to …adds the 1st again, and fails: write it asa 2nd ordered GET request to ….axx validateshows the line to write. - A check names its response:
the 2nd ordered response status code is 200, or… for 2nd ordered responseat the end of the other response steps. A check without one reads the 1st response.
Find an item in a list
Section titled “Find an item in a list”A property can pick items out of a list with a JSONPath filter: parcels[?(@.reference=='PX-REG-1401')].status is the status of that parcel. The value a check compares is the list of what matched, so one match reads '["delivered"]'.
Then the response payload property parcels[?(@.reference=='PX-REG-1401')].status is '["delivered"]'And the response payload property parcels[?(@.service=~/Next\sday\sair/)].reference is '["PX-REG-1401"]'- A path is one word, without spaces. To match a text with spaces, use
=~and a regular expression, where\sstands for the space. =~matches the whole text, as Jayway’s JSONPath does:/Next\sday/doesn’t match “Next day air”, while/Next\sday.*/does.
Redirects
Section titled “Redirects”| Request | Redirects it follows | The response the steps check |
|---|---|---|
GET, HEAD |
301, 302, 303, 307 and 308 | the one the redirects lead to |
POST, PUT, PATCH, DELETE, … |
303 See Other, with a GET |
after a 303, the one it leads to |
POST, PUT, PATCH, DELETE, … |
none of the others: 301, 302, 307 and 308 | the redirect itself |
A redirect the pack follows is not kept: its status, its Location header and the cookies it sets are not the response’s, and the response steps cannot check them. The scenario’s log shows the request as the step sent it and the status at the end, like GET http://localhost:8080/api/parcels/PX-REG-1010 -> 200 OK (12ms, 412 bytes).
The GET that follows a 303 has no body and no Content-Type. It has the request’s other headers, Authorization and Cookie only when the redirect stays on the same host or goes to a subdomain of it.
Redirects left to the scenario
Section titled “Redirects left to the scenario”A POST, PUT, PATCH or DELETE answered with 301, 302, 307 or 308 has the redirect as its response. Check its status and its Location header, and send the request it leads to as the next ordered request. Say a service moved its API from /api/v1 and answers the old paths with 308 Permanent Redirect:
Scenario: A cancellation sent to the old API cancels the parcel through its redirect Given a 1st ordered DELETE request to /api/v1/parcels/PX-REG-1010 And a 2nd ordered DELETE request to /api/parcels/PX-REG-1010 When the 1st ordered request is executed And the 2nd ordered request is executed Then the 1st ordered response status code is 308 And the response header Location is '/api/parcels/PX-REG-1010' for 1st ordered response And the 2nd ordered response status code is 204The scenario sends both requests, then checks both responses: the redirect, where it leads, and the cancellation there.
Cookies
Section titled “Cookies”The REST pack keeps no cookies. A Set-Cookie response header is never sent back: not with the scenario’s later requests, and not to where a redirect leads. A request carries the cookies its scenario gives it, in its Cookie header (the request header Cookie is '...'), and nothing else, so scenarios running side by side never share cookies.
Headers from custom steps
Section titled “Headers from custom steps”A custom step changes a request the pack’s steps built, before it is executed, through the request’s headers: Header() returns the headers it is sent with, and Set, Add and Del change them. SetHeader(name, value) does what the request header steps do. Write custom steps has an example.