QuadrastackQuadrastack
Documentation

Docs

Assertions (Compact DSL)

Master the Compact DSL for powerful response validation

Assertions (Compact DSL)

Learn Quadrastack's powerful inline assertion syntax for validating HTTP responses.

Overview

The expect field validates responses using our Compact DSL - a concise, readable syntax for expressing assertions. Unlike traditional testing frameworks that require verbose code, the Compact DSL lets you write assertions inline in YAML.

Basic Structure

requests:
  get-users:
    method: GET
    url: https://api.example.com/users
    expect:                    # Assertions start here
      status: 200              # Status code assertion
      headers:                 # Header assertions
        Content-Type: contains application/json
      body:                    # Body assertions (JSONPath)
        $.length: "> 0"
        $.is: exists
      responseTime: "< 500ms"  # Response time assertion

Operators Reference

Existence Operators

exists

Value must be present (not nil or missing).

expect:
  body:
    $.id: exists
    $.user.email: exists

!exists

Value must NOT be present (nil or missing).

expect:
  headers:
    X-Internal-Debug: "!exists"  # Should not be in response
  body:
    $.error: "!exists"

!empty

Value must not be empty string.

expect:
  body:
    $.name: !empty
    $.description: !empty

String Matching

contains "text"

String must contain the substring.

expect:
  headers:
    Content-Type: contains application/json
    Set-Cookie: contains session=
  body:
    $.message: contains success
    $.url: contains https://

Note: Quotes around the text are optional but recommended for clarity.

!contains "text"

String must NOT contain the substring.

expect:
  body:
    $.message: !contains error
    $.response: !contains failed

matches "regex"

String must match the regular expression pattern.

expect:
  body:
    $.email: matches "^[\\w.]+@[\\w.]+\\.[\\w]+$"
    $.uuid: matches "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
    $.phone: matches "^\\+?[0-9]{10,15}$"
    $.date: matches "^\\d{4}-\\d{2}-\\d{2}$"

Important: Escape backslashes in YAML (\\ instead of \).


Numeric Comparisons

> N - Greater Than

expect:
  body:
    $.count: "> 0"
    $.price: "> 99.99"
    $.stock: "> 10"

>= N - Greater Than or Equal

expect:
  status: ">= 200"    # Any success status
  body:
    $.total: ">= 1"
    $.rating: ">= 4.0"

< N - Less Than

expect:
  body:
    $.age: "< 100"
    $.discount: "< 50"

<= N - Less Than or Equal

expect:
  body:
    $.quantity: "<= 1000"
    $.percentage: "<= 100"

Type Checks

type <type>

Value must be of the specified JSON type.

Supported types:

  • string
  • number
  • boolean (or bool)
  • array
  • object
  • null
expect:
  body:
    $.id: type number
    $.name: type string
    $.active: type boolean
    $.tags: type array
    $.metadata: type object
    $.deletedAt: type null

Length Checks

Works on strings and arrays.

length N - Exact Length

expect:
  body:
    $.code: length 6           # Exactly 6 characters
    $.items: length 10         # Exactly 10 array items

length > N - Length Greater Than

expect:
  body:
    $.description: length > 10
    $.results: length > 0

length >= N - Length Greater Than or Equal

expect:
  body:
    $.password: length >= 8
    $.items: length >= 1

length < N - Length Less Than

expect:
  body:
    $.title: length < 100
    $.tags: length < 20

length <= N - Length Less Than or Equal

expect:
  body:
    $.summary: length <= 280    # Tweet length
    $.choices: length <= 5

List Membership

in [val1, val2, val3]

Value must be one of the listed values.

expect:
  body:
    $.status: in [active, pending, completed]
    $.role: in [admin, user, guest]
    $.priority: in [high, medium, low]

Exact Match

Plain value for exact equality.

expect:
  status: 200                 # Exact status code
  body:
    $.status: "success"       # Exact string match
    $.count: 42               # Exact number
    $.enabled: true           # Exact boolean

Array of Values (Any Of)

Match if value equals any of the listed values.

expect:
  status: [200, 201]          # Status is 200 OR 201
  body:
    $.type: [user, admin]     # Type is "user" OR "admin"

Assertion Targets

Status Code

Validate HTTP status codes.

expect:
  status: 200                       # Exact match
  status: [200, 201]                # Any of these
  status: ">= 200"                  # Range check
  status: "< 400"                   # Less than 400

Common patterns:

# Success (2xx)
status: ">= 200"
status: "< 300"

# Client error (4xx)
status: ">= 400"
status: "< 500"

# Created
status: 201

# No content
status: 204

# Not found
status: 404

Headers

Validate response headers.

expect:
  headers:
    # Exact match
    Content-Type: application/json

    # Contains
    Content-Type: contains application/json
    Set-Cookie: contains session=

    # Exists
    X-Request-ID: exists
    X-RateLimit-Remaining: exists

    # Doesn't exist
    X-Debug-Info: "!exists"

    # Regex match
    Date: matches "^[A-Za-z]{3}, \\d{2} [A-Za-z]{3} \\d{4}"

    # Not empty
    Authorization: !empty

Note: Header names are case-insensitive in HTTP but case-sensitive in assertions.


Body (JSONPath)

Validate JSON response bodies using JSONPath expressions.

JSONPath Syntax Quick Reference

ExpressionMeaningExample
$Root object$: type object
$.fieldTop-level field$.id: exists
$.nested.fieldNested field$.user.email: !empty
$[0]Array index$[0].id: exists
$.array[0]Named array index$.items[0].name: !empty
$.array.lengthArray length$.items.length: "> 0"

Common Body Assertions

expect:
  body:
    # Root type
    $: type object
    $: type array

    # Field existence
    $.id: exists
    $.user: exists
    $.error: "!exists"

    # Field values
    $.status: "success"
    $.code: 200
    $.active: true

    # Nested fields
    $.user.id: exists
    $.user.email: matches "^\\w+@\\w+\\.\\w+$"
    $.user.name: !empty

    # Arrays
    $.items: type array
    $.items.length: "> 0"
    $.items.length: "<= 100"
    $.items[0].id: exists
    $.items[0].name: !empty

    # Type checks
    $.id: type number
    $.tags: type array
    $.metadata: type object

    # Numeric comparisons
    $.count: "> 0"
    $.total: ">= 100"
    $.price: "< 1000"

    # String matching
    $.message: contains success
    $.url: contains https://
    $.code: length 6

Response Time

Validate response time performance.

expect:
  responseTime: "< 500ms"          # Less than 500 milliseconds
  responseTime: "< 1s"             # Less than 1 second
  responseTime: "<= 2s"            # At most 2 seconds
  responseTime: "< 100ms"          # Very fast

Supported units:

  • ms - milliseconds
  • s - seconds
  • m - minutes

Complete Examples

Response Body Validation

Validate complex nested JSON structures and arrays:

requests:
  get-user-data:
    expect:
      status: 200
      headers:
        Content-Type: contains application/json
      body:
        # Root array validation
        $: type array
        $.length: "> 0"
        
        # Item validation
        $[0].id: 123
        $[0].email: matches "^[\\w.]+@[\\w.]+\\.[\\w]+$"
        $[0].name: !empty
        $[0].role: in [user, admin, guest]
        
        # Nested object validation
        $[0].profile: type object
        $[0].profile.age: "> 18"

Error Response

requests:
  unauthorized:
    method: GET
    url: https://api.example.com/admin
    expect:
      status: 401
      body:
        $.error: "unauthorized"
        $.message: !empty
        $.code: 401
        $.data: "!exists"  # No data in error response

Create Resource

requests:
  create-user:
    method: POST
    url: https://api.example.com/users
    body: |
      {
        "name": "John Doe",
        "email": "john@example.com"
      }
    expect:
      status: [201, 200]  # Accept either
      headers:
        Location: exists
        Location: contains /users/
      body:
        $.id: exists
        $.id: type number
        $.name: "John Doe"
        $.email: "john@example.com"
        $.createdAt: exists
        $.createdAt: matches "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}"

Pagination

requests:
  paginated-list:
    method: GET
    url: https://api.example.com/items?page=1&limit=20
    expect:
      status: 200
      body:
        $.items: type array
        $.items.length: ">= 1"
        $.items.length: "<= 20"
        $.pagination: type object
        $.pagination.page: 1
        $.pagination.limit: 20
        $.pagination.total: "> 0"
        $.pagination.hasNext: type boolean

Advanced Patterns

Multiple Conditions

Combine multiple assertions on the same field:

expect:
  body:
    # Multiple assertions as a list
    $.price:
      - type number
      - "> 0"
      - "< 10000"

    $.title:
      - type string
      - !empty
      - length >= 3
      - length <= 100

Conditional Fields

Check if optional fields are valid when present:

expect:
  body:
    # Required field
    $.id: exists

    # Optional field - if present, must be valid
    # (Use workflows to conditionally check)

For complex conditional logic, use workflows with conditional steps.

Deep Nesting

expect:
  body:
    $.user.profile.settings.notifications.email: true
    $.data.items[0].metadata.tags[0]: !empty

Common Pitfalls

1. Escaping Regex

Wrong:

$.email: matches "^\w+@\w+\.\w+$"

Correct:

$.email: matches "^\\w+@\\w+\\.\\w+$"

YAML requires escaping backslashes.

2. Quotes for Operators

Some operators need quotes in YAML:

Wrong:

$.count: > 0          # Parsed as YAML anchor
$.status: !exists     # Parsed as YAML tag

Correct:

$.count: "> 0"
$.status: "!exists"

3. Type vs Value

Wrong:

$.active: "true"      # String "true", not boolean

Correct:

$.active: true        # Boolean true
$.active: type boolean  # Check type

4. Array Length

Wrong:

$.items: "> 0"        # Comparing array to number

Correct:

$.items.length: "> 0"

See Also

Assertions (Compact DSL) - Quadrastack Docs