Validation
Use Elysia schemas directly for request validation and end-to-end inferred types.
#Basics
Validate request bodies where the route is defined:
TS
import { Elysia, t } from 'elysia';
new Elysia()
.post('/api/users', ({ body }) => createUser(body), {
body: t.Object({
name: t.String({ minLength: 2 }),
email: t.String({ format: 'email' })
})
});#Params & Query
Define params and query schema together to avoid untyped request parsing:
TS
import { Elysia, t } from 'elysia';
new Elysia()
.get('/api/users/:id', ({ params, query }) => {
return getUser(params.id, query.expand);
}, {
params: t.Object({
id: t.String()
}),
query: t.Object({
expand: t.Optional(t.Boolean())
})
});#Typed Responses
Attach response schemas for status-specific return shapes:
TS
import { Elysia, t } from 'elysia';
new Elysia()
.post('/api/projects', ({ body, set }) => {
const project = createProject(body);
set.status = 201;
return project;
}, {
body: t.Object({
name: t.String()
}),
response: {
201: t.Object({
id: t.String(),
name: t.String()
}),
400: t.Object({
error: t.String()
})
}
});#Guarded Validation
Use guard to enforce shared constraints for route groups:
TS
import { Elysia, t } from 'elysia';
new Elysia()
.guard(
{
headers: t.Object({
authorization: t.TemplateLiteral('Bearer ${string}')
})
},
(app) =>
app
.get('/api/private/profile', ({ headers }) =>
getProfile(headers.authorization)
)
.get('/api/private/settings', ({ headers }) =>
getSettings(headers.authorization)
)
);