Define a Route
Create your first route
Note: In this example we’ll keep everything in src/index.ts for simplicity. For real projects, it’s recommended to separate your code into:
- Controllers files → to organize your routes.
- Zod Schemas files → to keep validation logic clean and reusable.
src/index.ts
import { App, cors, secureHeaders, signals } from "@crumbjs/core";
import { indexController } from "./modules/index/index.controller";
import z from "zod";
const app = new App();
app.prefix("api");
app.use(signals(true));
app.use(secureHeaders());
app.use(indexController);
app.post(
"/posts",
// Pick the values and tools you need from Context
async ({ body, setStatus }) => {
// Here you can do real things with body, like inserting on a db
// Set 201 Status code
setStatus(201);
return body; // your framework will JSON-serialize it
},
// Route Config (all the parameters are optionals)
{
// Content-Type definition throws if is not the same from the request (also document openapi media type)
type: "application/json",
// Validate + document the body (Zod drives both)
body: z.object({
title: z.string().min(10).max(50).meta({ example: "My new post" }),
slug: z
.string()
.regex(/^[a-z0-9-]+$/i, "Use letters, numbers, and dashes only")
.optional()
.meta({ example: "my-new-post" }),
content: z
.string()
.min(150)
.meta({ example: "Write at least 150 chars of useful content..." }),
}),
// headers: z.object(...) // Same as body: Validate + Document
// query: z.object(...) // Same as body: Validate + Document
// extra OpenAPI metadata
summary: "Create a post",
description:
"Creates a blog post. If `slug` is omitted, it is generated from `title`.",
tags: ["Posts"],
operationId: "createPost",
// hide: true, // to dont show the route in openapi
}
);
app.serve();
** you can use fluent way like index.ts comes by default
See your api documentation working
- By default is on /reference path Link following the exact example http://localhost:8080/reference#tag/posts/post/api/posts