A local profile connects request, transport, and response contract

Automatically Test HTTP Interfaces: Status, Headers, and JSON Contracts

An HTTP API can respond cleanly and still violate its contract: the status code is wrong, a required header is missing, or the JSON response contains the wrong type. Iteration 3 of ZEUS Interface Quality closes that gap with a small, reproducible HTTP adapter.

The flow is deliberately limited: a local JSON request calls an explicitly described HTTP endpoint, then the adapter checks status, headers, content type, and response schema. The result stays familiar: VALID, INVALID, stable findings, and exit codes 0, 1, and 2.

The larger approach is covered by the English Project Page. Iteration 1 explains the JSON contract, and Iteration 2 covers CSV and fixed-width files. This article shows the HTTP slice and its boundaries.

AI-generated illustration: An HTTP request and JSON response pass through a validation station and are evaluated by status, headers, and schema
AI-generated illustration for tiny-tool.de: A local HTTP check connects request, endpoint, and JSON response. Green, amber, and red represent valid data, contract deviations, and technical failures.

What Iteration 3 delivers

This is a vertical slice, not a complete API test manager. It takes a local profile, an optional local JSON request, and a local JSON response schema, then calls exactly the endpoint described by that profile.

  • Request: an optional request schema is checked before the network call.
  • Transport: JDK 21 HttpClient executes HTTP or HTTPS with a timeout; redirects are not followed automatically.
  • Response: expected status, required headers, and optional media type are checked.
  • Data contract: the response must be strict UTF-8 JSON and match a local JSON Schema.
  • Result: contract violations return INVALID; profile, file, request, and transport errors use exit code 2.
  • Safety: local schema paths remain below the profile directory; request header values and response payloads are not written to the report.

The HTTP profile as a local contract

The profile describes only what this adapter can actually check. It is intentionally smaller than OpenAPI: method, URL, headers, status, and JSON schemas are enough for a first reproducible HTTP proof.

HTTP profile · delivery.http-profile.json · Version 1
{
  "format": "http",
  "version": 1,
  "method": "POST",
  "url": "http://127.0.0.1:8080/deliveries",
  "requestHeaders": {
    "Content-Type": "application/json",
    "Accept": "application/json"
  },
  "requestSchema": "delivery-request.schema.json",
  "expectedStatus": 201,
  "requiredResponseHeaders": ["Content-Type", "X-Request-Id"],
  "responseContentType": "application/json",
  "responseSchema": "delivery-response.schema.json",
  "timeoutSeconds": 5
}

The schema paths are relative local files. The adapter resolves them below the profile directory and rejects paths that escape through .. or symbolic links. The URL may not contain credentials or a fragment. Header names must be valid HTTP token names, and header values may not contain line breaks.

These rules are not a complete security architecture, but they stop a profile from silently pointing to arbitrary local files or carrying credentials in a URL.

Validate the request before sending

If the profile defines requestSchema, a local input file is required. The adapter validates it before calling HttpClient.send. A missing field or wrong type is therefore a request finding, not an ambiguous failure of the counterparty.

delivery-request.json
{
  "deliveryId": "DEL-1001",
  "quantity": 3,
  "email": "ops@example.org"
}

A request violation is mapped into the shared report with an explicit side:

Request finding · Exit code 1
{
  "status" : "INVALID",
  "valid" : false,
  "findings" : [ {
    "instancePath" : "/request/body/quantity",
    "schemaPath" : "/request/schema/properties/quantity/type",
    "keyword" : "type",
    "message" : "should be integer"
  } ]
}

The message is useful for people, but automation should use status, paths, and keyword. The important side effect is that an invalid request is rejected before it is sent; the loopback test verifies that the local server receives no request in this case.

Execute the HTTP request reproducibly

The transport uses the JDK HTTP client, so no extra client library or Spring Boot runtime is needed. Method, URL, headers, and timeout come from the profile. Redirects are disabled, making an unexpected target change visible rather than silently following a second request.

PowerShell · Validate HTTP profile
$jar = "target/zeus-interface-quality-0.1.0-SNAPSHOT.jar"
$profile = "src/test/resources/fixtures/http/delivery.http-profile.json"
$input = "src/test/resources/fixtures/http/delivery-request.json"

java -jar $jar validate --input-format http --schema $profile --input $input --report json
$LASTEXITCODE

A real local run needs an endpoint with the expected behavior on the port in the profile. The automated tests use a loopback server rather than a public service, so status, headers, and response body stay under test control and no external system is affected.

Check status, headers, and response schema

A response is contract-compliant only when several layers match. The adapter reports them separately: unexpected status under /response/status, missing headers under /response/headers/, and schema findings under /response/body/....

delivery-response.json · Expected response
{
  "accepted": true,
  "deliveryId": "DEL-1001",
  "requestId": "req-local-1001"
}

Content type is compared as a media type, ignoring parameters such as charset=utf-8. The body is decoded strictly as UTF-8 and parsed as JSON. A malformed JSON response is therefore an invalid response contract with exit code 1; an unreachable server is a technical failure with exit code 2.

Response findings · Exit code 1
{
  "status" : "INVALID",
  "valid" : false,
  "findings" : [ {
    "instancePath" : "/response/status",
    "schemaPath" : "/expectedStatus",
    "keyword" : "status",
    "message" : "HTTP-Status 201 erwartet, 500 erhalten"
  }, {
    "instancePath" : "/response/headers/X-Request-Id",
    "schemaPath" : "/requiredResponseHeaders",
    "keyword" : "required",
    "message" : "HTTP-Response enthält den erforderlichen Header nicht: X-Request-Id"
  }, {
    "instancePath" : "/response/body/accepted",
    "schemaPath" : "/response/schema/properties/accepted/type",
    "keyword" : "type",
    "message" : "should be boolean"
  } ]
}

The report does not contain the complete response payload or request header values. That keeps the first report contract small and reduces the chance of tokens, personal data, or large response bodies leaking into CI logs.

Read findings and exit codes

HTTP adapter result semantics
Case Example Result
VALID Status, headers, JSON, and schema match Report, exit 0
INVALID Wrong status, missing header, or response violation Report, exit 1
Invalid request Request schema fails before sending Report, exit 1
Check not possible Invalid profile, file, or transport failure No report, exit 2

The distinction matters in CI. Exit code 1 means the adapter could classify the data and found a contract violation. Exit code 2 means the check itself could not be trusted.

Why the core stays unchanged

The new adapter implements the same Validator interface as the file adapters. The HTTP-specific code reads the profile, executes the transport, and maps deviations to Finding objects. The CLI and report writer do not need to know whether a finding came from a JSON file or an HTTP response.

Iteration 3 responsibility boundaries
Component Responsibility Deliberate boundary
core Finding, status, result, and validator port No HTTP or profile knowledge
adapter.http Profile, request, JDK client, and response checks No OpenAPI parser or secret manager
adapter.jsonschema Validate local schemas and JSON nodes No HTTP transport
cli AUTO/HTTP selection, report, and exit code No multi-request orchestration

The automated evidence

The new tests start a local loopback server and cover more than the happy path: a valid request and response, an invalid request that must not be sent, wrong status, missing header, wrong response type, malformed response JSON, the real CLI output, and a transport failure.

🟢 Reproducible run

Run mvnw.cmd -B -Dtest=HttpValidatorTest test to isolate the HTTP path. The full build has 70 tests after Iteration 3; two Windows symbolic-link cases may remain skipped when the local permission is unavailable. mvnw.cmd -B package then creates the executable JAR.

The tests remain local: they need no public endpoint, send no data to the internet, and control the expected status and headers. That proves the adapter; it does not prove availability or business correctness of a production API.

What is deliberately not included

  • no OpenAPI parser and no automatic profile generation from OpenAPI;
  • no OAuth, API-key, or mTLS secret management;
  • no redirects, streaming, multi-step calls, or multi-file scenarios;
  • no SFTP or FTP connection, quarantine, or retry model;
  • no business rules across multiple requests or records;
  • no performance, load, or availability claim about a real API.

Conclusion: HTTP becomes testable as a contract

Iteration 3 connects the local data contract to a real but deliberately small HTTP flow. A profile describes method, URL, headers, expected status, and local JSON schemas. The JDK client executes the request and maps deviations to the same report as the file adapters.

The evidence is reproducible: loopback tests cover valid and invalid requests, response failures, and transport problems. OpenAPI, authentication, and operational maturity remain separate decisions.

The English Project Page keeps the overall roadmap in view.

Code and sources

Source edition status: September 21, 2026. The examples describe the local Iteration 3 state.

Transparency Notice


Transparency Notice:
Content published on tiny-tool.de is carefully researched, editorially reviewed, and updated regularly. Sources and quotations are provided in a transparent and traceable manner wherever possible. However, we do not guarantee the accuracy, completeness, or timeliness of the information provided. Errors cannot be ruled out.

Editorial Responsibility and Use of AI: Digital tools – including AI-based assistance systems – may be used to support research, structuring, language refinement, translation, code analysis, or visual production. Published content is editorially reviewed, revised, and approved by Guido Zeuner. Content selection, contextualisation, and publication remain under human responsibility. AI-generated output is not treated as an independent source. AI systems are not responsible authors or editors. More information about our use of AI in texts, images, videos, and digital personas is available on our AI Transparency page, which is currently available in German.

Audience Measurement (VG WORT / METIS): VG WORT tracking markers may be used to measure the reach of individual texts. As part of the METIS audience measurement process, a client ID may be generated and a so-called “METIS Session Cookie” may be set. The measurement is used to determine statistical access figures and as a basis for possible VG WORT remuneration. According to VG WORT, no personal usage profiles are created, and the measurement is not used for advertising or marketing tracking. More information is available in our Privacy Notice, which is currently available in German.

Please note: The content provided on this website is for general informational purposes only and does not constitute professional advice, including legal, tax, medical, technical, financial, or other specialist advice. Use of the content is at your own responsibility.

Advertising and Affiliate Links: Some posts may contain promotional references or affiliate links. These are identified accordingly. Clicking such links does not result in any additional cost to you; we may receive a small commission.

Trademark Notice: All brand names, logos, and product names are the property of their respective rights holders and are used solely for identification and descriptive purposes. No affiliation with the companies mentioned is implied unless explicitly stated.

External Links: This website contains links to external third-party websites. Although links are reviewed carefully, we assume no responsibility for the content of external websites. If we become aware of unlawful content, the respective links will be reviewed and removed where appropriate.