Status code
StatusCode is the canonical enum that ExpressoTS uses everywhere a status code crosses a boundary: controller responses, AppError constructors, @Http() decorators, exception filters. It maps the standard RFC 9110 status codes to typed numbers, eliminating the magic-number sprawl that creeps into Express apps.
import { StatusCode } from "@expressots/core";
StatusCode.OK; // 200
StatusCode.Created; // 201
StatusCode.NoContent; // 204
StatusCode.BadRequest; // 400
StatusCode.Unauthorized; // 401
StatusCode.Forbidden; // 403
StatusCode.NotFound; // 404
StatusCode.Conflict; // 409
StatusCode.UnprocessableEntity; // 422
StatusCode.TooManyRequests; // 429
StatusCode.InternalServerError; // 500
StatusCode.BadGateway; // 502
StatusCode.ServiceUnavailable; // 503
Five families:
- 1xx: informational responses (rarely used directly)
- 2xx: successful responses
- 3xx: redirection
- 4xx: client errors
- 5xx: server errors
See the MDN status code reference for the full meaning of each code.
Where to use it
@Http(...) decorator
The cleanest pattern: declare the success status next to the route, return the body, and let the framework do the wiring.
import { controller, Get, Http, Post, body } from "@expressots/adapter-express";
import { StatusCode } from "@expressots/core";
@controller("/users")
export class UsersController {
@Post("/")
@Http(StatusCode.Created)
create(@body() dto: CreateUserDTO) {
return this.users.create(dto);
}
@Get("/:id")
@Http(StatusCode.OK)
getById(@param("id") id: string) {
return this.users.findById(id);
}
}
Direct res.status(...)
When you need to choose the status at runtime (e.g. 200 vs 201 vs 304):
import { controller, Get, response } from "@expressots/adapter-express";
import { StatusCode } from "@expressots/core";
import type { Response } from "express";
@controller("/cache")
export class CacheController {
@Get("/:key")
fetch(@response() res: Response, @param("key") key: string) {
const cached = this.cache.get(key);
if (cached === undefined) {
return res.status(StatusCode.NotFound).send();
}
if (cached.notModified) {
return res.status(StatusCode.NotModified).send();
}
return res.status(StatusCode.OK).json(cached.value);
}
}
Inside AppError and Report.Error()
Errors thrown anywhere in the request pipeline carry a status code through to the response:
import { AppError, NotFoundError, StatusCode } from "@expressots/core";
if (!user) {
throw new NotFoundError(`User ${id} not found`, "users.get");
}
if (await this.users.findByEmail(email)) {
throw new AppError(StatusCode.Conflict, "Email already in use", "users.create");
}
// Or with the Report helper:
throw this.report.Error("User already exists", StatusCode.BadRequest, "users.create");
The exception filter pipeline turns these into RFC 7807 problem-details responses with the right status code automatically. See Error handling.
Inside use cases
import { provide, Report, StatusCode } from "@expressots/core";
@provide(CreateUserUseCase)
export class CreateUserUseCase {
constructor(
private readonly users: UserRepository,
private readonly report: Report,
) {}
async execute(data: ICreateUserRequestDTO): Promise<ICreateUserResponseDTO> {
const { name, email } = data;
if (await this.users.findByEmail(email)) {
throw this.report.Error(
"User already exists",
StatusCode.BadRequest,
"users.create",
);
}
const user = await this.users.create(new User(name, email));
return { id: user.id, name: user.name, email: user.email, status: "success" };
}
}
Why use the enum?
- Refactor-safe: your IDE rejects typos.
- Searchable:
StatusCode.Conflictis greppable;409is not. - Consistent: the framework also uses
StatusCodein its built-in errors and filters, so your code matches its output.
See also
- Error handling:
AppError,Report.Error, RFC 7807 responses. - Exception filters: custom error → response mapping.