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[];
}
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);
}
// 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,
});
}
Now both sides of my application can have confidence that they will be receiving/sending the same payloads!
Top comments (0)