The APId tests are configured using one or more YAML
files. These YAML
files define what checks and what steps each check has to perform.
For more information on how to setup your environment, please follow our installation guide.
An APId configuration file consists of variables and transactions which in turn consist of steps. Variables are pieces of data that can be referenced in multiple transactions. Steps are the basic elements of the configuration. They specify how to make a request and then how to validate its response. Transactions bundle steps together to help you represent meaningful stories.
Please refer to cloud reference.
APId has variables that can be inplaced throughout your steps and transactions. Variables can be declared for the transaction or step scope or be global. They can also come from the environment, which can be handy for things like secrets and passwords, or from a response from your API.
Variables are scoped either globally, to a transaction or to a step. Variables in a narrower scope have precedence over those in a broader one. Variables are available in templates - "{{ var.api_url }}"
. Make sure to add quotes to it so that the YAML parser doesn't confuse it for a YAML object.
These are declared either in the transaction, step or the root yaml document. There they are simply declared as a mapping from variable name to its value. Those will be available in templates using the var
prefix - "{{ var.api_url }}"
Each step can export a set of variables. This is useful when you want to make a request and then use part of the response in another request. For example, when you authenticate to get a token and then use this token in subsequent requests. See step about the exact syntax of exporting variables in a step. Exported variables will be available in subsequent steps by using the step id that exported them; e.g "{{ step_one.auth_token }}"
These will contain anything environment variable that the APId CLI has inherited. Useful for injecting passwords or other kinds of secrets. They will be available like so: "{{ env.PASSWORD }}"
variables:title: "A long time ago"subtitle: "in a {{ var.place }} far far away {{ env.DATABASE_USER }} accidentally dropped all tables"year: 2187
Commands are a familiar way to manipulate variables. They allow you to run shell commands and use their output. There are practically no limitations as to what you can do.
The syntax for commands is very similar to the syntax of variables, but instead of using {{
and }}
as as delimiters, it uses `
. For example
{$ echo $ENV_VARIABLE $}`
Commands are executed in the default shell (defined in $SHELL
), or /bin/sh
if none is set.
You can use whatever commands you want, obviously you need to have them set up on you dev machine / build server.
The default docker image of APId is using alpine as the base image, therefore, it has very few executables pre-installed. If you need a more versatile docker image, feel free to build your own.
You can use step and transaction variables from within commands. All the variables are exported for use in commands as $VAR_CAPITALIZEDNAMEOFVARIABLE
, e.g if you want to use "{{ step_one.auth_token }}"
in a command, you'd use `
. Another example might be, which will be available as
`. Note that dashes are replaced with underscores because most shells don't accept dashes inside variable names.
steps:request:endpoint: "{{ var.api_url }}/avengers/{% curl https://dynamic-avengers-api.io/random-avenger-id %}"
The configuration files are the single thing that defines your tests. You can have more than one config file, though in this case you need to provide the directory with config files to APId - apid check -c /dir/to/configs/
. When providing multiple config files you can reference root variables defined in other files, however you can't reference transactions from other files.
Field | Type | Required | Description |
variables | ​ | no | Globally scoped variables |
transactions | ​ | yes | A list of transactions to execute |
A transaction is a list of steps which are executed sequentially. If a step fails, the whole transaction and the other steps in the transaction are not executed.
id: "transaction-one"variables:api_url: "https://jsonplaceholder.typicode.com"steps:- id: "todos-1"request:method: "GET"endpoint: "{{ var.api_url }}/todos/1"
A matrix allows running the same transaction with different variables. Different combinations of the variables will be generated and the transaction will be ran with all of them. The order in which they are generated is not guaranteed.
The below will send four different requests in four different transactions.
id: transactionmatrix:api_url:- "http://localhost:8080"- "https://jsonplaceholder.typicode.com"todo_id:- 1- 2steps:- id: todosrequest:method: GETendpoint: "{{ var.api_url }}/todos/{{ var.todo_id }}"
The different transactions and requests:
todos-1: GET http://localhost:8080/todos/1
todos-2: GET http://localhost:8080/todos/2
todos-3: GET https://jsonplaceholder.typicode.com/todos/1
todos-4: GET https://jsonplaceholder.typicode.com/todos/2
A step is a call to a single endpoint with optional validation of the response.
Field | Type | Required | Description |
id | string | yes | A string to uniquely identify a step within a transaction |
variables | ​ | no | Variables scoped to this step |
request | ​ | yes | The request to send |
expect | ​ | no | How to validate the response |
export | ​ | no | Data to export from this step as variables to be used in other steps |
skip_ssl_verify | bool | no | Skip SSL certificate verification on this step |
steps:- id: "get user with id 1"variables:api_url: "http://localhost:80"request:method: "GET"endpoint: "{{ var.api_url }}/users/1"expect:code: 200body:type: "json"content: |{"first_name": "Bobby","last_name": "Hounslow","address": {"postcode": "TW4 7AE","country": "UK",}}export:auth_header: "response.headers.X-APIDAUTH"auth_token: "response.body.access_token"
Request specifies what request to make - which endpoint to go to, what body to use, etc.
Field | Type | Required | Description |
method | string | yes | The HTTP method of the request |
endpoint | string | yes | The URL of the request |
headers | mapping | no | Headers to attach to the request. Keys may repeat. If keys repeat, all the values are added to the header. |
body | string | no | A string of the body of the request |
request:method: "GET"endpoint: "http://https://jsonplaceholder.typicode.com/posts/1"headers:X-APIDAUTH: "{{ env.AUTH_TOKEN }}"Accept: "application/json"Accept: "application/ld+json"Accept:- "application/json"- "application/ld+json"
Expect will define what we are expecting as a valid response from the API.
Field | Type | Required | Description |
code | int | no | The status code of the response |
headers | mapping | no | What headers to expect |
body | ​[]body​ | no | What body to expect |
expect:code: 200headers:Accept: "application/json"
Body provides a bit more flexibility on what body to expect in this response.
Field | Type | Required | default | Description |
is | string | yes | ​ | What content of the body (or selector content) to expect |
selector | string | no | - | A selector to get part of the body. The underlying implementation is using |
subset | bool | no | no | If the |
keys_only | bool | no | no | If values should be disregarded when checking for equality. All types of values except objects are ignored. Objects will still be recursively checked. See examples. |
expect:body:- is: |{"name": {"first": "Tom", "last": "Anderson"},"age":37,"children": ["Sara","Alex","Jack"],"fav.movie": "Deer Hunter","friends": [{"first": "Dale", "last": "Murphy", "age": 44, "nets": ["ig", "fb", "tw"]},{"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]},{"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]}]}- selector: nameis: |{"first": "Tom","last": "Anderson"}​- selector: namekeys_only: trueis: |{"first": "Something, but not Tom","last": "not Anderson"}​- selector: namesubset: truekeys_only: trueis: |{"first": "Something, but not Tom"}​- selector: namesubset: trueis: |{"first": "Tom"}​- selector: friends.#.firstis: |["Dale","Jane","Roger"]​- selector: friends.#.firstsubset: trueis: |["Rojer"]
SSL verification can be skipped on all steps in a APId config (suite). Specify the skip_ssl_verify: True
field at the root of the config and it will be applied to all steps. If a step has that field specified already, the step's field will take precedence.