Template-based HTTP request/response specification tool
As an API developer who loves HTTP and test driven development, I wanted a very lightweight, language-agnostic way to test APIs.
http-spec intends to allow development of explicit and fast spec suites.
If you have code that executes behind an HTTP API, then it is ideal to test that code via HTTP -- anything else is missing the point!
Stated another way: APIs are contracts executed via HTTP. http-spec allows API contracts to be written in and verified by HTTP.
While low-level tests may still be required for edge cases such as networking exceptions and intermittent service retry, for instance, the vast majority of the code behind the API should be exercisable via HTTP requests.
A significant advantage of this method is that it requires you consider every byte of your API's input and output, including request and response headers. There is much to be learned from that experience!
go install github.com/tmornini/http-spec@latest
Download a binary executable from:
https://github.com/tmornini/http-spec/releases
Don't forget to put it somewhere in your PATH, and chmod 755 it!
-hostname string
hostname (also inferred from Host header in spec)
-matchers string
path to custom matchers JSON file
-http-retry-delay duration
delay between failed HTTP requests (default 1s)
-http-timeout duration
timeout per HTTP request (default 30s)
-max-http-attempts int
maximum number of attempts per HTTP request (default 180)
-retry-status-codes string
comma-separated HTTP status codes to retry on (e.g. 502,503)
-scheme string
scheme (http/https)
-show-substitutions
show substitutions table on success (always shown on failure)
-skip-tls-verification
skip TLS verification (hostname mismatch, self-signed certifications, etc.)
https://hub.docker.com/r/tmornini/http-spec/
This image is not intended to be used directly, but as the base to build your own custom http-spec container atop.
Just COPY your .htsf files and /run-http-specs executable to the image.
/run-http-specs allows you to orchestrate the test invocation order, timing, and prefix handling when testing microservices within a docker-compose cluster.
FROM tmornini/http-spec
LABEL maintainer="Tom Mornini <[email protected]>"
COPY run-http-specs /run-http-specs
COPY *.htsf /
COPY matchers.yml /
http-spec path/to/\*.htsf
HTSF is, first and foremost, modeled after curl -v output.
It consists of a HTTP request, including the request line, HTTP headers, mandatory empty line, and optional body. The Content-Length header is set automatically.
Each line of the request is prefixed by "> " -- though ">" is allowed for the blank line.
An empty line separates the request from the expected response.
The expected response is an HTTP response, including the status line, followed by HTTP headers sorted in ASCII order, a mandatory empty line, and an optional body.
Each line of the expected response is prepended by "< " though "<" is acceptable for the blank line.
http-spec will send the request and compare the expected response to the actual response.
If the responses match, the next request/response pair is executed until the end of the file.
If a response doesn't match, a error is logged to STDERR. Any response mismatch or any error of any sort will cause http-spec to terminate with exit code 1 to signal failure.
If a response matches, a success is logged to STDOUT along with the response time.
If all responses in all files match, http-spec terminates with exit code 0 to signal success.
When passed more than one file http-spec processes each file concurrently, allowing for large spec suites to be run quickly.
If no expected response follows a request, http-spec will make the request and output the response formatted as an http-spec expected response ready to be copied into an .htsf file. This allows for rapid, iterative request/response development.
Request-only mode reports as a failure to prevent false-positives on incomplete specs.
Expected responses are parsed for regexp matchers that allow dynamic matching and named capture for subsequent substitution within the file.
Matchers take the form:
⧆optional-name⧆mandatory-regexp⧆
If name is provided, the complete match of the regexp is assigned to the name, making the matched text available for substitutions later in the file.
Matching makes it easy to match variable content items such as UUIDs and authentication tokens.
- character is SQUARED ASTERISK (U+29C6)
⧆optional-name⧆:date⧆ is a matcher for RFC-822 dates used by the HTTP 1.1 Date header.
⧆optional-name⧆:uuid⧆ is a matcher for RFC-4122 UUIDs.
⧆optional-name⧆:b62:22⧆ is a matcher for 22 base 62 characters sometimes used for 128+ bit UUIDs.
⧆optional-name⧆:digits:⧆ is a matcher for one or more decimal digits.
⧆optional-name⧆:iso8601:µs:z⧆ is a matcher for ISO 8601 format timestamps with microsecond resolution and zulu (Z) timezone.
Custom matchers work just like built-in matchers and are loaded from a JSON
file specified via the -matchers flag. See the examples/Dockerfile and
matchers.json file.
The JSON file maps matcher names to regexp patterns. Keys become the
mandatory-regexp portion of the matcher, prefixed with :.
matchers.json example:
{
"RFC4122v4": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
}Usage of the custom matcher:
⧆optional-name⧆:RFC4122v4⧆
Usage via CLI:
http-spec -matchers matchers.json specs/*.htsf
⧈YYYY-MM-DD⧈ is a substitution for today's date
⧈random-uuid⧈ is a substitution for a randomly generated uuid,
created once per .htsf file
If you need to delay between one request (and it's associated response) and the next, you can use a separating line that begins with "+ " followed by a sequence of decimal numbers, each with optional fraction and a unit suffix, such as "300ms" or "1.5s". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h"
This is useful when making a request that triggers an asyncronous operation where you need to wait enough time to allow the asyncronous operation to complete before sending the next request.
Substitution allows the re-use of previous regexp matches and take the form:
⧈name⧈
Substitutions are applied to requests and responses within the same file.
- character is SQUARED SQUARE (U+29C8)
- improve testing dramatically :-(