Collections
A collection describes one resource with its type, route, model, schema, validation and routes
A collection is the unit you build a StarkForge backend from. It is one plain object that describes a resource or a feature: what kind it is, where it lives in the URL, how its data is stored, how requests are checked and which endpoints exist. You pass a list of collections to new Forge, and StarkForge builds the rest.
A Complete Collection
This is the products collection that the documentation uses everywhere. It has a stored schema, two validation groups and eight routes:
// src/collections/products.ts
import { collection, defineRoutes, fields } from "@starklabs/forge";
import { z } from "zod";
export const products = collection({
type: "crud",
route: "products",
model: "Product",
schema: {
name: fields.requiredString,
price: fields.requiredNumber,
sku: { mongoose: { type: String, unique: true, sparse: true }, zod: z.string().optional() },
},
validations: {
create: { name: z.string().min(1).max(120), price: z.number().min(0), sku: z.string().optional() },
update: { name: z.string().min(1).max(120).optional(), price: z.number().min(0).optional() },
},
routes: defineRoutes([
{ method: "get", path: "/", handler: "readAll", auth: "public" },
{ method: "get", path: "/:id", handler: "read", auth: "public" },
{ method: "post", path: "/", handler: "create", auth: "authenticated", roles: ["editor", "admin"], validation: "create" },
{ method: "post", path: "/bulk", handler: "createBulk", auth: "authenticated", roles: ["editor", "admin"], validation: "create" },
{ method: "patch", path: "/update/:id", handler: "update", auth: "authenticated", roles: ["editor", "admin"], validation: "update" },
{ method: "delete", path: "/delete/:id", handler: "remove", auth: "admin" },
{ method: "delete", path: "/delete-many", handler: "removeMultiple", auth: "admin" },
{ method: "delete", path: "/delete-all", handler: "removeAll", auth: "admin" },
]),
});The Keys of a Collection
| Key | Required | What it is |
|---|---|---|
type | Always | The kind of collection: "crud", "auth", "account" or "health" |
route | Always | The URL segment of the collection, such as products. It must start with a letter or a digit and may contain letters, digits, /, _ and - |
routes | Always | The list of endpoints. See Routes |
model | crud and auth | The model name, singular and capitalized, such as Product |
schema | crud and auth | The fields that are stored. See Schemas |
validations | When a route reads a body | Named groups of Zod rules that check request bodies. See Validation |
The URL of a route is /api/v{apiVersion}/{route} followed by the path of the route, so with the default apiVersion the products collection serves /api/v1/products. A route that contains a slash, such as shop/products, gives a longer path, /api/v1/shop/products.
Collection Types
| Type | Use it for | Where it comes from |
|---|---|---|
crud | A resource stored in the database, with read, list, create, update, delete and file handlers | You write it. See CRUD Collections |
auth | Sign-up, sign-in, sessions and the other ways to prove who a user is | Generated from builtinConfig.auth, or written by you when you need full control. See Authentication |
account | The signed-in user's own profile and role | Generated from builtinConfig.account |
health | The health check | Added automatically |
The type decides which handler names a route may use, and the Handlers page lists them. A crud collection must have a model and a schema, and so must an auth collection. An account collection needs a user model, which comes from the built-in or custom auth collection. A health collection needs neither.
There is also an admin type. It is deprecated and only exposes GET /admin/check. Use GET /account/role from the account collection instead, as the Authorization page explains.
The Two Helpers
collection() and defineRoutes() return exactly what you give them. They exist so that your editor can autocomplete keys and flag a wrong handler or auth value as you type. A plain object works just as well.
What Start-up Does With a Collection
- 1
- The
routeis checked against the allowed characters. - The module for the
typeregisters the model and compiles the schema. - Every route is checked: its handler must exist for the type, its validation group must exist and its settings must agree with each other.
- The routes are mounted under
/api/v1and the route name.
- The
If a collection has a mistake, StarkForge throws one ConfigurationError that lists every problem of that collection. build() throws it, and start() calls build(), so the server never starts with a broken collection. This real error has three problems at once:
ConfigurationError (CONFIGURATION_ERROR): Invalid 'things' collection:
- GET /things/: handler 'list' is not available for collections of type 'crud'. Available: read, readAll, create, createBulk, update, remove, removeMultiple, removeAll, addFile, updateFile, deleteFile.
- POST /things/: validation 'nope' is not defined in the collection's 'validations'.
- DELETE /things/delete-all: 'removeAll' must use auth 'admin' or 'admin-or-owner' - otherwise any caller could wipe the whole collection.The first line names the collection by its route. Every following line starts with the HTTP method and the full path of the route that has the problem, then says what is wrong and, when it can, what the valid choices are. Fix all the lines, then start again.
Collections That Share a Model
StarkForge keeps one model for each model name. When two collections use the same model, the first collection that StarkForge prepares registers the model, and the schema of the other one is not used. Generated collections are prepared first, then yours in the order of the collections list.
If two collections use the same model but different schemas, the second schema is ignored without a warning. Share one schema object between them instead.
Where to Go Next
Schemas
Describe your data once with field helpers.
Handlers
See which handlers each collection type offers.
:::