Logo GH

API Contract Testing

1) Why contract testing

The contract captures customer expectations and provider promises: routes/methods, headers, body schemas, statuses, error semantics, and constraints. The goal is to catch incompatible changes before integration and release versions safely, without heavy E2E.

2) Approaches

Consumer-Driven Contracts (CDC): the client forms expectations (Pact and analogues); the provider regularly verifies them.
Specification: contract as a single source of truth (OpenAPI/Protobuf/GraphQL SDL); tests validate implementation against specification.
Event-based: message schemas (Avro/JSON Schema/Protobuf) + broker/registry compatibility rules.

3) HTTP/REST specification stream

1. Contract: OpenAPI 3. x (diagrams, examples, codes).
2. Lint and stat analysis: style, required fields, uniform codes.
3. Implementation validation: anti-OpenAPI test generator (schemathesis/Dredd approach) + manual negatives.
4. Snapshots: capture sample responses, ETag semantics, idempotency headers.

Example of a negative contract (OpenAPI fragment):
yaml paths:
/v1/payments:
post:
responses:
"201": { $ref: "#/components/responses/PaymentCreated" }
"409": { description: Duplicate by Idempotency-Key }
"422": { description: Schema/Business validation failed }

4) CDC (Pact approach)

Lifecycle:

1. Consumer writes a test, generates a pact file (expectations).

2. Publication in a broker (artifact).

3. Provider in CI raises service (or contract-rack), verifies pact's.

4. The broker calculates the can-i-deploy compatibility matrix.

Example of a consumer test (pseudo-JS):
js pact
.given("wallet exists")
.uponReceiving("get wallet")
.withRequest({ method:"GET", path:"/v1/wallets/w123", headers:{ "Authorization": term({generate:"Bearer x", matcher:/^Bearer\s.+/}) }})
.willRespondWith({
status: 200,
headers: { "Content-Type": "application/json" },
body: like({ id:"w123", currency: "EUR", balance: 0 })
});

5) gRPC/Protobuf contracts

The contract is' .proto'with package/service versioning.
Compatibility: do not reuse tags, only add new ones with optional, do not delete fields used; reserve numbers.
Tests: server/client stab generation, auto-generated case rental + negatives (unknown fields, size-limits).

6) Event Contracts (Kafka/NATS/...)

Схемы: Avro/JSON Schema/Protobuf в Schema Registry.
Compatibility policy is'BACKWARD '(often enough) or'FULL'.
Producer tests: validates the message against the scheme; consumer tests: accepts old and new versions.
Invariants: idempotence keys, order/repeatability, deduplication semantics.

Avro diagram example (fragment):
json
{"type":"record","name":"PayoutCreated","fields":[
{"name":"payoutId","type":"string"},
{"name":"amount","type":"double"},
{"name":"currency","type":{"type":"string","logicalType":"iso-4217"}}
]}

7) Compatibility and versions

Backward-compatible (recommended minimum): add optional fields, do not break existing ones.
Forward-compatible: Consumers ignore unknown fields.
Full: Both.
Versioning: 'path (/v1)', 'Accept: application/vnd. brand. v2+json`, `proto package v2`.
Deviation policy: output window (for example, 90 days), warning headers/events.

8) Negative and mistakes are also a contract

Standardize codes: 400/401/403/404/409/422/429/5xx, mandatory fields' code ',' message ',' trace _ id '.
Sizes/limits are part of the contract (413/414/431).
Idempotency: repetition behavior (409 vs 201 same id).
Headings: 'Retry-After' at 429/503, 'Idempotency-Key', 'Content-Language', etc.

Error pattern:
json
{ "code":"validation_error", "message":"amount must be ≥ 1", "trace_id":"..." }

9) Data managed by contract

Examples - live, validated in CI.
Fixtures for CDC are minimal, deterministic.
Data generation - property-based for numbers/dates; but not to break the stability of snapshots.

10) Pipeline in CI/CD (reference)

1. Lint/validate: OpenAPI/Proto/Avro (`validate`, style-линер).
2. Publish: Contract as artifact (broker/registry).
3. Verify: the provider runs CDC packets/specification tests.
4. can-i-deploy gate: no release allowed without green matrix.
5. Diff-Verifies that the changes are semantic diff.
6. Report: JUnit/HTML, list of violations/definitions.

Pseudo-matrix:
yaml jobs:
lint:...
publish-contract: needs: [lint]
verify-provider: needs: [publish-contract]
can-i-deploy:
if: always()
steps: [run: pact-broker can-i-deploy...]

11) Tools (by task class)

Lint/validators: openapi-linters, protobuf-lint, avro-tools.
CDC: Pact family/broker, Spring Cloud Contract, Hoverfly (HTTP records/replays).
Specification runners: schemathesis/Dredd-like approach, Postman test + JSON Schema.
Diff: semantic-diff OpenAPI/Proto/Avro (detects breaking changes).
Containers: Testcontainers to raise provider/contract desk.

12) Antipatterns

"Special dock" separately from the code → desynchronization. Keep the contract near the service.
Moki of a third-party service instead of a contract → fragility during updates.
Random responses/generation without binding to the → flake scheme.
Changing types/mandatory fields without version.
Silent extensions without notification/decrement.
No negative contracts and error codes.

13) Specifics of iGaming/Finance

Formalize money fields: 'amount' - decimal with scale, currency - ISO-4217, invariants of amounts.
Payment/webhook contracts: HMAC/mTLS, anti-replay ('X-Timestamp' window), idempotency, 'Retry-After'.
Regionality/tenants: mandatory headers' X-Tenant/X-Region ', localization of messages.
Events: unchanging logs (audit), deduplication keys, delivery guarantees (at least once + idempotent handlers).

14) Examples of "skeletons" of tests

14. 1 Schemathesis-style (pseudo)

bash schemathesis run openapi. yaml --checks all --hypothesis-deadline=200

14. 2 Postman as spec runner

js pm. test ("Scheme/v1/wallets/{ id} is valid," () => {
const schema = pm. collectionVariables. get("wallet_get_schema");
pm. expect(ajv. validate(JSON. parse(schema), pm. response. json())). to. be. true;
});

14. 3 CDC Provider Verification (Pseudo)

bash pact-broker can-i-deploy --pacticipant wallets --version $SHA --to-environment staging

15) Prod Readiness Checklist

  • Contracts in repository, CI validates and publishes artifacts.
  • CDC enabled for critical integrations; broker/matrix "can-i-deploy" works.
  • Compatibility policy (HTTP/gRPC/Events) documented; automatic semantic-diff.
  • Negative contracts: errors, size limits, idempotence, 'Retry-After'.
  • Test data is deterministic; snapshots of examples are supported.
  • Versioning and deprecation: deadlines, notifications, headers.
  • For events - Schema Registry and compatibility mode; The producer/consumer is testing both versions.
  • Artifacts: JUnit/HTML, diff/verify reports, compatibility matrix.
  • Incident procedure: fast contract rollback/feature flag, notification to integrators.

16) TL; DR

Capture expectations in contracts and run them automatically: CDC for customer expectations, specification tests to match implementation, schema register for events. Keep strict compatibility policies and negative contracts (errors, limits, idempotence). You cannot release without a green can-i-deploy matrix and semantic-diff without breaking changes.

Contact

Get in Touch

Reach out with any questions or support needs.We are always ready to help!

Telegram
@Gamble_GC
Start Integration

Email is required. Telegram or WhatsApp — optional.

Your Name optional
Email optional
Subject optional
Message optional
Telegram optional
@
If you include Telegram — we will reply there as well, in addition to Email.
WhatsApp optional
Format: +country code and number (e.g., +380XXXXXXXXX).

By clicking this button, you agree to data processing.