Request Handling
Work with HTTP requests and responses in JustScale
HTTP routes receive a context object containing request data (params, body,query, headers) and a response helper (res).
The Request Context
Every HTTP route handler receives a context object with transport-specific properties:
import { createController } from '@justscale/core';
import { Get } from '@justscale/http';
export const UsersController = createController('/users', {
routes: () => ({
getOne: Get('/:id').handle(({ params, body, query, headers, res }) => {
// params: Route parameters extracted from the URL path
// body: Parsed JSON request body (POST/PUT/PATCH)
// query: Query string parameters
// headers: Request headers
// res: Response helper for sending responses
}),
}),
});The Response Object
The res object provides methods for sending HTTP responses. Always pair with .returns() to declare response types:
res.json(data)
Send a JSON response with 200 status:
import { createController } from '@justscale/core';
import { Get } from '@justscale/http';
import { UsersResponse } from '../schemas/user';
export const UsersController = createController('/users', {
routes: () => ({
list: Get('/')
.returns(UsersResponse)
.handle(({ res }) => {
res.json({ users: [{ id: '1', name: 'Alice' }] });
// HTTP 200 with Content-Type: application/json
}),
}),
});res.status(code).json(data)
Send a JSON response with a custom status code:
import { createController } from '@justscale/core';
import { Post } from '@justscale/http';
import { body } from '@justscale/http/builder';
import { UserService } from '../services/user-service';
import { UserResponse, ErrorResponse, CreateUserBody } from '../schemas/user';
export const UsersController = createController('/users', {
inject: { users: UserService },
routes: (services) => ({
create: Post('/')
.apply(body(CreateUserBody))
.returns(UserResponse, 201)
.returns(ErrorResponse, 400)
.handle(async ({ body, res }) => {
const user = await services.users.create(body);
res.status(201).json({ user });
// HTTP 201 Created
}),
}),
});res.status(code).end()
Send an empty response (for void responses like 204):
import { createController } from '@justscale/core';
import { Delete } from '@justscale/http';
import { populate } from '@justscale/http';
import { UserService } from '../services/user-service';
export const UsersController = createController('/users', {
inject: { users: UserService },
routes: (services) => ({
delete: Delete('/:userId')
.use(populate(services.users, 'user', 'userId'))
.returns(204)
.returns(404)
.handle(async ({ user, res }) => {
await services.users.delete(user.id);
res.status(204).end();
// HTTP 204 No Content
}),
}),
});res.error(message, status?)
Send an error response (default 400):
import { createController } from '@justscale/core';
import { Get } from '@justscale/http';
import { UserResponse, ErrorResponse } from '../schemas/user';
export const UsersController = createController('/users', {
routes: () => ({
getOne: Get('/:id')
.returns(UserResponse)
.returns(ErrorResponse, 400)
.returns(404)
.handle(({ params, res }) => {
if (!params.id) {
return res.status(400).json({ error: 'User ID is required' });
}
// Continue processing...
}),
}),
});Headers
Access request headers through the headers object:
import { createController } from '@justscale/core';
import { Get } from '@justscale/http';
export const ProfileController = createController('/profile', {
routes: () => ({
getProfile: Get('/').handle(({ headers, res }) => {
const authHeader = headers.authorization;
const userAgent = headers['user-agent'];
if (!authHeader) {
res.error('Authorization header required', 401);
return;
}
res.json({ authenticated: true });
}),
}),
});Info
Cookies
Cookies are available in the headers.cookie string. You can parse them manually or use a middleware:
import { createController } from '@justscale/core';
import { Get } from '@justscale/http';
export const SessionController = createController('/', {
routes: () => ({
checkSession: Get('/check-session').handle(({ headers, res }) => {
const cookieHeader = headers.cookie;
// cookieHeader = "session=abc123; theme=dark"
// Parse cookies manually
const cookies = Object.fromEntries(
cookieHeader?.split('; ').map(c => c.split('=')) ?? []
);
res.json({ sessionId: cookies.session });
}),
}),
});Auto-Response Handling
If your handler doesn't send a response, JustScale automatically sends a 204 No Content:
import { createController } from '@justscale/core';
import { Get } from '@justscale/http';
export const HealthController = createController('/', {
routes: () => ({
ping: Get('/ping').handle(() => {
// No response sent - JustScale sends 204 No Content
}),
}),
});Warning
Error Handling
If a handler throws an error, JustScale catches it and sends a 500 response:
import { createController } from '@justscale/core';
import { Get } from '@justscale/http';
import { DataResponse } from '../schemas/data';
export const RiskyController = createController('/', {
routes: () => ({
risky: Get('/risky')
.returns(DataResponse)
.returns(500) // Document that this can fail
.handle(({ res }) => {
throw new Error('Something went wrong!');
// JustScale sends: {"error": "Something went wrong!"} with status 500
}),
}),
});For controlled error responses, declare them with .returns():
import { createController } from '@justscale/core';
import { Get } from '@justscale/http';
import { populate } from '@justscale/http';
import { UserService } from '../services/user-service';
import { UserResponse, ErrorResponse } from '../schemas/user';
export const UsersController = createController('/users', {
inject: { users: UserService },
routes: (services) => ({
// With populate middleware
getOne: Get('/:userId')
.use(populate(services.users, 'user', 'userId'))
.returns(UserResponse)
.returns(404) // populate handles this automatically
.handle(({ user, res }) => {
res.json({ user });
}),
// Or with manual error handling:
getOneManual: Get('/manual/:id')
.returns(UserResponse)
.returns(ErrorResponse, 404)
.handle(async ({ params, res }) => {
const user = await services.users.findById(params.id);
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
res.json({ user });
}),
}),
});Multiple Responses
Warning
res.json() orres.error() are ignored:import { createController } from '@justscale/core';
import { Get } from '@justscale/http';
export const ExampleController = createController('/', {
routes: () => ({
example: Get('/example').handle(({ res }) => {
res.json({ message: 'First' });
res.json({ message: 'Second' }); // Ignored - response already sent
}),
}),
});