04 - Validating & Testing Data
Continuing from the previous section, we will now look at understanding how we can validate our incoming input data, or any data involved in action.
This section briefly starts to show you how we can build workflows by controlling the order of actions.
Assertions
A highly configurable assertion & test framework is built into the platform for you to leverage, see all the available options here.
Steps
1. HTTP GET API with Input Validation
In this simple example we will be creating a HTTP GET API where we will validate the input data and then call another API endpoint and use a query parameter to specify an id parameter to fetch a specific comment.
Deploy via Hosted / Managed
- Ensure you are logged into https://app.airpipe.io
- Click Deploy
to load the below example config into your account
- Alternatively, go to Configurations > Add New, and copy and paste the example
 
Deploy via Self Hosted / Unmanaged
- A configsdirectory should have been created automatically for you, else create one.
- Copy the below example config into your configsdirectory, eg.configs/04-http-get-validate.yml
- Stop/Start airpipeeg../airpipe server --api-key your-api-key --config-dir configs
Example Config
Deployloading...
Test
Hosted mode, either navigate to or curl:
- 
The load configuration UI will automatically show you what your detected routes are, you can copy this for the next steps. 
- 
The link is automatically built with your organization uuid and environment, your API endpoints can be found here if required https://app.airpipe.io/configurations. 
- 
Update the route as necessary 
curl https://api.airpipe.io/your_org_id/staging/tutorial/validate?id=1&first=panther
Self hosted mode, either navigate to or curl:
http://0.0.0.0:4111/tutorial/validate?id=1&first=panther
curl http://0.0.0.0:4111/tutorial/validate?id=1&first=panther
Observations
If you used the exact same query parameters as supplied above, you will get the below response, where an errors parameter has now been added and indicates the first value has failed validation.
The id existed and did not throw an error, and was succesfully used in the subsequent action GetData.
Response
{
  "data": {
    "CheckParams": {
      "data": {
        "first": "panther",
        "id": "1"
      },
      "errors": [
        "first::is_less_than: expected target panther not less than 5"
      ],
      "time.ms": 0
    },
    "GetData": {
      "data": {
        "body": {
          "body": "laudantium enim quasi est quidem magnam voluptate ipsam eos\ntempora quo necessitatibus\ndolor quam autem quasi\nreiciendis et nam sapiente accusantium",
          "email": "Eliseo@gardner.biz",
          "id": 1,
          "name": "id labore ex et quam laborum",
          "postId": 1
        },
        "headers": {
          "accept-ranges": "bytes",
          "access-control-allow-credentials": "true",
          "age": "7758",
          "alt-svc": "h3=\":443\"; ma=86400",
          "cache-control": "max-age=43200",
          "cf-cache-status": "HIT",
          "cf-ray": "883c4494f9a981c4-IAD",
          "content-length": "268",
          "content-type": "application/json; charset=utf-8",
          "date": "Tue, 14 May 2024 16:29:34 GMT",
          "etag": "W/\"10c-KJ4I9RM/+33TKdV8CFsIvqsDSP0\"",
          "expires": "-1",
          "nel": "{\"report_to\":\"heroku-nel\",\"max_age\":3600,\"success_fraction\":0.005,\"failure_fraction\":0.05,\"response_headers\":[\"Via\"]}",
          "pragma": "no-cache",
          "report-to": "{\"group\":\"heroku-nel\",\"max_age\":3600,\"endpoints\":[{\"url\":\"https://nel.heroku.com/reports?ts=1715432434&sid=e11707d5-02a7-43ef-b45e-2cf4d2036f7d&s=unAGx%2FNj2kC7aw%2BJo6jqZ5aN559MvyKIxP1xTVZgHcw%3D\"}]}",
          "reporting-endpoints": "heroku-nel=https://nel.heroku.com/reports?ts=1715432434&sid=e11707d5-02a7-43ef-b45e-2cf4d2036f7d&s=unAGx%2FNj2kC7aw%2BJo6jqZ5aN559MvyKIxP1xTVZgHcw%3D",
          "server": "cloudflare",
          "vary": "Origin, Accept-Encoding",
          "via": "1.1 vegur",
          "x-content-type-options": "nosniff",
          "x-powered-by": "Express",
          "x-ratelimit-limit": "1000",
          "x-ratelimit-remaining": "999",
          "x-ratelimit-reset": "1715432467"
        },
        "status": 200
      },
      "time.ms": 33
    }
  }
}
2. Perform action on success
We will build upon the prior example and make a simple change from depends_on to run_when_succeeded to enforce that the first action should be successful before continuing to the next.
Deploy via Hosted / Managed
- Ensure you are logged into https://app.airpipe.io
- Click Deploy
to load the below example config into your account
- Alternatively, go to Configurations > Add New, and copy and paste the example
 
Deploy via Self Hosted / Unmanaged
- A configsdirectory should have been created automatically for you, else create one.
- Copy the below example config into your configsdirectory, eg.configs/04-http-get-validate.yml
- Stop/Start airpipeeg../airpipe server --api-key your-api-key --config-dir configs
Example Config
Deployloading...
Test
Hosted mode, either navigate to or curl:
- 
The load configuration UI will automatically show you what your detected routes are, you can copy this for the next steps. 
- 
The link is automatically built with your organization uuid and environment, your API endpoints can be found here if required https://app.airpipe.io/configurations. 
- 
Update the route as necessary 
curl https://api.airpipe.io/your_org_id/staging/tutorial/validate-success?id=1&first=panther
Self hosted mode, either navigate to or curl:
http://0.0.0.0:4111/tutorial/validate-success?id=1&first=panther
curl http://0.0.0.0:4111/tutorial/validate-success?id=1&first=panther
Observations
If you used the exact same query parameters as supplied above, you will get the below response, where an errors parameter has now been added and indicates the first value has failed validation.
Additionally you will now see that the GetData action was not performed and returned an error stating that CheckParams did not succeed.
If you update the first parameter for eg. from panther to leo, you will notice that the GetData action will be performed with no errors returned.
Failure Response
{
  "data": {
    "CheckParams": {
      "data": {
        "first": "panther",
        "id": "1"
      },
      "errors": [
        "first::is_less_than: expected target panther not less than 5"
      ],
      "time.ms": 0
    },
    "GetData": {
      "data": null,
      "error": "previous action 'CheckParams' did not succeed",
      "time.ms": 0
    }
  }
}
2. Perform action on failure
Simply update depends_on or run_when_succeeded to run_when_failed.
3. Advanced combination use cases
It is completely possible to use depends_on, run_when_succeeded and run_when_failed together in a single action.
This is completely dependent on your own circumstances.
4. All assertion and test configuration
Review the assertion section here.