TestMesh
YAML ReferenceActions

http_request

Make HTTP requests — GET, POST, PUT, PATCH, DELETE and more — with headers, authentication, query parameters, body, and response assertions.

The http_request action sends an HTTP request and exposes the response status, body, headers, cookies, and duration for assertions and output extraction.

Minimal example

health-check.yaml
- id: health_check
  action: http_request
  config:
    method: GET
    url: "http://localhost:5016/health"
  assert:
    - status == 200

Config fields

method (required)

HTTP verb. One of: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS.

url (required)

The request URL. Supports ${variable} interpolation.

config:
  method: GET
  url: "${API_URL}/users/${user_id}"

headers

Key-value map of request headers.

config:
  method: POST
  url: "${API_URL}/users"
  headers:
    Content-Type: "application/json"
    Authorization: "Bearer ${auth_token}"
    X-Request-ID: "${RANDOM_ID}"

params

Query string parameters. Each value is a string.

config:
  method: GET
  url: "${API_URL}/users"
  params:
    page: "1"
    limit: "20"
    status: "active"

body

Request body for POST, PUT, and PATCH. Can be a YAML object (sent as JSON) or a raw string.

# JSON body (object)
config:
  method: POST
  url: "${API_URL}/users"
  body:
    email: "user@example.com"
    password: "SecurePass123!"
    role: "member"

# Raw string body
config:
  method: POST
  url: "${API_URL}/webhook"
  body: "raw text payload"

# Multiline body (XML, plain text, etc.)
config:
  method: POST
  url: "${API_URL}/xml-endpoint"
  body: |
    <request>
      <user>test</user>
    </request>

auth

Authentication configuration. Supported types: basic, bearer, api_key, oauth2.

config:
  auth:
    type: bearer
    token: "${AUTH_TOKEN}"
config:
  auth:
    type: basic
    username: "${USERNAME}"
    password: "${PASSWORD}"
config:
  auth:
    type: api_key
    key: "${API_KEY}"
    location: "header"    # "header" or "query"
    name: "X-API-Key"     # Header name or query param name

timeout

Per-request timeout. Overrides the step-level timeout field.

config:
  method: GET
  url: "${API_URL}/slow-endpoint"
  timeout: "60s"

follow_redirects

Whether to follow HTTP redirects. Defaults to true. Set max_redirects to limit redirect chains.

config:
  follow_redirects: false

verify_ssl

Whether to verify TLS certificates. Defaults to true.

config:
  verify_ssl: false    # Only for local/test environments

cookies

Request cookies.

config:
  cookies:
    session_id: "abc123"
    preference: "dark_mode"

Full config reference

full-http-config.yaml
- id: api_call
  action: http_request
  config:
    method: POST
    url: "${API_URL}/users"
    headers:
      Content-Type: "application/json"
      Authorization: "Bearer ${AUTH_TOKEN}"
    params:
      include_metadata: "true"
    body:
      email: "user@example.com"
      name: "Test User"
    auth:
      type: bearer
      token: "${TOKEN}"
    follow_redirects: true
    max_redirects: 5
    verify_ssl: true
    timeout: "30s"
    cookies:
      session: "${SESSION_ID}"

Response data

After a step runs, the following paths are available for output extraction and assert expressions.

PathDescription
response.statusHTTP status code (integer)
response.bodyParsed response body (object or string)
response.body.fieldNested field access
response.body.array[0]Array element
response.headersResponse headers object
response.headers["Content-Type"]Specific header value
response.cookiesResponse cookies
response.timeResponse time in milliseconds

Output extraction

output:
  user_id: "response.body.id"
  user_email: "response.body.email"
  auth_token: "response.body.token"
  content_type: "response.headers[\"Content-Type\"]"
  status_code: "response.status"
  duration_ms: "response.time"

Assertions

assert:
  - status == 201                                          # Status code
  - response.body.id exists                                # Field present
  - response.body.email == "user@example.com"              # Field value
  - response.headers["Content-Type"] contains "json"       # Header contains
  - response.time < 500                                    # Response under 500ms
  - response.body.users.length > 0                         # Array non-empty
  - response.body.role == "member"                         # String equality

Common patterns

POST and capture the created resource

- id: create_product
  action: http_request
  config:
    method: POST
    url: "${API_URL}/products"
    headers:
      Authorization: "Bearer ${auth_token}"
    body:
      name: "Widget Pro"
      price: 49.99
      sku: "WDGT-${RANDOM_INT}"
  output:
    product_id: "response.body.id"
    sku: "response.body.sku"
  assert:
    - status == 201
    - response.body.id exists

GET with query parameters and pagination assertion

- id: list_users
  action: http_request
  config:
    method: GET
    url: "${API_URL}/users"
    headers:
      Authorization: "Bearer ${auth_token}"
    params:
      page: "1"
      limit: "10"
      status: "active"
  output:
    users: "response.body.data"
    total: "response.body.total"
  assert:
    - status == 200
    - response.body.data.length <= 10
    - response.body.total >= 0

DELETE and verify 404 afterward

- id: delete_user
  action: http_request
  config:
    method: DELETE
    url: "${API_URL}/users/${user_id}"
    headers:
      Authorization: "Bearer ${auth_token}"
  assert:
    - status == 204

- id: verify_deleted
  action: http_request
  config:
    method: GET
    url: "${API_URL}/users/${user_id}"
    headers:
      Authorization: "Bearer ${auth_token}"
  assert:
    - status == 404

Retry on server errors

- id: create_payment
  action: http_request
  config:
    method: POST
    url: "${PAYMENT_URL}/charge"
    body:
      amount: 1999
      currency: "usd"
  retry:
    max_attempts: 3
    delay: "2s"
    backoff: "exponential"
    retry_on:
      - "status >= 500"
      - "timeout"
    retry_on_not:
      - "status == 402"
  assert:
    - status == 200
    - response.body.status == "succeeded"

On this page