Skip to content

DASPRiD/koa-jsonapi-zod

Repository files navigation

JSON:API support for Koa with Zod

Release

This package provides support for working with JSON:API in Koa, taking all guesswork out of the equation.

Installation

npm

npm i koa-jsonapi-zod

pnpm

pnpm add koa-jsonapi-zod

Usage

In order to serialize your entities into valid JSON:API responses, you have to set up a serialize manager which is composed of several entity serializers. You also have access to several utility functions meant for parsing incoming requests, as well as a middleware which takes care of handling requests and responses.

For a complete example, have a look under examples/complete.

Middlewares

This package exports two middlewares, jsonApiRequestMiddleware and jsonApiErrorMiddleware.

The former takes care of validating incoming requests and formatting responses accordingly. You can exclude specific paths from being handled by the middleware (e.g. RPC endpoints). This middleware should be registered as early as possible.

The error middleware is a convenience middleware which traps all errors and creates appropriate error responses. You can also supply a logger function as an option, which allows you to log specific errors. This middleware should be registered right after the request middleware.

For more details, see index.ts in the complete example.

Features not covered in the example

Serialization context

In some instances your serializers might require context about a request. One instance of this is where you want to expose specific fields of an entity only when the user has permission to access these. In that case you should define your serialization context first:

type SerializerContext = {
    permissions?: string[];
};

Each serializer can define its own context, and it will be accessible separately for each serializer. Since the context is always an optional property, you can then perform checks like this in e.g. your getAttributes() implementation:

const attributes: Record<string, unknown> = {
    foo: "bar",
    baz: "bat",
};

if (options.context?.permissions?.includes("read:secret")) {
    attributes.secret = "super secrtet information";
}

You can then serialize your entities in the following way:

serializeManager.createResourceDocument("my_entity", entity, {
    context: {my_entity: {permissions: "foo"}},
});

Additionally, when you define a relationship in a serializer as an entity, you can pass down additional context which will be merged with the parent context.

Filtering

You can add filters to list handlers as well. JSON:API does not define the structure of filters itself, except that the filter property should be used for this. Whether you make that property an object or a plain string is up to you. Simply provide a Zod schema to the filterSchema property, and you will get a filter property on the result back.

Pagination

Similar to filters you can also supply a pageSchema property, which will result in a page result.