Backend setup
Backend setup
Add crouton to a NestJS application.
Install
pnpm add @ghentcdh/crouton-apiPeer dependencies (NestJS, Prisma client, Zod, …) are installed automatically by pnpm and npm.
Register the module
The simplest setup loads everything from the file system — point forResourceDir at your resources folder and your data-sources folder:
import { resolve } from 'node:path';
import { Module } from '@nestjs/common';
import { CroutonApiModule } from '@ghentcdh/crouton-api';
@Module({
imports: [
CroutonApiModule.forResourceDir(
resolve(__dirname, 'resources'),
resolve(__dirname, 'data-sources'),
{
baseUrl: 'http://localhost:3000',
// enumsFile: resolve(__dirname, 'crouton.enums.json'), // optional
},
),
],
})
export class AppModule {
}Every subdirectory of resources/ is loaded as one resource (see resource.json); every subdirectory of data-sources/ provides a database client (see Data sources).
The config object accepts the following fields:
| Field | Type | Description |
|---|---|---|
baseUrl | string | Absolute base URL prepended to operation URIs returned to the frontend (e.g. https://api.example.com). |
prefix | string | Optional URL path prefix prepended to every crouton controller route (e.g. 'api'). See Route prefix. |
enumsFile | string | Path to the shared enum registry. When omitted, found by walking up from the resources directory. |
security | object | Named NestJS guards and an optional module-level default. See Security. |
Other registration styles
| Method | Use when |
|---|---|
forResourceDir(dir, dataSourcesDir, config) | Standard file-system convention (recommended) |
forResources(configs, dataSources, loader, config) | Resource configs built in code / in memory |
forLoader(loader, configs, dataSources, config) | Custom loading strategy |
The schema file
Each resource directory must contain a schema.ts that default-exports the Zod schema describing one record. If you generate Zod schemas from your Prisma models, re-export the generated one:
// resources/book/schema.ts
import { BookSchema } from '../generated/types';
export default BookSchema;What you get
For a resource with "route": "books", crouton registers (depending on the enabled operations):
| Endpoint | Description |
|---|---|
GET /books | Paginated list with filtering and sorting |
GET /books/:id | Single record |
POST /books | Create, validated against the Zod schema |
PATCH /books/:id | Update, validated against the Zod schema |
DELETE /books/:id | Delete |
GET /books/schemas | Table / form / view / filter schemas for the frontend |
GET /books/definition | Enabled operations + schemas |
POST /books/procedure/:actionId/:recordId | Row-level actions |
POST /books/table-action/:actionId | Table-level actions |
One application-wide endpoint feeds the frontend navigation:
| Endpoint | Description |
|---|---|
GET /_app/layout | Sidebar items for all resources (respects sidebar.hide / sidebar.position) |
Route prefix
Set prefix in the config to mount every crouton route under a common path segment:
CroutonApiModule.forResourceDir(
resolve(__dirname, 'resources'),
resolve(__dirname, 'data-sources'),
{
baseUrl: 'http://localhost:3000',
prefix: 'api',
},
)With prefix: 'api' the routes become /api/books, /api/_app/layout, /api/crouton/status.json, etc. This is useful when crouton shares a NestJS application with other controllers and you want all crouton routes grouped under a single path prefix without relying on NestJS's global prefix (which would affect all controllers).