Getting started
Quick start
A working endpoint in three steps.
1. Declare a service
defineService is an identity function. It exists to preserve the literal types of your config, which is what lets everything downstream be inferred.
api.ts
import { defineService, createApi } from '@tesyl/hapi';
import { z } from 'zod';
const userSchema = z.object({ id: z.string(), name: z.string() });
const users = defineService({
service: 'users',
basePath: '/users',
endpoints: {
detail: {
endpoint: 'detail',
method: 'GET',
path: '/:id',
pathParamsSchema: z.object({ id: z.string() }),
responseSchema: userSchema,
},
update: {
endpoint: 'update',
method: 'PATCH',
path: '/:id',
pathParamsSchema: z.object({ id: z.string() }),
requestSchema: z.object({ name: z.string() }),
responseSchema: userSchema,
},
},
});2. Compose the API
createApi cascades baseUrl, headers, hooks, and defaultOptions down through every service and endpoint.
api.ts
export const api = createApi({
baseUrl: 'https://api.example.com',
services: { users },
});3. Call it
UserProfile.tsx
function UserProfile({ id }: { id: string }) {
const { data } = api.users.detail.withPathParams({ id }).useQuery();
// ^? User | undefined
const save = api.users.update.withPathParams({ id }).useMutation();
if (!data) return <Skeleton />;
return (
<>
<h1>{data.name}</h1>
<button onClick={() => save.mutate({ name: 'Ada' })}>Rename</button>
</>
);
}