Back to insights

Frontend engineering

Building a Typed API Layer with TypeScript

How a reusable TypeScript API layer can separate transport details from product screens, unify errors, support pagination, and make React and React Native features easier to maintain.

7 min readBy Abdulrahman Hares
TypeScriptAPI IntegrationReact QueryReact NativeFrontend Engineering
01

Why screens should not call fetch directly

Direct fetch calls inside screens look fast at the beginning, but they spread authentication, language headers, base URLs, parsing, timeout behaviour, and error handling across the application. When the backend changes, every screen becomes a separate integration point.

A typed API layer creates one place for transport concerns. Screens ask for product operations such as listCars, chooseCar, analyseText, or loadCases instead of rebuilding HTTP rules every time.

02

Start with one request primitive

The request primitive should know how to build the URL, attach headers, serialise the body, parse the response, and convert failures into one application error shape. It should stay small enough to understand and flexible enough for JSON, form data, and authenticated requests.

  • Add authentication and locale headers centrally.
  • Return typed data rather than raw Response objects to feature code.
  • Include endpoint, status, and safe backend details in normalised errors.
  • Support cancellation so abandoned screens do not keep unnecessary work alive.
03

Model contracts instead of guessing shapes

TypeScript is most useful when the type represents a real contract. Required, optional, and nullable fields should match the API instead of being widened until the compiler stops complaining. Request payloads and response payloads should be separate types because they often evolve independently.

When an API has legacy inconsistencies, I normalise them at the boundary. The component should receive one dependable model rather than branches for every historical response shape.

04

Keep server state outside local UI state

Libraries such as TanStack Query are effective when the API layer remains independent. The API function performs the operation; the query layer handles caching, invalidation, retries, stale time, and request lifecycle; the component renders the product state.

This separation also supports React Native and web applications sharing contracts without forcing both platforms to share presentation code.

05

Pagination and search belong in the contract

Server-side selects, searchable tables, and infinite lists need explicit query parameters and metadata. I model page, perPage, search, filters, total, and next-page information instead of storing them as unrelated component variables.

A predictable contract makes it easier to debounce search, reset pagination when filters change, prefetch the next page, and show accurate empty or end-of-list states.

Related project work

Case studies connected to the decisions in this article.

Continue reading

Related engineering notes

View all