T8 SDK Factory
Schema-based validation
Fine-grained schema-based validation of the request and response can be implemented with a custom request handler. Here's how the basic JSON request handler from the previous section can be modified to validate its input and output with Zod or, similarly, with another validation lib:
import {
RequestHandler,
RequestError,
RequestService,
getRequestAction,
toStringValueMap,
} from "@t8/sdk-factory";
- import type { APISchema } from "./APISchema";
+ import { apiSchema, type APISchema } from "./apiSchema"; // defined with Zod
function getRequestHandler(endpoint: string): RequestHandler {
return function(target, request) {
+ try {
+ schema[target]?.request?.parse(request);
+ }
+ catch {
+ throw new RequestError({
+ statusText: "Invalid request data",
+ });
+ }
let { method, url } = getRequestAction({ request, target, endpoint });
let response = await fetch(url, {
method,
headers: toStringValueMap(request?.headers),
body: request?.body ? JSON.stringify(request?.body) : null,
});
let { ok, status, statusText } = response;
if (!ok) {
throw new RequestError({
status,
statusText,
});
}
try {
let body = await response.json();
+ try {
+ schema[target]?.response?.parse(body);
+ }
+ catch {
+ throw new RequestError({
+ statusText: "Invalid response data",
+ });
+ }
return {
ok,
status,
statusText,
body,
};
}
catch (error) {
throw new RequestError(error);
}
};
}
export const serverService = new RequestService<APISchema>(
getRequestHandler("https://api.example.com")
);
// Assuming that the given API is proxied by the server to
// the browser via `/api`
export const browserService = new RequestService<APISchema>(
getRequestHandler("/api")
);
Here's an example of what the API schema definition with a validation library may look like:
import { z } from "zod";
export const apiSchema = {
"GET /items/:id": {
request: z.object({
params: z.object({
id: z.coerce.number(),
}),
query: z.optional(
z.object({
mode: z.optional(z.string()),
})
),
}),
response: z.object({
id: z.coerce.number(),
name: z.optional(z.string()),
}),
},
};
export type APISchema = {
[K1 in keyof typeof apiSchema]: {
[K2 in keyof (typeof apiSchema)[K1]]: z.infer<(typeof apiSchema)[K1][K2]>;
};
};
← Custom request handler | GitHub ✦