Vafast Quick Start
Get a Vafast server running in a few minutes. This page covers install → Hello → Schema → common request types → simple middleware. For splitting CRUD into files and nested routes, follow the Tutorial.
Create a Project
npx create-vafast-app
cd my-vafast-app
npm install
npm run devmkdir my-vafast-app && cd my-vafast-app
npm init -y
npm install vafast
npm install -D typescript tsx @types/nodeAfter scaffolding, open localhost:3000 to see the welcome page.
For a manual setup, add this to package.json:
{
"type": "module",
"scripts": {
"dev": "tsx watch src/index.ts",
"start": "tsx src/index.ts"
}
}A tsconfig.json you can use:
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "dist",
"rootDir": "src"
},
"include": ["src/**/*"]
}Hello Vafast
Create src/index.ts:
import { Server, defineRoute, defineRoutes, serve } from 'vafast'
const routes = defineRoutes([
defineRoute({
method: 'GET',
path: '/',
handler: () => 'Hello Vafast!',
}),
])
const server = new Server(routes)
serve({ fetch: server.fetch, port: 3000 }, () => {
console.log('http://localhost:3000')
})npm run devOpen http://localhost:3000 in your browser and you should see Hello Vafast!.
Schema
Declare a schema with Type: validation failures return 422 automatically, and fields in the handler are typed for you.
import { defineRoute, Type } from 'vafast'
const CreateUser = Type.Object({
name: Type.String({ minLength: 1 }),
age: Type.Optional(Type.Number({ minimum: 0 })),
})
defineRoute({
method: 'POST',
path: '/users',
schema: { body: CreateUser },
handler: ({ body }) => ({ id: '1', name: body.name, age: body.age ?? 18 }),
})| schema field | Purpose |
|---|---|
body | JSON request body |
query | Query string |
params | Path :id |
When validation fails, the handler is never called; the framework returns HTTP 422 directly:
{
"code": 422,
"message": "Request validation failed",
"details": [
{
"location": "body",
"path": "/name",
"field": "name",
"message": "Expected string length greater or equal to 1",
"value": ""
}
]
}| Field | Description |
|---|---|
details[].location | body / query / params, etc. |
details[].field | Field path, e.g. name, receiver.email |
details[].message | Original TypeBox message (English) |
details[].value | The actual value that triggered the error (optional) |
See Validation for more.
Common Request Types
Set the method with method and constrain inputs with schema:
import { defineRoute, defineRoutes, Type } from 'vafast'
const routes = defineRoutes([
// GET + path / query params
defineRoute({
method: 'GET',
path: '/users/:id',
schema: {
params: Type.Object({ id: Type.String() }),
query: Type.Object({
verbose: Type.Optional(Type.Boolean()),
}),
},
handler: ({ params, query }) => ({
id: params.id,
verbose: query.verbose ?? false,
}),
}),
// POST + body
defineRoute({
method: 'POST',
path: '/users',
schema: {
body: Type.Object({ name: Type.String({ minLength: 1 }) }),
},
handler: ({ body }) => ({ id: '1', name: body.name }),
}),
// PUT / PATCH
defineRoute({
method: 'PUT',
path: '/users/:id',
schema: {
params: Type.Object({ id: Type.String() }),
body: Type.Object({ name: Type.String() }),
},
handler: ({ params, body }) => ({ id: params.id, ...body }),
}),
// DELETE
defineRoute({
method: 'DELETE',
path: '/users/:id',
schema: { params: Type.Object({ id: Type.String() }) },
handler: ({ params }) => {
console.log('deleted', params.id)
return null // → 204 No Content
},
}),
])Just return a value from the handler: 'text' → text/plain, { ok: true } → JSON, null → 204.
Simple Middleware
import { defineMiddleware, defineRoute } from 'vafast'
const log = defineMiddleware(async (req, next) => {
const start = Date.now()
const res = await next()
console.log(`${req.method} ${new URL(req.url).pathname} ${res.status} ${Date.now() - start}ms`)
return res
})
defineRoute({
method: 'GET',
path: '/',
middleware: [log],
handler: () => 'Hello Vafast!',
})
// Global: server.use(log)Use next({ ... }) to inject data into the handler:
const withUser = defineMiddleware(async (req, next) => {
return next({ userId: req.headers.get('x-user-id') ?? 'guest' })
})
defineRoute({
method: 'GET',
path: '/me',
middleware: [withUser],
handler: ({ userId }) => ({ userId }),
})See Tutorial · Middleware for more.
What You've Learned
| API | Purpose |
|---|---|
Type + schema | Request validation and type inference |
defineRoute / defineRoutes | Define routes |
defineMiddleware | Middleware; next() / next({ ctx }) |
Server + serve | Create the app and listen on a port |
Next Steps
Continue with the Tutorial: split files and nest routes. To understand how it works first, read Key Concepts.