Send HTTP requests to REST services, validate them against the services’ OpenAPI specifications, and assert on the responses.
Services. Register services with the <name> service with the following properties: (url, optional openapi). The first service registered in a scenario is the default one; the other steps name a service with on <name>.
Requests. Each service keeps its requests in the order they are added: a GET request to /path adds the first (default) request and a 2nd ordered POST request to /path the second. Header, payload, execution and response steps address a request with for 2nd ordered request / for 2nd ordered response (default: the first). A request is executed once; its response stays available to every later step.
Payloads. A payload starts from an OpenAPI content example (the named one, or the first in document order; externalValue examples are read relative to the specification) or from an empty template {}, and is edited with the payload property steps (JSONPath, typed values, null/undefined). application/x-www-form-urlencoded payloads are sent form-encoded.
Execution. Requests go through one HTTP client shared by the run (connections are reused and closed at the end), honor the step timeout, and do not verify TLS certificates unless packs.rest.tls.verify: true is set in axx.yaml. Without a Content-Type header a payload is sent with its payload step’s media type.
Redirects. A GET or HEAD request follows redirects (301, 302, 303, 307 and 308); a request with another method follows only 303 See Other, with a GET, as a browser does after a form. A request that follows a redirect has the response it leads to: the response steps check that one, and the redirect responses, with their Location and Set-Cookie headers, are not kept. The other redirects of a POST, PUT, PATCH or DELETE (301, 302, 307 and 308) are its response: check the status and the Location header, and send the request it leads to as the next ordered request.
Cookies. The pack keeps no cookies: a Set-Cookie response header is never sent back, not even to where a redirect leads, so no request carries a cookie from another scenario. Send a cookie with the Cookie request header: it goes along when the request follows a redirect on the same host or to a subdomain of it.
OpenAPI validation. When a service has an openapi specification (OpenAPI 3.0 or 3.1, a URL or a file; parsed once per run), each executed request and its response are validated after sending. Every finding has a key in the style of the swagger request validator (the one the WireMock extension uses), and a level:
ERROR(aliasFAIL, the default for every key) fails the execute step, listing every error with its key;WARNandINFOare logged on the step;IGNOREdrops the finding.
Levels come from openapi.levels in axx.yaml and are overridden per scenario with the OpenAPI validation levels are:. A key also sets every more specific key (validation.request.body covers validation.request.body.schema.required); the most specific configured key wins. A key must be one of the keys below, or a prefix of them: any other, in the step or in axx.yaml, is an error that names the closest keys.
| Key | Reported when |
|---|---|
validation.request.path.missing |
no path of the specification matches the request path |
validation.request.operation.notAllowed |
the path exists but not for the request method |
validation.request.body.missing |
the operation requires a body and the request has none |
validation.request.body.unexpected |
the request has a body the operation does not declare |
validation.request.contentType.notAllowed |
the request Content-Type is not declared for the operation |
validation.request.body.schema.{keyword} |
the request body violates a schema keyword (type, required, enum, format, pattern, minimum, maxLength, additionalProperties, oneOf, …) |
validation.request.body.schema.invalidJson |
the request body cannot be parsed |
validation.request.body.schema.processingError |
the request body schema cannot be compiled or the body cannot be read |
validation.request.parameter.missing |
a required path parameter is missing |
validation.request.parameter.query.missing |
a required query parameter is missing |
validation.request.parameter.header.missing |
a required header parameter is missing |
validation.request.parameter.cookie.missing |
a required cookie parameter is missing |
validation.request.parameter.schema.{keyword} |
a parameter value violates its schema (type, enum, format, pattern, minimum, …) |
validation.request.parameter.schema.invalidJson |
a JSON (content) parameter cannot be parsed |
validation.request.parameter.schema.processingError |
a parameter’s schema cannot be compiled |
validation.request.parameter.collection.invalidFormat |
an array or object parameter is serialized in the wrong style |
validation.request.parameter.collection.tooManyItems |
an array parameter has more than maxItems items |
validation.request.parameter.collection.tooFewItems |
an array parameter has fewer than minItems items |
validation.request.parameter.collection.duplicateItems |
an array parameter with uniqueItems repeats an item |
validation.request.parameter.{in}.invalid |
any other parameter problem; {in} is path, query, header or cookie |
validation.request.security.missing |
the credentials a security requirement needs are absent |
validation.request.security.invalid |
credentials are present but do not match the security scheme |
validation.response.status.unknown |
the response status is not documented for the operation (and there is no default) |
validation.response.contentType.notAllowed |
the response Content-Type is not declared for the status |
validation.response.body.missing |
the response declares a body schema but has no body |
validation.response.body.unexpected |
a response to HEAD has a body |
validation.response.body.schema.{keyword} |
the response body violates a schema keyword |
validation.response.body.schema.invalidJson |
the response body cannot be parsed |
validation.response.body.schema.processingError |
the response body schema cannot be compiled or the body cannot be read |
validation.response.header.missing |
a required response header is missing |
validation.response.header.schema.{keyword} |
a response header value violates its schema |
validation.request.unknownError |
anything else the validator reports about the request |
validation.response.unknownError |
anything else the validator reports about the response |
Schema keywords use the draft-4 names: const is reported as enum, exclusiveMinimum/exclusiveMaximum as minimum/maximum, unevaluatedProperties as additionalProperties. A schema failure that names no keyword is keyed unknownError (validation.request.body.schema.unknownError).
When a scenario fails, its failure context (rest) shows the last request and response (headers, bodies truncated to 2 KB) and the OpenAPI findings.
Add it to a project with axx pack add rest.
Settings
Section titled “Settings”In axx.yaml, under packs.rest:
| Setting | Takes | Values | Default |
|---|---|---|---|
openapi.levels |
Validation key -> ERROR (or FAIL), WARN, INFO or IGNORE. Merged over the top-level openapi.levels. | names and values | |
tls.verify |
Verify TLS certificates. | true, false |
false |
rest.service
Section titled “rest.service”Given the {word} service with the following properties: | property | value |The table may start with the row naming its columns, as above, or go straight to its rows.
Register a REST service: where its requests go, and the OpenAPI specification they are checked against.
- The first service registered in a scenario is the default one.
- With an
openapispecification, every request executed and its response are validated against it, and request payloads can start from its examples. - Values can use
${env:…}and${sys:…}, which are expanded.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
| Property | Takes | Default |
|---|---|---|
url |
the base URL requests go to, like http://localhost:8400; a request’s path is added to it |
required |
openapi |
the service’s OpenAPI 3.0 or 3.1 specification: a URL, or a file of the project (relative to the resources directories or to axx.yaml’s directory) |
Any other property fails the step.
Example:
Given the parcels service with the following properties: | url | http://localhost:8400 | | openapi | http://localhost:8400/openapi.json |rest.openapi.levels
Section titled “rest.openapi.levels”Given the OpenAPI validation levels[[ on {service}]] are: | validation key | level |The table may start with the row naming its columns, as above, or go straight to its rows.
Set the level of OpenAPI validation findings for this scenario, on the default or the named service.
- A key also sets the keys below it:
validation.request.bodyrelaxesvalidation.request.body.schema.requiredtoo. The most specific key set wins. - The rows are merged over
openapi.levelsof axx.yaml. - The pack’s documentation lists the keys, and what each level does.
| Parameter | Takes | For example |
|---|---|---|
{service} |
the name of a REST service the scenario registered | parcels |
A row is a validation key and its level: ERROR (or FAIL), WARN, INFO or IGNORE. The key must be one the pack reports, or a prefix of such keys, like validation.request.body: any other fails the step, which names the closest keys.
Variants, the parts in [[...]] said or left out:
the OpenAPI validation levels are:the OpenAPI validation levels on {service} are:
Example:
Given the OpenAPI validation levels are: | validation.request.body.schema.maximum | IGNORE | | validation.response.header.missing | WARN |Given the OpenAPI validation levels on parcels are: | validation.request.body.schema.required | WARN |rest.request
Section titled “rest.request”Given a(n) {word} request to {word}[[ on {service}]]Add a request to the default or the named service: its method, and its path below the service’s url.
- The path can have a query string, like
/api/parcels?sender=kestrel-books. A whole URL replaces the service’surl. - This is the service’s first (default) request; the ordered form adds more.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{service} |
the name of a REST service the scenario registered | parcels |
Variants, the parts in [[...]] said or left out:
a(n) {word} request to {word}a(n) {word} request to {word} on {service}
Example:
Given a GET request to /api/parcels/PX-1001Given a DELETE request to /api/parcels/PX-1001 on parcelsrest.request.ordered
Section titled “rest.request.ordered”Given a {ordinal} ordered {word} request to {word}[[ on {service}]]Add the Nth request of a service. Requests are numbered in the order they are added: the 1st ordered request is the default request, and the Nth can only be added once N-1 exist.
| Parameter | Takes | For example |
|---|---|---|
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{word} |
one word, with no spaces | parcels, PX-4101 |
{service} |
the name of a REST service the scenario registered | parcels |
Variants, the parts in [[...]] said or left out:
a {ordinal} ordered {word} request to {word}a {ordinal} ordered {word} request to {word} on {service}
Example:
Given a 2nd ordered GET request to /api/parcels/PX-1001Given a 1st ordered POST request to /api/parcels on parcelsrest.request.header
Section titled “rest.request.header”Given the request header {word} is {string}[[ for {ordinal} ordered request]]Set a request header.
Content-TypeandAcceptreplace an earlier value; other headers may be added more than once, and are all sent.- Without an ordinal it applies to the service’s first (default) request;
for 2nd ordered request, to its second. - It uses the default service, the first one registered;
rest.request.header.onnames a service.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{string} |
text in double or single quotes, which the step leaves out | "Get a quote", 'Express' |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
Variants, the parts in [[...]] said or left out:
the request header {word} is {string}the request header {word} is {string} for {ordinal} ordered request
Example:
Given the request header Content-Type is 'application/json'rest.request.header.on
Section titled “rest.request.header.on”Given the request header {word} is {string} for[[ {ordinal} ordered]] request on {service}rest.request.header on a named service: for request on <service> addresses the service’s first (default) request, for 2nd ordered request on <service> its second one. Everything else works like rest.request.header.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{string} |
text in double or single quotes, which the step leaves out | "Get a quote", 'Express' |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
Variants, the parts in [[...]] said or left out:
the request header {word} is {string} for request on {service}the request header {word} is {string} for {ordinal} ordered request on {service}
Example:
Given the request header Accept is 'application/json' for 1st ordered request on parcelsrest.request.headers
Section titled “rest.request.headers”Given the request headers[[ for {ordinal} ordered request]] are: | header | value |The table may start with the row naming its columns, as above, or go straight to its rows.
Set request headers, a row each.
- A name may repeat. Like the single-header step,
Content-TypeandAcceptreplace an earlier value, and other headers are all sent. - Without an ordinal it applies to the service’s first (default) request;
for 2nd ordered request, to its second. - It uses the default service, the first one registered;
rest.request.headers.onnames a service.
| Parameter | Takes | For example |
|---|---|---|
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
A row is a header’s name and its value.
Variants, the parts in [[...]] said or left out:
the request headers are:the request headers for {ordinal} ordered request are:
Example:
Given the request headers are: | Accept | application/json | | Accept-Language | de-DE |rest.request.headers.on
Section titled “rest.request.headers.on”Given the request headers for[[ {ordinal} ordered]] request on {service} are: | header | value |The table may start with the row naming its columns, as above, or go straight to its rows.
rest.request.headers on a named service: for request on <service> addresses the service’s first (default) request, for 2nd ordered request on <service> its second one. Everything else works like rest.request.headers.
| Parameter | Takes | For example |
|---|---|---|
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
A row is a header’s name and its value.
Variants, the parts in [[...]] said or left out:
the request headers for request on {service} are:the request headers for {ordinal} ordered request on {service} are:
Example:
Given the request headers for request on parcels are: | Content-Type | application/json | | Accept | application/json |rest.request.payload.empty
Section titled “rest.request.payload.empty”Given a request payload using a(n) {mimeType} empty content template[[ for {ordinal} ordered request]]Start the request payload from an empty JSON object, {}, for the payload property steps to fill.
- It needs no OpenAPI specification.
- With
application/x-www-form-urlencoded, the properties are sent form-encoded, and nested objects and arrays as JSON text. - A request takes one payload step.
- Without an ordinal it applies to the service’s first (default) request;
for 2nd ordered request, to its second. - It uses the default service, the first one registered;
rest.request.payload.empty.onnames a service.
| Parameter | Takes | Values | For example |
|---|---|---|---|
{mimeType} |
a content type | application/json, text/json, application/problem+json, application/x-www-form-urlencoded |
application/json |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
Variants, the parts in [[...]] said or left out:
a request payload using a(n) {mimeType} empty content templatea request payload using a(n) {mimeType} empty content template for {ordinal} ordered request
Example:
Given a request payload using an application/json empty content templaterest.request.payload.empty.on
Section titled “rest.request.payload.empty.on”Given a request payload using a(n) {mimeType} empty content template for[[ {ordinal} ordered]] request on {service}rest.request.payload.empty on a named service: for request on <service> addresses the service’s first (default) request, for 2nd ordered request on <service> its second one. Everything else works like rest.request.payload.empty.
| Parameter | Takes | Values | For example |
|---|---|---|---|
{mimeType} |
a content type | application/json, text/json, application/problem+json, application/x-www-form-urlencoded |
application/json |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
|
{service} |
the name of a REST service the scenario registered | parcels |
Variants, the parts in [[...]] said or left out:
a request payload using a(n) {mimeType} empty content template for request on {service}a request payload using a(n) {mimeType} empty content template for {ordinal} ordered request on {service}
Example:
Given a request payload using an application/json empty content template for request on parcelsrest.request.payload.example
Section titled “rest.request.payload.example”Given a request payload using a(n) {mimeType} content example[[ named {string}]][[ for {ordinal} ordered request]]Start the request payload from a request body example of the service’s OpenAPI specification.
- With
named '<name>'it is the example of that name; without, the first example in document order, or the media type’s singleexample. - The example is looked up under the operation that matches the request’s method and path, for the media type.
- An example with an
externalValueis read relative to the specification. - The service needs its
openapiproperty, and the request must be added first. - A request takes one payload step.
- Without an ordinal it applies to the service’s first (default) request;
for 2nd ordered request, to its second. - It uses the default service, the first one registered;
rest.request.payload.example.onnames a service.
| Parameter | Takes | Values | For example |
|---|---|---|---|
{mimeType} |
a content type | application/json, text/json, application/problem+json, application/x-www-form-urlencoded |
application/json |
{string} |
text in double or single quotes, which the step leaves out | "Get a quote", 'Express' |
|
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
Variants, the parts in [[...]] said or left out:
a request payload using a(n) {mimeType} content examplea request payload using a(n) {mimeType} content example named {string}a request payload using a(n) {mimeType} content example for {ordinal} ordered requesta request payload using a(n) {mimeType} content example named {string} for {ordinal} ordered request
Example:
Given a request payload using an application/json content example named 'Standard parcel'rest.request.payload.example.on
Section titled “rest.request.payload.example.on”Given a request payload using a(n) {mimeType} content example[[ named {string}]] for[[ {ordinal} ordered]] request on {service}rest.request.payload.example on a named service: for request on <service> addresses the service’s first (default) request, for 2nd ordered request on <service> its second one. Everything else works like rest.request.payload.example.
| Parameter | Takes | Values | For example |
|---|---|---|---|
{mimeType} |
a content type | application/json, text/json, application/problem+json, application/x-www-form-urlencoded |
application/json |
{string} |
text in double or single quotes, which the step leaves out | "Get a quote", 'Express' |
|
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
|
{service} |
the name of a REST service the scenario registered | parcels |
Variants, the parts in [[...]] said or left out:
a request payload using a(n) {mimeType} content example for request on {service}a request payload using a(n) {mimeType} content example named {string} for request on {service}a request payload using a(n) {mimeType} content example for {ordinal} ordered request on {service}a request payload using a(n) {mimeType} content example named {string} for {ordinal} ordered request on {service}
Example:
Given a request payload using an application/json content example for 1st ordered request on parcelsrest.request.payload.resource
Section titled “rest.request.payload.resource”Given a request payload using a(n) {mimeType} {filepath} resource[[ for {ordinal} ordered request]]Start the request payload from a file of the project, such as a fixture factory’s output: it is sent with the media type.
- The file is found like other files steps name: relative to the
resourcesdirectories, or to axx.yaml’s directory. - It is sent as it is, and a JSON payload can then be changed with the payload property steps. With
application/x-www-form-urlencoded, the file is a JSON object whose properties are sent form-encoded. - It needs no OpenAPI specification.
- A request takes one payload step.
- Without an ordinal it applies to the service’s first (default) request;
for 2nd ordered request, to its second. - It uses the default service, the first one registered;
rest.request.payload.resource.onnames a service.
| Parameter | Takes | Values | For example |
|---|---|---|---|
{mimeType} |
a content type | application/json, text/json, application/problem+json, application/x-www-form-urlencoded |
application/json |
{filepath} |
a file of the project: a path relative to the feature file’s directory, the resources directories or axx.yaml’s directory (looked for in that order), or an absolute path, quoted when it has a space |
seeds/parcels.yaml, kafka/scan-delivered.json |
|
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
Variants, the parts in [[...]] said or left out:
a request payload using a(n) {mimeType} {filepath} resourcea request payload using a(n) {mimeType} {filepath} resource for {ordinal} ordered request
Example:
Given a request payload using an application/json requests/order-7731.json resourcerest.request.payload.resource.on
Section titled “rest.request.payload.resource.on”Given a request payload using a(n) {mimeType} {filepath} resource for[[ {ordinal} ordered]] request on {service}rest.request.payload.resource on a named service: for request on <service> addresses the service’s first (default) request, for 2nd ordered request on <service> its second one. Everything else works like rest.request.payload.resource.
| Parameter | Takes | Values | For example |
|---|---|---|---|
{mimeType} |
a content type | application/json, text/json, application/problem+json, application/x-www-form-urlencoded |
application/json |
{filepath} |
a file of the project: a path relative to the feature file’s directory, the resources directories or axx.yaml’s directory (looked for in that order), or an absolute path, quoted when it has a space |
seeds/parcels.yaml, kafka/scan-delivered.json |
|
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
|
{service} |
the name of a REST service the scenario registered | parcels |
Variants, the parts in [[...]] said or left out:
a request payload using a(n) {mimeType} {filepath} resource for request on {service}a request payload using a(n) {mimeType} {filepath} resource for {ordinal} ordered request on {service}
Example:
Given a request payload using an application/json requests/order-7732.json resource for 2nd ordered request on parcelsrest.request.property
Section titled “rest.request.property”Given the request payload property {word} is {string}[[ for {ordinal} ordered request]]Set a property of the request payload, by its JSONPath, like weightGrams, recipient.postcode or $.recipient.name.
- A value in double quotes inside the quotes, like
'"42"', is always a string. - Any other value takes the type of the property’s current value: a string, a boolean, an integer, a number, or an object or array parsed from JSON text.
- A property that does not exist yet, or is null, takes the type its value reads as:
true,42,1.5,{...},[...], or else a string. - A property inside an object the payload lacks creates the object:
recipient.namein a payload withoutrecipient. A path through an array (items[2].sku) needs the array. - A payload step must come first.
- Without an ordinal it applies to the service’s first (default) request;
for 2nd ordered request, to its second. - It uses the default service, the first one registered;
rest.request.property.onnames a service.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{string} |
text in double or single quotes, which the step leaves out | "Get a quote", 'Express' |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
Variants, the parts in [[...]] said or left out:
the request payload property {word} is {string}the request payload property {word} is {string} for {ordinal} ordered request
Example:
Given the request payload property sender is 'kestrel-books'rest.request.property.on
Section titled “rest.request.property.on”Given the request payload property {word} is {string} for[[ {ordinal} ordered]] request on {service}rest.request.property on a named service: for request on <service> addresses the service’s first (default) request, for 2nd ordered request on <service> its second one. Everything else works like rest.request.property.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{string} |
text in double or single quotes, which the step leaves out | "Get a quote", 'Express' |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
Variants, the parts in [[...]] said or left out:
the request payload property {word} is {string} for request on {service}the request payload property {word} is {string} for {ordinal} ordered request on {service}
Example:
Given the request payload property serviceLevel is 'EXPRESS' for request on parcelsrest.request.properties
Section titled “rest.request.properties”Given the request payload properties[[ for {ordinal} ordered request]] are: | JSONPath | value |The table may start with the row naming its columns, as above, or go straight to its rows.
Set properties of the request payload, a row each, in order, like the single-property step.
nullsets JSON null, andundefinedremoves the property, in any case."null"and"undefined", in double quotes, are the strings.- A property inside an object the payload lacks creates the object, so a table can list
recipient.nameandrecipient.postcodeon an empty payload. - Without an ordinal it applies to the service’s first (default) request;
for 2nd ordered request, to its second. - It uses the default service, the first one registered;
rest.request.properties.onnames a service.
| Parameter | Takes | For example |
|---|---|---|
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
A row is a property’s JSONPath and its value.
Variants, the parts in [[...]] said or left out:
the request payload properties are:the request payload properties for {ordinal} ordered request are:
Example:
Given the request payload properties are: | reference | PX-4101 | | weightGrams | 1200 | | recipient.postcode | "53111" |rest.request.properties.on
Section titled “rest.request.properties.on”Given the request payload properties for[[ {ordinal} ordered]] request on {service} are: | JSONPath | value |The table may start with the row naming its columns, as above, or go straight to its rows.
rest.request.properties on a named service: for request on <service> addresses the service’s first (default) request, for 2nd ordered request on <service> its second one. Everything else works like rest.request.properties.
| Parameter | Takes | For example |
|---|---|---|
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
A row is a property’s JSONPath and its value.
Variants, the parts in [[...]] said or left out:
the request payload properties for request on {service} are:the request payload properties for {ordinal} ordered request on {service} are:
Example:
Given the request payload properties for 1st ordered request on parcels are: | sender | lark-ceramics | | recipient.street | undefined |rest.request.property.null
Section titled “rest.request.property.null”Given the request payload property {word} is null[[ for {ordinal} ordered request]]Set an existing property of the request payload to JSON null.
- Without an ordinal it applies to the service’s first (default) request;
for 2nd ordered request, to its second. - It uses the default service, the first one registered;
rest.request.property.null.onnames a service.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
Variants, the parts in [[...]] said or left out:
the request payload property {word} is nullthe request payload property {word} is null for {ordinal} ordered request
Example:
Given the request payload property recipient.street is nullrest.request.property.null.on
Section titled “rest.request.property.null.on”Given the request payload property {word} is null for[[ {ordinal} ordered]] request on {service}rest.request.property.null on a named service: for request on <service> addresses the service’s first (default) request, for 2nd ordered request on <service> its second one. Everything else works like rest.request.property.null.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
Variants, the parts in [[...]] said or left out:
the request payload property {word} is null for request on {service}the request payload property {word} is null for {ordinal} ordered request on {service}
Example:
Given the request payload property recipient.street is null for request on parcelsrest.execute
Section titled “rest.execute”When the[[ {ordinal} ordered]] request is executed[[ on {service}]]Send a request, and keep its response for the response steps.
- With an OpenAPI specification, the request and its response are validated after sending. Findings at level
ERRORfail the step, which lists them all with their keys;WARNandINFOfindings are logged. - The payload is sent as it is, or form-encoded for
application/x-www-form-urlencoded. - Without a
Content-Typeheader, the request has the payload’s media type; without anAcceptheader,*/*. - A GET or HEAD request follows redirects, and a request with another method a
303 See Other(with a GET): the response steps then check the response it leads to. Other redirects are the response, with theirLocationheader. - No cookies are kept: a
Set-Cookieresponse header is not sent back. Send one with theCookierequest header. - The request honors the step timeout, and is executed once.
- Without an ordinal it sends the service’s first (default) request;
the 2nd ordered request, its second. - Without
on {service}it uses the default service, the first one registered.
| Parameter | Takes | For example |
|---|---|---|
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
Variants, the parts in [[...]] said or left out:
the request is executedthe request is executed on {service}the {ordinal} ordered request is executedthe {ordinal} ordered request is executed on {service}
Example:
When the request is executedWhen the 2nd ordered request is executed on parcelsrest.response.status
Section titled “rest.response.status”Then the[[ {ordinal} ordered]] response status code is {int}[[ on {service}]]Check the HTTP status code of a response.
- Without an ordinal it checks the response to the first (default) request;
the 2nd ordered response, the response to the second. - Without
on {service}it uses the default service, the first one registered.
| Parameter | Takes | For example |
|---|---|---|
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{int} |
a whole number | 200, 3 |
{service} |
the name of a REST service the scenario registered | parcels |
Variants, the parts in [[...]] said or left out:
the response status code is {int}the response status code is {int} on {service}the {ordinal} ordered response status code is {int}the {ordinal} ordered response status code is {int} on {service}
Example:
Then the response status code is 200Then the 2nd ordered response status code is 201 on parcelsrest.response.body.contains
Section titled “rest.response.body.contains”Then the response body contains {string}[[ for {ordinal} ordered response]]Check that the response body contains the text.
- Without an ordinal it checks the response to the first (default) request;
for 2nd ordered response, the response to the second. - It uses the default service, the first one registered;
rest.response.body.contains.onnames a service.
| Parameter | Takes | For example |
|---|---|---|
{string} |
text in double or single quotes, which the step leaves out | "Get a quote", 'Express' |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
Variants, the parts in [[...]] said or left out:
the response body contains {string}the response body contains {string} for {ordinal} ordered response
Example:
Then the response body contains 'already registered'rest.response.body.contains.on
Section titled “rest.response.body.contains.on”Then the response body contains {string} for[[ {ordinal} ordered]] response on {service}rest.response.body.contains on a named service: for response on <service> addresses the service’s first (default) response, for 2nd ordered response on <service> its second one. Everything else works like rest.response.body.contains.
| Parameter | Takes | For example |
|---|---|---|
{string} |
text in double or single quotes, which the step leaves out | "Get a quote", 'Express' |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
Variants, the parts in [[...]] said or left out:
the response body contains {string} for response on {service}the response body contains {string} for {ordinal} ordered response on {service}
Example:
Then the response body contains 'already registered' for 2nd ordered response on parcelsrest.response.header.is
Section titled “rest.response.header.is”Then the response header {word} is {string}[[ for {ordinal} ordered response]]Check that a response header has the value.
- The header’s name is matched in any case.
- With the header repeated, one of its values must be the value.
- Without an ordinal it checks the response to the first (default) request;
for 2nd ordered response, the response to the second. - It uses the default service, the first one registered;
rest.response.header.is.onnames a service.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{string} |
text in double or single quotes, which the step leaves out | "Get a quote", 'Express' |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
Variants, the parts in [[...]] said or left out:
the response header {word} is {string}the response header {word} is {string} for {ordinal} ordered response
Example:
Then the response header Content-Type is 'application/json'rest.response.header.is.on
Section titled “rest.response.header.is.on”Then the response header {word} is {string} for[[ {ordinal} ordered]] response on {service}rest.response.header.is on a named service: for response on <service> addresses the service’s first (default) response, for 2nd ordered response on <service> its second one. Everything else works like rest.response.header.is.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{string} |
text in double or single quotes, which the step leaves out | "Get a quote", 'Express' |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
Variants, the parts in [[...]] said or left out:
the response header {word} is {string} for response on {service}the response header {word} is {string} for {ordinal} ordered response on {service}
Example:
Then the response header Content-Type is 'application/json' for response on parcelsrest.response.header.matches
Section titled “rest.response.header.matches”Then the response header {word} matches {pattern}[[ for {ordinal} ordered response]]Check that a response header matches a regular expression.
- The regular expression is in Java syntax, and must match the whole value.
- With the header repeated, one of its values must match.
- Without an ordinal it checks the response to the first (default) request;
for 2nd ordered response, the response to the second. - It uses the default service, the first one registered;
rest.response.header.matches.onnames a service.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{pattern} |
a regular expression (Java syntax) with no spaces, which matches the whole value | PX-\d{4}, [A-Z]{2}-\d+ |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
Variants, the parts in [[...]] said or left out:
the response header {word} matches {pattern}the response header {word} matches {pattern} for {ordinal} ordered response
Example:
Then the response header Content-Type matches ^application/json.*$rest.response.header.matches.on
Section titled “rest.response.header.matches.on”Then the response header {word} matches {pattern} for[[ {ordinal} ordered]] response on {service}rest.response.header.matches on a named service: for response on <service> addresses the service’s first (default) response, for 2nd ordered response on <service> its second one. Everything else works like rest.response.header.matches.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{pattern} |
a regular expression (Java syntax) with no spaces, which matches the whole value | PX-\d{4}, [A-Z]{2}-\d+ |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
Variants, the parts in [[...]] said or left out:
the response header {word} matches {pattern} for response on {service}the response header {word} matches {pattern} for {ordinal} ordered response on {service}
Example:
Then the response header Content-Type matches ^application/json$ for 1st ordered response on parcelsrest.response.header.missing
Section titled “rest.response.header.missing”Then the response header {word} is missing[[ for {ordinal} ordered response]]Check that the response has no header of that name.
- Without an ordinal it checks the response to the first (default) request;
for 2nd ordered response, the response to the second. - It uses the default service, the first one registered;
rest.response.header.missing.onnames a service.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
Variants, the parts in [[...]] said or left out:
the response header {word} is missingthe response header {word} is missing for {ordinal} ordered response
Example:
Then the response header Content-Length is missingrest.response.header.missing.on
Section titled “rest.response.header.missing.on”Then the response header {word} is missing for[[ {ordinal} ordered]] response on {service}rest.response.header.missing on a named service: for response on <service> addresses the service’s first (default) response, for 2nd ordered response on <service> its second one. Everything else works like rest.response.header.missing.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
Variants, the parts in [[...]] said or left out:
the response header {word} is missing for response on {service}the response header {word} is missing for {ordinal} ordered response on {service}
Example:
Then the response header Retry-After is missing for response on parcelsrest.response.headers.are
Section titled “rest.response.headers.are”Then the response headers[[ for {ordinal} ordered response]] are: | header | value |The table may start with the row naming its columns, as above, or go straight to its rows.
Check response headers, a row each, like the single-header step.
- A name may repeat.
- Every row is checked, and every mismatch reported.
- Without an ordinal it checks the response to the first (default) request;
for 2nd ordered response, the response to the second. - It uses the default service, the first one registered;
rest.response.headers.are.onnames a service.
| Parameter | Takes | For example |
|---|---|---|
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
A row is a header’s name and the value it must have.
Variants, the parts in [[...]] said or left out:
the response headers are:the response headers for {ordinal} ordered response are:
Example:
Then the response headers are: | Content-Type | application/json | | Location | /api/parcels/PX-4101 |rest.response.headers.are.on
Section titled “rest.response.headers.are.on”Then the response headers for[[ {ordinal} ordered]] response on {service} are: | header | value |The table may start with the row naming its columns, as above, or go straight to its rows.
rest.response.headers.are on a named service: for response on <service> addresses the service’s first (default) response, for 2nd ordered response on <service> its second one. Everything else works like rest.response.headers.are.
| Parameter | Takes | For example |
|---|---|---|
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
A row is a header’s name and the value it must have.
Variants, the parts in [[...]] said or left out:
the response headers for response on {service} are:the response headers for {ordinal} ordered response on {service} are:
Example:
Then the response headers for 1st ordered response on parcels are: | Content-Type | application/problem+json | | Retry-After | 5 |rest.response.headers.match
Section titled “rest.response.headers.match”Then the response headers[[ for {ordinal} ordered response]] match: | header | regular expression |The table may start with the row naming its columns, as above, or go straight to its rows.
Check that response headers match regular expressions, a row each.
- Each regular expression is in Java syntax, and must match the whole value.
- Every row is checked, and every mismatch reported.
- Without an ordinal it checks the response to the first (default) request;
for 2nd ordered response, the response to the second. - It uses the default service, the first one registered;
rest.response.headers.match.onnames a service.
| Parameter | Takes | For example |
|---|---|---|
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
A row is a header’s name and a regular expression its value must match.
Variants, the parts in [[...]] said or left out:
the response headers match:the response headers for {ordinal} ordered response match:
Example:
Then the response headers match: | Content-Type | application/json.* | | Location | /api/parcels/PX-[0-9]{4} |rest.response.headers.match.on
Section titled “rest.response.headers.match.on”Then the response headers for[[ {ordinal} ordered]] response on {service} match: | header | regular expression |The table may start with the row naming its columns, as above, or go straight to its rows.
rest.response.headers.match on a named service: for response on <service> addresses the service’s first (default) response, for 2nd ordered response on <service> its second one. Everything else works like rest.response.headers.match.
| Parameter | Takes | For example |
|---|---|---|
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
A row is a header’s name and a regular expression its value must match.
Variants, the parts in [[...]] said or left out:
the response headers for response on {service} match:the response headers for {ordinal} ordered response on {service} match:
Example:
Then the response headers for response on parcels match: | Retry-After | [0-9]+ |rest.response.headers.missing
Section titled “rest.response.headers.missing”Then the response headers[[ for {ordinal} ordered response]] are missing: | header |Check that the response has none of the headers the table names.
- Without an ordinal it checks the response to the first (default) request;
for 2nd ordered response, the response to the second. - It uses the default service, the first one registered;
rest.response.headers.missing.onnames a service.
| Parameter | Takes | For example |
|---|---|---|
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
A row names a header, in its first cell.
Variants, the parts in [[...]] said or left out:
the response headers are missing:the response headers for {ordinal} ordered response are missing:
Example:
Then the response headers are missing: | Retry-After | | Set-Cookie |rest.response.headers.missing.on
Section titled “rest.response.headers.missing.on”Then the response headers for[[ {ordinal} ordered]] response on {service} are missing: | header |rest.response.headers.missing on a named service: for response on <service> addresses the service’s first (default) response, for 2nd ordered response on <service> its second one. Everything else works like rest.response.headers.missing.
| Parameter | Takes | For example |
|---|---|---|
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
A row names a header, in its first cell.
Variants, the parts in [[...]] said or left out:
the response headers for response on {service} are missing:the response headers for {ordinal} ordered response on {service} are missing:
Example:
Then the response headers for response on parcels are missing: | Retry-After |rest.response.property.is
Section titled “rest.response.property.is”Then the response payload property {word} is {string}[[ for {ordinal} ordered response]]Check a property of a JSON response, by its JSONPath, like status, recipient.postcode or [?(@.sender=='kestrel-books')].reference.
- An indefinite path, like a filter, reads as a list.
- The response must be JSON:
application/json,text/jsonor any+jsontype, whatever its charset. - A value is compared with its JSON type. Text, like
REGISTERED, is a string, and so is a value in double quotes, like"42". 42is an integer,42La long and1.5a number. An integer never equals a decimal:5is not5.0.trueandfalseare booleans.{...}and[...]are a JSON object and a JSON array; an object’s members may come in any order.- Without an ordinal it checks the response to the first (default) request;
for 2nd ordered response, the response to the second. - It uses the default service, the first one registered;
rest.response.property.is.onnames a service.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{string} |
text in double or single quotes, which the step leaves out | "Get a quote", 'Express' |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
Variants, the parts in [[...]] said or left out:
the response payload property {word} is {string}the response payload property {word} is {string} for {ordinal} ordered response
Example:
Then the response payload property status is 'REGISTERED'rest.response.property.is.on
Section titled “rest.response.property.is.on”Then the response payload property {word} is {string} for[[ {ordinal} ordered]] response on {service}rest.response.property.is on a named service: for response on <service> addresses the service’s first (default) response, for 2nd ordered response on <service> its second one. Everything else works like rest.response.property.is.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{string} |
text in double or single quotes, which the step leaves out | "Get a quote", 'Express' |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
Variants, the parts in [[...]] said or left out:
the response payload property {word} is {string} for response on {service}the response payload property {word} is {string} for {ordinal} ordered response on {service}
Example:
Then the response payload property status is 'REGISTERED' for 1st ordered response on parcelsrest.response.property.null
Section titled “rest.response.property.null”Then the response payload property {word} is null[[ for {ordinal} ordered response]]Check that a property of the response payload exists, and is JSON null.
- Without an ordinal it checks the response to the first (default) request;
for 2nd ordered response, the response to the second. - It uses the default service, the first one registered;
rest.response.property.null.onnames a service.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
Variants, the parts in [[...]] said or left out:
the response payload property {word} is nullthe response payload property {word} is null for {ordinal} ordered response
Example:
Then the response payload property lastLocation is nullrest.response.property.null.on
Section titled “rest.response.property.null.on”Then the response payload property {word} is null for[[ {ordinal} ordered]] response on {service}rest.response.property.null on a named service: for response on <service> addresses the service’s first (default) response, for 2nd ordered response on <service> its second one. Everything else works like rest.response.property.null.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
Variants, the parts in [[...]] said or left out:
the response payload property {word} is null for response on {service}the response payload property {word} is null for {ordinal} ordered response on {service}
Example:
Then the response payload property lastLocation is null for response on parcelsrest.response.property.undefined
Section titled “rest.response.property.undefined”Then the response payload property {word} is undefined[[ for {ordinal} ordered response]]Check that a property of the response payload does not exist.
- An indefinite path always exists: it reads as a list, which may be empty.
- Without an ordinal it checks the response to the first (default) request;
for 2nd ordered response, the response to the second. - It uses the default service, the first one registered;
rest.response.property.undefined.onnames a service.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
Variants, the parts in [[...]] said or left out:
the response payload property {word} is undefinedthe response payload property {word} is undefined for {ordinal} ordered response
Example:
Then the response payload property recipient.street is undefinedrest.response.property.undefined.on
Section titled “rest.response.property.undefined.on”Then the response payload property {word} is undefined for[[ {ordinal} ordered]] response on {service}rest.response.property.undefined on a named service: for response on <service> addresses the service’s first (default) response, for 2nd ordered response on <service> its second one. Everything else works like rest.response.property.undefined.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
Variants, the parts in [[...]] said or left out:
the response payload property {word} is undefined for response on {service}the response payload property {word} is undefined for {ordinal} ordered response on {service}
Example:
Then the response payload property recipient.street is undefined for 1st ordered response on parcelsrest.response.property.matches
Section titled “rest.response.property.matches”Then the response payload property {word} matches {pattern}[[ for {ordinal} ordered response]]Check that a property of the response payload is a string that matches a regular expression.
- The regular expression is in Java syntax, and must match the whole value.
- Without an ordinal it checks the response to the first (default) request;
for 2nd ordered response, the response to the second. - It uses the default service, the first one registered;
rest.response.property.matches.onnames a service.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{pattern} |
a regular expression (Java syntax) with no spaces, which matches the whole value | PX-\d{4}, [A-Z]{2}-\d+ |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
Variants, the parts in [[...]] said or left out:
the response payload property {word} matches {pattern}the response payload property {word} matches {pattern} for {ordinal} ordered response
Example:
Then the response payload property barcode matches ^PX[0-9]{11}$rest.response.property.matches.on
Section titled “rest.response.property.matches.on”Then the response payload property {word} matches {pattern} for[[ {ordinal} ordered]] response on {service}rest.response.property.matches on a named service: for response on <service> addresses the service’s first (default) response, for 2nd ordered response on <service> its second one. Everything else works like rest.response.property.matches.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{pattern} |
a regular expression (Java syntax) with no spaces, which matches the whole value | PX-\d{4}, [A-Z]{2}-\d+ |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
Variants, the parts in [[...]] said or left out:
the response payload property {word} matches {pattern} for response on {service}the response payload property {word} matches {pattern} for {ordinal} ordered response on {service}
Example:
Then the response payload property barcode matches ^PX[0-9]{11}$ for response on parcelsrest.response.properties.are
Section titled “rest.response.properties.are”Then the response payload properties[[ for {ordinal} ordered response]] are: | JSONPath | value |The table may start with the row naming its columns, as above, or go straight to its rows.
Check properties of a JSON response, a row each, like the single-property step.
nullandundefined, in any case, check for JSON null and for no such property;"null", in double quotes, is the string.- Every row is checked, and every mismatch reported.
- A value is compared with its JSON type. Text, like
REGISTERED, is a string, and so is a value in double quotes, like"42". 42is an integer,42La long and1.5a number. An integer never equals a decimal:5is not5.0.trueandfalseare booleans.{...}and[...]are a JSON object and a JSON array; an object’s members may come in any order.- Without an ordinal it checks the response to the first (default) request;
for 2nd ordered response, the response to the second. - It uses the default service, the first one registered;
rest.response.properties.are.onnames a service.
| Parameter | Takes | For example |
|---|---|---|
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
A row is a property’s JSONPath and the value it must have.
Variants, the parts in [[...]] said or left out:
the response payload properties are:the response payload properties for {ordinal} ordered response are:
Example:
Then the response payload properties are: | reference | PX-4101 | | status | REGISTERED | | zone | DE-1 |rest.response.properties.are.on
Section titled “rest.response.properties.are.on”Then the response payload properties for[[ {ordinal} ordered]] response on {service} are: | JSONPath | value |The table may start with the row naming its columns, as above, or go straight to its rows.
rest.response.properties.are on a named service: for response on <service> addresses the service’s first (default) response, for 2nd ordered response on <service> its second one. Everything else works like rest.response.properties.are.
| Parameter | Takes | For example |
|---|---|---|
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
A row is a property’s JSONPath and the value it must have.
Variants, the parts in [[...]] said or left out:
the response payload properties for response on {service} are:the response payload properties for {ordinal} ordered response on {service} are:
Example:
Then the response payload properties for 1st ordered response on parcels are: | serviceLevel | STANDARD | | recipient.name | Ada Lovelace | | recipient.street | undefined |rest.response.properties.match
Section titled “rest.response.properties.match”Then the response payload properties[[ for {ordinal} ordered response]] match: | JSONPath | regular expression |The table may start with the row naming its columns, as above, or go straight to its rows.
Check that properties of the response payload are strings that match regular expressions, a row each.
- Each regular expression is in Java syntax, and must match the whole value.
- Every row is checked, and every mismatch reported.
- Without an ordinal it checks the response to the first (default) request;
for 2nd ordered response, the response to the second. - It uses the default service, the first one registered;
rest.response.properties.match.onnames a service.
| Parameter | Takes | For example |
|---|---|---|
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
A row is a property’s JSONPath and a regular expression its value must match.
Variants, the parts in [[...]] said or left out:
the response payload properties match:the response payload properties for {ordinal} ordered response match:
Example:
Then the response payload properties match: | barcode | ^PX[0-9]{11}$ | | signature | ^[0-9a-f]{64}$ |rest.response.properties.match.on
Section titled “rest.response.properties.match.on”Then the response payload properties for[[ {ordinal} ordered]] response on {service} match: | JSONPath | regular expression |The table may start with the row naming its columns, as above, or go straight to its rows.
rest.response.properties.match on a named service: for response on <service> addresses the service’s first (default) response, for 2nd ordered response on <service> its second one. Everything else works like rest.response.properties.match.
| Parameter | Takes | For example |
|---|---|---|
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
A row is a property’s JSONPath and a regular expression its value must match.
Variants, the parts in [[...]] said or left out:
the response payload properties for response on {service} match:the response payload properties for {ordinal} ordered response on {service} match:
Example:
Then the response payload properties for 2nd ordered response on parcels match: | [0].reference | PX-[0-9]{4} |rest.token
Section titled “rest.token”Given the {word} token with the following properties: | property | value |The table may start with the row naming its columns, as above, or go straight to its rows.
Register a bearer token under a name: a JSON Web Token Axx signs, or an OAuth 2.0 client credentials token Axx gets from a token endpoint.
- A request uses it with
the request is authorized with the {word} token; the steps of other packs that take header rows, like the websocket and sse packs, with${token:<name>}. - A JSON Web Token is signed each time it is used, with
iatandexpfrom then; the claims of the table add to them or replace them. - A client credentials token is got once for the run, and again once it expires.
- Values expand
${env:..}and${sys:..}; the token and its secrets are masked in logs and failures.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
| Property | Takes | Values | Default |
|---|---|---|---|
algorithm |
how Axx signs a JSON Web Token | HS256, HS384, HS512, RS256, ES256 |
HS256 |
key |
the secret an HS token is signed with, like ${env:SHOP_TOKEN_KEY}, or the PEM private key (a file of the project) of an RS or ES token |
||
key id |
the kid in the token’s header |
||
claim.<name> |
a claim of the token: a JSON value (true, 42, ["parcels:read"]) or text |
||
expires in |
how long the token lasts from when it is used, like 5m |
5m |
|
token url |
an OAuth 2.0 token endpoint Axx gets a client credentials token from, instead of signing one | ||
client id |
the client’s ID, for the token endpoint | ||
client secret |
the client’s secret, like ${env:SHOP_CLIENT_SECRET} |
||
scope |
the scopes asked for, separated by spaces | ||
audience |
the API the token is for, for token endpoints that ask for one |
Give a key for a token Axx signs, or a token url, client id and client secret for one it gets, not both.
Example:
Given the shop token with the following properties: | key | ${env:SHOP_TOKEN_KEY} | | claim.shop | maple-crafts |Given the shop-system token with the following properties: | token url | http://localhost:8400/oauth/token | | client id | maple-crafts | | client secret | ${env:SHOP_CLIENT_SECRET} | | scope | parcels:read |Since 0.1.5.
rest.request.token
Section titled “rest.request.token”Given the request is authorized with the {word} token[[ for {ordinal} ordered request]]Send the request with the token of that name: Authorization: Bearer <token>.
- The token is had when the request is executed: a JSON Web Token is signed then.
- Without an ordinal it applies to the service’s first (default) request;
for 2nd ordered request, to its second. - It uses the default service, the first one registered;
rest.request.token.onnames a service.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
Variants, the parts in [[...]] said or left out:
the request is authorized with the {word} tokenthe request is authorized with the {word} token for {ordinal} ordered request
Example:
Given the request is authorized with the shop tokenSince 0.1.5.
rest.request.token.on
Section titled “rest.request.token.on”Given the request is authorized with the {word} token for[[ {ordinal} ordered]] request on {service}rest.request.token on a named service: for request on <service> addresses the service’s first (default) request, for 2nd ordered request on <service> its second one. Everything else works like rest.request.token.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
Variants, the parts in [[...]] said or left out:
the request is authorized with the {word} token for request on {service}the request is authorized with the {word} token for {ordinal} ordered request on {service}
Example:
Given the request is authorized with the shop token for 2nd ordered request on parcelsSince 0.1.5.
rest.request.signed
Section titled “rest.request.signed”Given the request is signed in the {word} header[[ for {ordinal} ordered request]] with the following properties: | property | value |The table may start with the row naming its columns, as above, or go straight to its rows.
Sign the request as webhooks are signed: an HMAC of its body, or of what the signs template gives, in the header.
- The signature is made when the request is executed, over the body as it is sent.
sha256={signature}is GitHub’s form;t={timestamp},v1={signature}with{timestamp}.{body}signed, Stripe’s.- The key expands
${env:..}, and is masked. - Without an ordinal it applies to the service’s first (default) request;
for 2nd ordered request, to its second. - It uses the default service, the first one registered;
rest.request.signed.onnames a service.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
| Property | Takes | Values | Default |
|---|---|---|---|
key |
the secret the signature is made with, like ${env:COURIER_WEBHOOK_KEY} |
required | |
algorithm |
the HMAC | hmac-sha256, hmac-sha1, hmac-sha512 |
hmac-sha256 |
signs |
what is signed: a template of {body}, {timestamp} (Unix seconds), {method} and {path} (with the query), like {timestamp}.{body} |
{body} |
|
encoding |
how the signature is written | hex, base64 |
hex |
value |
the header’s value: a template of {signature} and {timestamp}, like sha256={signature} or t={timestamp},v1={signature} |
{signature} |
|
timestamp header |
a header that also carries {timestamp}, as Slack’s X-Slack-Request-Timestamp does |
Variants, the parts in [[...]] said or left out:
the request is signed in the {word} header with the following properties:the request is signed in the {word} header for {ordinal} ordered request with the following properties:
Example:
Given the request is signed in the X-Courier-Signature header with the following properties: | key | ${env:COURIER_WEBHOOK_KEY} | | value | sha256={signature} |Since 0.1.5.
rest.request.signed.on
Section titled “rest.request.signed.on”Given the request is signed in the {word} header for[[ {ordinal} ordered]] request on {service} with the following properties: | property | value |The table may start with the row naming its columns, as above, or go straight to its rows.
rest.request.signed on a named service: for request on <service> addresses the service’s first (default) request, for 2nd ordered request on <service> its second one. Everything else works like rest.request.signed.
| Parameter | Takes | For example |
|---|---|---|
{word} |
one word, with no spaces | parcels, PX-4101 |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
| Property | Takes | Values | Default |
|---|---|---|---|
key |
the secret the signature is made with, like ${env:COURIER_WEBHOOK_KEY} |
required | |
algorithm |
the HMAC | hmac-sha256, hmac-sha1, hmac-sha512 |
hmac-sha256 |
signs |
what is signed: a template of {body}, {timestamp} (Unix seconds), {method} and {path} (with the query), like {timestamp}.{body} |
{body} |
|
encoding |
how the signature is written | hex, base64 |
hex |
value |
the header’s value: a template of {signature} and {timestamp}, like sha256={signature} or t={timestamp},v1={signature} |
{signature} |
|
timestamp header |
a header that also carries {timestamp}, as Slack’s X-Slack-Request-Timestamp does |
Variants, the parts in [[...]] said or left out:
the request is signed in the {word} header for request on {service} with the following properties:the request is signed in the {word} header for {ordinal} ordered request on {service} with the following properties:
Example:
Given the request is signed in the Stripe-Signature header for request on parcels with the following properties: | key | ${env:PAYMENTS_WEBHOOK_KEY} | | signs | {timestamp}.{body} | | value | t={timestamp},v1={signature} |Since 0.1.5.
rest.request.webhook
Section titled “rest.request.webhook”Given the request is signed as a standard webhook with the key {string}[[ for {ordinal} ordered request]]Sign the request as a Standard Webhook (standardwebhooks.com): its webhook-id, webhook-timestamp and webhook-signature headers.
- The key is
whsec_and the key in base64, as Standard Webhooks give it; it expands${env:..}, and is masked. - The signature is made when the request is executed, over the body as it is sent.
- Without an ordinal it applies to the service’s first (default) request;
for 2nd ordered request, to its second. - It uses the default service, the first one registered;
rest.request.webhook.onnames a service.
| Parameter | Takes | For example |
|---|---|---|
{string} |
text in double or single quotes, which the step leaves out | "Get a quote", 'Express' |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
Variants, the parts in [[...]] said or left out:
the request is signed as a standard webhook with the key {string}the request is signed as a standard webhook with the key {string} for {ordinal} ordered request
Example:
Given the request is signed as a standard webhook with the key '${env:SHOP_WEBHOOK_KEY}'Since 0.1.5.
rest.request.webhook.on
Section titled “rest.request.webhook.on”Given the request is signed as a standard webhook with the key {string} for[[ {ordinal} ordered]] request on {service}rest.request.webhook on a named service: for request on <service> addresses the service’s first (default) request, for 2nd ordered request on <service> its second one. Everything else works like rest.request.webhook.
| Parameter | Takes | For example |
|---|---|---|
{string} |
text in double or single quotes, which the step leaves out | "Get a quote", 'Express' |
{ordinal} |
a position, counting from 1; an optional ordinal left out is the first | 1st, 2nd |
{service} |
the name of a REST service the scenario registered | parcels |
Variants, the parts in [[...]] said or left out:
the request is signed as a standard webhook with the key {string} for request on {service}the request is signed as a standard webhook with the key {string} for {ordinal} ordered request on {service}
Example:
Given the request is signed as a standard webhook with the key '${env:SHOP_WEBHOOK_KEY}' for request on shopsSince 0.1.5.
Parameter types
Section titled “Parameter types”| Parameter | Takes | Values | For example |
|---|---|---|---|
{service} |
the name of a REST service the scenario registered | parcels |