DEV Community

loading...

Sharing contracts

Jack
Typescript and React nerd. I have a soft spot for architecture and unit testing
・1 min read

This is a concept that really drives home how nice it is when your entire stack is written in the same language. I am using node/typescript on the backend which means I can share stuff between the ui and api.

I have a separate repo that holds common stuff like error codes, request payloads and response payloads:

// Contracts
export interface SearchProductsRequest {
  page: number;
  q: string;
}

export interface SearchProductsResponse {
  nextPage: number;
  products: Product[];
}
Enter fullscreen mode Exit fullscreen mode

Then I can use that to bridge the gap between api and ui:

// API
async function searchProductsApi(
  req: Request<void, void, void, SearchProductsRequest>,
  res: Response<SearchProductsResponse>
) {
  // req.query is strongly typed
  const result = await search(req.query);

  // res.send will throw a ts error if result doesn't match the response
  res.status(200).send(result);
}
Enter fullscreen mode Exit fullscreen mode
// UI
// (driver is a simple wrapper around the fetch api)
async function searchProducts(args) {
  // data will be strongly typed
  const { data } = await driver<SearchProductsRequest, SearchProductsResponse>({
    url: "/products",
    // will throw a ts error is args doesn't match the request
    data: args,
  });
}
Enter fullscreen mode Exit fullscreen mode

Now both sides of my application can have confidence that they will be receiving/sending the same payloads!

Discussion (0)