← React / TypeScript

React / TypeScript · 14 / 18

HTTP contracts and runtime validation

Distinguish transport failures, HTTP failures and invalid response data.

  • Medium
  • Intermediate
  • 45 min

Prerequisites: SQLite and repositories in House Log

A TypeScript type checks source code, not foreign JSON contents. An API boundary needs a runtime parser. HTTP also provides status codes. A 500 result is often a successfully received Response for a failed request. Our example therefore checks both status and data shape. Typed API Contract Kit groups such rules into reusable contracts.

Example files

01Validate unknown data

parseEntry accepts unknown. An Entry is produced only after checking the object, ID and title. This differs from JSON.parse(...) as Entry. An assertion performs no validation.

contract.ts · typescriptOpen file
type Entry = { id: string; title: string };
function parseEntry(value: unknown): Entry {
  if (typeof value !== 'object' || value === null ||
      !('id' in value) || typeof value.id !== 'string' ||
      !('title' in value) || typeof value.title !== 'string') {
    throw new Error('Invalid entry response');
  }
  return { id: value.id, title: value.title };
}
async function loadEntry(response: Response): Promise<Entry> {
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  return parseEntry(await response.json());
}
async function main() {
  console.log(await loadEntry(Response.json({ id: 'e1', title: 'Roof' })));
  try { await loadEntry(Response.json({ id: 'e1' })); }
  catch (error) { console.log(String(error)); }
}
void main();

Run / check

npx tsc contract.ts --strict --target ES2022 --module NodeNext
node contract.js

02Encapsulate the transport boundary

loadEntry receives a Response, checks ok and processes JSON as unknown. The example creates responses locally. A real fetch function would first receive an address and an AbortSignal.

03Distinguish failure categories

A network interruption, status 500 and a response missing title need different diagnostic information. Users can receive clear translated messages. No failure should transfer unchecked data into confirmed state.

04Read project scope accurately

The checked Contract Kit version implements parsers, a Fastify adapter and a fetch client. React Query integration, OpenAPI generation and a compatibility CLI remain on the roadmap. A tutorial must not present planned features as finished APIs.

Expected result

The valid response produces Roof. A missing title property is rejected.

Your exercise

Add a nonblank title as a domain rule. Then test status 500 and an empty title.

Show the solution and explanation

Check value.title.trim().length after validating the type. A 500 response fails before parsing. An empty title fails inside the parser. This ordering separates HTTP and data failures.

Project context and sources

The example is simplified for learning. The linked source version shows its use in the project and the checks applied there.