Serve a spec-compliant JSON:API from your Lucid models. Every model serializes with no configuration, and each endpoint is a few lines. The package builds compound documents, includes, sparse fieldsets, sorting, filtering, pagination, error documents, content negotiation, and full write support.
// A complete JSON:API endpoint:
async index({ jsonApi }: HttpContext) {
const articles = await jsonApi.query(Article).paginate(...jsonApi.page)
return jsonApi.render(articles)
}New to the format? Start with JSON:API concepts.
node ace add @evoactivity/jsonapi-adonisThis installs the package and configures it. It writes config/jsonapi.ts, registers the provider and the jsonApi named middleware, and registers the generator commands.
Requirements. AdonisJS v7 (@adonisjs/core ^7) and Lucid v22 (@adonisjs/lucid ^22).
jsonApi.query(Model) is Model.query() with the request's include, sort, and filter already applied, so you chain .where(), scopes, and .paginate() as usual. jsonApi.render(...) builds the document and sets the media type:
export default class ArticlesController {
async index({ jsonApi }: HttpContext) {
const articles = await jsonApi.query(Article).paginate(...jsonApi.page)
return jsonApi.render(articles)
}
async show({ jsonApi, params }: HttpContext) {
const article = await jsonApi.query(Article).where('id', params.id).firstOrFail()
return jsonApi.render(article)
}
async store({ jsonApi }: HttpContext) {
const input = await jsonApi.deserialize(Article)
const article = await Article.create(await createArticleValidator.validate(input.attributes))
await jsonApi.syncToMany(article, input.toMany)
return jsonApi.render(article, { status: 201 })
}
}A request like GET /api/v1/articles/1?include=author,tags returns the article as data, the author and tags in included with duplicates removed, the linkage, self and related links, and the application/vnd.api+json content type. Unknown include paths get a 400, and there are no N+1 queries. The Getting started guide walks through the full setup.
| Guide | Covers |
|---|---|
| Concepts | The format, and where this package fits |
| Getting started | Install, generate, first request, error rendering |
| Resources | How a model becomes a resource, and how to customize it |
| Queries | include, sparse fieldsets, sorting, pagination, filtering |
| Scopes | Row visibility with withScopes and withPreloadScopes |
| Writes | Create, update, delete, and the relationship endpoints |
| Polymorphism | Mixed-type relationships with single-table inheritance |
| Links | Route-driven URLs, API versioning, casing |
| Errors and negotiation | Error documents, handlesErrors(), media type rules |
| Building blocks | Serializing outside a request: commands, jobs, tests |
| Reference | The jsonApi helper API, config, generators, roadmap |
examples/blog is a complete AdonisJS application with articles, comments, tags, users, and attachments. It uses every feature, and mounts the same resources under /api/v1 and /api/v2 to show versioned links.
pnpm install
cd examples/blog
node ace migration:run
node ace db:seed
node ace serve --watch
curl 'localhost:3333/api/v1/articles?include=author,tags'pnpm test # package unit tests (no database needed)
pnpm test:example # example app functional suite (spec compliance, writes, links)
pnpm test:all # bothMIT