← API Contract LabDemonstration case study

Test the boundary.
Document the exception.

A valid example proves very little about rejection behavior. This experiment makes the rules, boundary cases, and parser limitations visible.

22documented fixtures
22/22match expected decisions
30automated tests passed in the recorded run

The question

Can a small request validator distinguish a format error from a contract error, reject unintended coercion, and make its own limits clear? The input is an order-shaped JSON object containing customerId, amountCents, and currency. The experiment has no database, payment processor, or customer records.

A three-step walkthrough

  1. Parse a request.

    A trailing comma fails parsing. An array parses successfully but fails the required object shape. A resource limit can stop processing before parsing even starts.

  2. Check the contract.

    The string "1250" is rejected as an amount. The number 1250 passes. Tests also cover missing fields, exact length boundaries, supported currencies, and unexpected properties.

  3. Inspect what the parser already changed.

    Duplicate keys and rounded numerical values show why an accepted request is not proof that the original JSON text was unambiguous.

Run these examples in the lab

The implementation choices

The function uses JSON.parse, checks the top-level shape, inspects each required field, rejects extra own properties, and returns a reconstructed object only after all checks pass. It does not trim identifiers or convert strings into numbers. The result field named normalized is a serialization of accepted values, not a promise of canonical JSON or normalized identity.

Input and identifier limits count JavaScript UTF-16 code units: 131,072 and 128 respectively. They are not byte limits or user-perceived character counts. The amount check applies Number.isSafeInteger to the parsed value and requires it to be positive. A production pricing system would need its own much narrower limits.

Recorded results

The Node.js 24.19.0 run passed 30 tests: six original regression tests, 22 fixture checks, and two checks documenting parser limitations. These are deterministic correctness checks, not a performance benchmark, production certification, or evidence that every possible input is covered. The table below runs the same fixture inputs through the validator when this page is rendered.

Expected and observed decisions for the 22 request fixtures
FixtureExpectedObservedWhat it checks
Documented requestAcceptAcceptAll three fields satisfy the published rules.
Number supplied as a stringRejectRejectThe contract does not convert strings to numbers.
Fractional centsRejectRejectThe parsed amount must be an integer.
Zero amountRejectRejectThis example requires a positive amount.
Negative amountRejectRejectRefund semantics are outside this order contract.
Maximum safe integerAcceptAcceptThis is the allowed numeric boundary, not a realistic pricing limit.
Integer above safe rangeRejectRejectThe parsed value lies outside JavaScript's safe integer range.
Whitespace-only customer IDRejectRejectA whitespace-only identifier is empty for this contract.
Missing customer IDRejectRejectAll three fields are required.
Customer ID at 128 code unitsAcceptAcceptThe implementation measures JavaScript UTF-16 string length.
Customer ID at 129 code unitsRejectRejectOne unit beyond the documented limit is rejected.
Unexpected admin propertyRejectRejectOnly the three documented own properties are accepted.
Unsupported currencyRejectRejectThe supported set is deliberately narrow.
Lowercase currencyRejectRejectCurrency codes are case-sensitive here.
Top-level arrayRejectRejectValid JSON does not imply an order-shaped object.
Trailing commaRejectRejectParsing fails before contract checks can run.
Supported GBP requestAcceptAcceptGBP is in the documented supported set.
Supported EUR requestAcceptAcceptEUR is in the documented supported set.
Unexpected __proto__ propertyRejectRejectParsed input is inspected and reconstructed, not merged into another object.
Top-level nullRejectRejectNull parses successfully but is not an order object.
Input at 131,072 code unitsAcceptAcceptJSON permits trailing whitespace; the length boundary is inclusive.
Input at 131,073 code unitsRejectRejectThe resource gate stops validation before parsing; syntaxValid false here does not prove malformed JSON.

Two accepted inputs that deserve attention

{"customerId":"demo","amountCents":0,"amountCents":1,"currency":"USD"}

This parser keeps the final amountCents value, so the contract accepts 1. The validator does not detect duplicate keys. If that ambiguity matters, use a parser or input contract that rejects it before ordinary object construction.

{"customerId":"demo","amountCents":1.00000000000000001,"currency":"USD"}

JavaScript parses this amount as 1. Number.isSafeInteger cannot recover precision that has already been lost. Applications requiring exact decimal text need an explicit representation and parser appropriate to that requirement.

Reproduce the experiment

Download or clone the source repository, use Node.js 22.6 or later, and run:

node --experimental-strip-types --test contract.test.mjs contract-cases.test.mjs
node --experimental-strip-types report.mjs

The report command writes contract-report.json with each expected and observed result, the runtime version, and UTC timestamp. The test command also verifies issue messages and documents the two parser limitations.

Source and tests on GitHub ↗ · Download the recorded fixture results

What a passing result cannot establish

This demonstration was created in September 2026 with AI assistance. It is not historical client work. No real orders were processed. Passing does not prove customer identity, authorization, correct pricing, safety under concurrency, duplicate-request handling, or readiness for production. Server-side enforcement and domain-specific checks remain separate engineering work.