Skip to main content
Assertions let you validate every aspect of an HTTP response — status codes, headers, body content, response times, and more. hitspec provides 26 operators grouped into six categories.

Assertion Block Syntax

Wrap assertions in >>> and <<< markers:
Each line inside the block follows this pattern:
When the operator is ==, you can omit it, as long as the value starts like a value (a number, a quoted string, true, false, null, [ or {):
A trailing # comment is allowed on any line (the # must follow whitespace and be followed by whitespace or the end of the line). Blank lines and lines starting with # or // inside the block are ignored. Any other line that does not start with expect is an error.

Mistakes are errors, not guesses

hitspec refuses assertion lines it would otherwise have to guess at. hitspec run and hitspec validate report them with file:line:column and exit with code 2:
  • An unknown operator (contians, =, ===, equals) is an error. A bare word after the subject is never read as ”== word”: write expect body.name == Jane or expect body.name "Jane".
  • An operator without a value (expect body.name ==) is an error. It no longer reads the next line as its value.
  • Extra values are an error: expect status 200 201 fails with a hint to write expect status in [200, 201].
  • expect misspelt (expcet status 200) is an error, so a line can never silently assert nothing.

Expected Values

Every operator that takes a value reads it with one rule. The value is either:
  1. a JSON literal: a string ("Jane Doe" or 'Jane Doe'), a number, true, false, null, a list [1, "a", b], or an object {"a": 1}; or
  2. a regular expression /pattern/flags after matches (flags i, m, s, U; g is accepted and ignored); or
  3. otherwise, the rest of the line, trimmed, exactly as written, as a string.
Quoted strings use JSON escapes; if the text is not valid JSON (a regex such as "\d+"), it is used as written. In a list, each element follows the same rule. {{variable}} references are filled in before comparing. Text after a closing quote is an error ("Jane" Doe), so quote the whole value or none of it. For contains, !contains, startsWith and endsWith the value is always text: a quoted string is decoded, anything else is used exactly as written (expect body startsWith {, expect body.price contains 1.50).

Assertion Subjects

A body path needs a JSON response: application/json, text/json and any +json type such as application/problem+json, with or without ; charset=.... On any other response, body.x fails with “response body is not JSON” instead of quietly matching; only the whole body can be read. See Assertion Subjects.

Equality and Comparison

Compare values using standard comparison operators.
Use expect status 200 as shorthand for expect status == 200. The == operator is implied when omitted.
== and != compare objects and arrays deeply, as JSON: key order does not matter, 1 equals 1.0, and ["a b"] is not ["a", "b"]:
Scalars are compared loosely: "42" and 42 are equal. null only equals null (see null versus absent).

String Operators

Match, search, and compare string values.
Regular expressions in matches are enclosed in forward slashes: /pattern/ or /pattern/i (flags i, m, s, U). The pattern uses Go’s regexp syntax. A value without slashes (matches "^a") is used as the pattern as written.
The string operators work on text. On the whole body of a JSON response they see the response’s raw JSON text; on an object or array they see its JSON encoding (never Go’s map[...] form); numbers appear without an exponent:

Existence and Type

Check whether values exist and validate their types. Supported types for the type operator: null, boolean, number, string, array, object. Anything else is an error (type strng suggests string).

null versus absent

A field that is missing and a field that is null are different, and the operators treat them differently: == null needs a real JSON null, and != null needs a present, non-null value, so a misspelt path cannot pass either. To accept “absent or null”, use !exists. Every other operator fails on an absent path, except the negated ones (!=, !contains, !includes, !in), which hold because nothing is there to match.

Length and Arrays

Validate array lengths and check array contents.

The each Operator

each applies an assertion to every element in an array. It is useful for validating the shape of list responses. After each write an operator and value, optionally preceded by a path inside the element (body or a leading . means the element itself):
A failure names the element: item[2]: expected type string, got number. An empty array passes (nothing to check); add length > 0 to require elements.

The in Operator

in checks whether a value is a member of a set. List values in square brackets:

The includes Operator

includes checks whether an array contains a specific value:

Schema Validation

Validate the entire response body against a JSON Schema file.
Where schemas/user.json contains a standard JSON Schema:
Schema file paths are resolved relative to the .http file that references them.

Snapshot Testing

Compare the response body against a previously saved baseline. A snapshot is never created by a plain run: the first run fails with “snapshot does not exist (run with —update-snapshots to create)”. Run once with --update-snapshots to save the baseline, then later runs compare against it.
Snapshots are stored in a __snapshots__ directory next to your test file. Create them the first time, and update them when the response intentionally changes:
Snapshot testing works well for responses that should remain stable over time, such as configuration endpoints or reference data.

Combining Assertions

A single assertion block can mix operators from any category:

Header Assertions

Assert on response headers using the header <name> subject:

Reading a failure

When a request fails, the console output alone says why: the failed assertions with their expected and actual values, then the request as it was sent, the response status line with its duration, and an excerpt of the response body.
JSON bodies are pretty-printed and the excerpt is capped at about 2 KB or 30 lines; a note says how much was cut, and -vvv prints the whole body. Credentials are redacted: header values such as Authorization and Cookie, the password in user:password@host, and query parameters named like api_key or access_token. If a request errored before any response arrived (connection refused, timeout), you get the request line and the error. See output formats for -v, -vv and -vvv.

Testing Error Responses

Assertions are equally useful for verifying error behavior:
Last modified on October 19, 2026