Routes
For every model in your Prisma schema, Arkos automatically generates a full set of RESTful endpoints. The model name is converted to kebab-case and pluralized for the route path.
Example: A UserProfile model is accessible at /api/user-profiles.
| Method | Endpoint | Description | Operation |
|---|---|---|---|
| GET | /api/[model] | List records | findMany |
| POST | /api/[model] | Create one record | createOne |
| GET | /api/[model]/:id | Get one record | findOne |
| PATCH | /api/[model]/:id | Update one record | updateOne |
| DELETE | /api/[model]/:id | Delete one record | deleteOne |
| POST | /api/[model]/many | Create multiple records | createMany |
| PATCH | /api/[model]/many | Update multiple records | updateMany |
| DELETE | /api/[model]/many | Delete multiple records | deleteMany |
All routes are mounted under your configured globalPrefix (default: /api).
See Configuration for more.
Configuring Model Routes
Every generated endpoint accepts the same configuration object used in ArkosRouter — disable routes, add rate limiting, authentication, and more via the Route Hook in your router file src/modules/<model>/<model>.router.ts where each key maps to the operation name from the table above:
import { ArkosRouter, RouterConfig, RouteHook } from "arkos";
import postPolicy from "@/src/modules/post/post.policy";
import UpdateUserSchema from "@/src/modules/post/schemas/post.schema";
export const hook: RouteHook = {
findMany: { authentication: false },
findOne: { authentication: true },
createOne: { authentication: postPolicy.Create },
updateOne: { validation: { body: UpdateUserSchema } },
deleteOne: { disabled: true },
createMany: { disabled: true },
updateMany: { disabled: true },
deleteMany: { disabled: true }
};
const router = ArkosRouter();
export default router;RouteHook is the new name for export const config: RouterConfig introduced in v1.6. The old name still works but will log a deprecation warning. See Route Hook for the full guide.
See the full configuration object reference at ArkosRouter Configuration Object.
Intercepting Model Requests
Every generated endpoint can be intercepted — run logic before or after any operation without replacing the built-in behavior. For example, to log every time a post is created:
import { ArkosRequest, ArkosResponse, ArkosNextFunction } from "arkos";
export const afterCreateOne = [
async (req: ArkosRequest, res: ArkosResponse, next: ArkosNextFunction) => {
console.log("Post created:", res.locals.data);
next();
},
];See Prisma Model Interceptors for the full list of available hooks and what you can do with them.
Sending Model Requests
The examples below use a Post model. Requests that require authentication pass the token via the Authorization header — it can also be sent through cookies, which are set automatically on login depending on your configuration.
Find Many Posts
GET /api/posts
Authorization: Bearer YOUR_API_TOKENResponse:
{
"total": 42,
"results": 10,
"data": [
{
"id": "1",
"title": "Getting Started with Arkos",
"content": "...",
"authorId": "123",
"published": true,
"createdAt": "2025-04-05T14:23:45.123Z",
"updatedAt": "2025-04-05T14:23:45.123Z"
}
]
}Find One Post
GET /api/posts/1Response:
{
"data": {
"id": "1",
"title": "Getting Started with Arkos",
"content": "...",
"authorId": "123",
"published": true,
"createdAt": "2025-04-05T14:23:45.123Z",
"updatedAt": "2025-04-05T14:23:45.123Z"
}
}Create One Post
POST /api/posts
Content-Type: application/json
Authorization: Bearer YOUR_API_TOKEN{
"title": "My New Post",
"content": "Post content here",
"authorId": "123",
"published": false
}Response:
{
"data": {
"id": "42",
"title": "My New Post",
"content": "Post content here",
"authorId": "123",
"published": false,
"createdAt": "2025-04-05T14:23:45.123Z",
"updatedAt": "2025-04-05T14:23:45.123Z"
}
}Create Multiple Posts
POST /api/posts/many
Content-Type: application/json
Authorization: Bearer YOUR_API_TOKEN[
{ "title": "First Post", "content": "...", "authorId": "123" },
{ "title": "Second Post", "content": "...", "authorId": "123" }
]Response:
{
"total": 2,
"results": 2,
"data": [
{
"id": "43",
"title": "First Post",
"content": "...",
"authorId": "123",
"createdAt": "2025-04-05T14:23:45.123Z",
"updatedAt": "2025-04-05T14:23:45.123Z"
},
{
"id": "44",
"title": "Second Post",
"content": "...",
"authorId": "123",
"createdAt": "2025-04-05T14:23:45.123Z",
"updatedAt": "2025-04-05T14:23:45.123Z"
}
]
}Update One Post
PATCH /api/posts/1
Content-Type: application/json
Authorization: Bearer YOUR_API_TOKEN{
"title": "Updated Title",
"published": true
}Response:
{
"data": {
"id": "1",
"title": "Updated Title",
"content": "...",
"authorId": "123",
"published": true,
"createdAt": "2025-04-05T14:23:45.123Z",
"updatedAt": "2025-04-05T15:30:12.456Z"
}
}Update Multiple Posts
Filters are passed as query parameters — all matched records are updated with the request body.
PATCH /api/posts/many?authorId=123&published=false
Content-Type: application/json
Authorization: Bearer YOUR_API_TOKEN{
"published": true
}Response:
{
"total": 5,
"results": 5,
"data": [
{
"id": "2",
"title": "Draft Post",
"published": true,
"updatedAt": "2025-04-05T15:30:12.456Z"
}
]
}Delete One Post
DELETE /api/posts/1
Authorization: Bearer YOUR_API_TOKENResponse: 204 No Content
Delete Multiple Posts
Filters are passed as query parameters — all matched records are deleted.
DELETE /api/posts/many?authorId=123&published=false
Authorization: Bearer YOUR_API_TOKENResponse:
{
"total": 3,
"results": 3,
"data": [
{ "id": "7", "title": "Deleted Draft Post" }
]
}Bulk delete requires at least one filter query parameter. Sending DELETE /api/posts/many with no filters will return a 400 error to prevent accidental mass deletion.
Querying
All list endpoints (GET /api/[model]) support a rich set of query parameters that translate directly into Prisma queries.
Arkos supports two interchangeable syntaxes — use whichever feels natural, or mix them in the same request:
- Bracket notation:
price[gte]=50&price[lt]=100 - Django-style:
price__gte=50&price__lt=100
Filtering
Basic filtering matches records where any of the conditions are true (OR by default):
GET /api/posts?published=true&authorId=123To switch to AND logic, use filterMode:
GET /api/posts?filterMode=AND&published=true&authorId=123Comparison operators:
GET /api/products?price[gte]=50&price[lt]=100
# or
GET /api/products?price__gte=50&price__lt=100Supported operators: gte, gt, lte, lt, contains, startsWith, endsWith, in, notIn, and all other Prisma filter operators.
Nested / relational filtering:
GET /api/posts?author[age]=30&comments[some][content][contains]=interesting
# or
GET /api/posts?author__age=30&comments__some__content__contains=interestingSearch
Full-text search across all string fields except those ending in id, ids, ID, or IDs:
GET /api/posts?search=arkosThis generates a case-insensitive contains check across every eligible string field on the model.
Sorting
Prefix a field with - for descending order. Comma-separate multiple fields:
GET /api/posts?sort=-createdAt,titleThis sorts by createdAt descending, then title ascending.
Pagination
GET /api/posts?page=2&limit=20limit defaults to 30. The response always includes total (all matching records) and results (records returned in this page).
Field Selection
Select specific fields:
GET /api/posts?fields=id,title,publishedInclude a relation (adds to default fields):
GET /api/posts?fields=+authorExclude specific fields:
GET /api/posts?fields=-content,-updatedAtYou can combine these in a single request:
GET /api/posts?fields=id,title,+author,-updatedAtCombining Parameters
All query parameters work together:
GET /api/posts?search=arkos&published=true&sort=-createdAt&page=1&limit=10&fields=id,title,+authorError Responses
// 404 - Record not found
{
"code": "PostNotFound",
"message": "Post with id '999' not found."
}
// 400 - Missing filters on bulk operation
{
"code": "MissingFilterCriteria",
"message": "Filter criteria not provided for bulk deletion."
}For the full list of possible errors, see Error Handling.
Customizing Model Routes
- Interceptors — Run logic before or after any generated endpoint
- Authentication — Control which endpoints require authentication and which roles can access them
- Validation — Add request body and query parameter validation