Scenario:
>full-stack typescript app
>backend is fastify, frontend is react, there's also a third "common" module
>I wanted strong typing for API requests without needing to duplicate anything or use codegen
>for now the frontend is the only consumer of the backend but this might not always be true
I've implemented the following:
First, within the common module, I've used typebox to describe the request and response types of each endpoint.
const Todo = Type.Object({
id: Type.String(),
content: Type.String(),
});
const GetTodosRequestSchema = Type.Object({ year: Type.Number() });
const GetTodosResponseSchema = Type.Object({
todos: Type.Array(Todo),
});
Second, also in the common module, I've described each endpoint in an object like
const getTodosEndpoint = {
method: "GET",
url: "/get_todos",
request: GetTodosRequestSchema,
response: GetTodosResponseSchema,
}
Now I can do something like this in the frontend:
const {todos} = await api.makeRequest(getTodosEndpoint, { year: 2024 })
The parameter and return types are correctly inferred.
Server-side I also get full type safety, and because I used typebox rather than just typescript types I can also easily validate that requests and responses actually fit the type definitions.
I'm reasonably happy with this- it works well and doesn't feel too over-engineered. But I do wonder if I'm reinventing the wheel and should be using some well-known library. I've looked at various graphql and openapi-related stuff but it all feels very heavyweight and mostly seems to involve code generation.
Anyone else using full-stack TS, what do you use for this?