HTTP Routes
Colyseus provides two ways to add HTTP endpoints to your server:
- API Routes (recommended) — Type-safe, with validation, middleware, frontend SDK integration, and visual testing via the Playground.
- Express — Use if you rely on existing Express middleware or libraries.
API Routes
Define type-safe HTTP endpoints using createEndpoint and createRouter.
import { defineServer, createEndpoint, createRouter } from "colyseus";
import { z } from "zod";
const getProfile = createEndpoint("/profile/:id", {
method: "GET",
query: z.object({ include: z.string().optional() }),
}, async (ctx) => {
return {
id: ctx.params.id,
include: ctx.query.include,
};
});
const updateProfile = createEndpoint("/profile/:id", {
method: "POST",
body: z.object({ name: z.string() }),
}, async (ctx) => {
ctx.setStatus(201);
return { id: ctx.params.id, name: ctx.body.name };
});
const server = defineServer({
routes: createRouter({
getProfile,
updateProfile,
})
});Middleware
Use createMiddleware to share logic across endpoints. The returned context is merged into ctx.context.
import { createEndpoint, createMiddleware } from "colyseus";
const auth = createMiddleware(async (ctx) => {
const token = ctx.headers.get("authorization");
if (!token) throw ctx.error("UNAUTHORIZED", { message: "Missing token" });
return { userId: "user-123" };
});
export const secureEndpoint = createEndpoint("/secure", {
method: "GET",
use: [auth],
}, async (ctx) => {
ctx.setHeader("X-User", ctx.context.userId);
ctx.setCookie("session", "abc", { httpOnly: true });
return { ok: true, userId: ctx.context.userId };
});Endpoint Options
createEndpoint(path, options, handler) accepts the following options:
| Option | Description |
|---|---|
method | HTTP method string or array (e.g. "GET" or ["GET", "POST"]). |
body | Zod schema for request body validation. Invalid bodies return 400. |
query | Zod schema for query string validation. Invalid queries return 400. |
use | Array of middlewares created with createMiddleware. |
requireHeaders | When true, requires headers when calling the endpoint as a function. |
requireRequest | When true, requires a request object when calling the endpoint as a function. |
metadata.scope | "rpc" (default): available to RPC client. "server": callable directly only. "http": routed only. |
metadata.allowedMediaTypes | Restricts accepted Content-Type values for this endpoint. |
Handler Context
The handler signature is async (ctx) => response.
Properties
| Property | Description |
|---|---|
ctx.request | The raw Request object (when running via HTTP). |
ctx.headers | Headers instance for the incoming request. |
ctx.body | Parsed and validated request body. |
ctx.query | Parsed and validated query string. |
ctx.params | Route parameters (e.g. :id, **:name). |
ctx.method | HTTP method (useful for multi-method endpoints). |
ctx.context | Merged middleware context. |
Methods
| Method | Description |
|---|---|
ctx.setStatus(status) | Override the default success status code. |
ctx.error(codeOrStatus, data?, headers?) | Throw an API error. |
ctx.redirect(url) | Throw a redirect response. |
ctx.json(data) | Return a JSON response. |
ctx.setHeader(name, value) | Set a response header. |
ctx.setCookie(name, value, options?) | Set a response cookie. |
ctx.getCookie(name) | Read a request cookie. |
ctx.setSignedCookie(name, value, options?) | Set a signed cookie. |
ctx.getSignedCookie(name) | Read a signed cookie. |
Express Routes
Use Express if you rely on existing Express middleware or libraries.
import { defineServer } from "colyseus";
import express from "express";
const server = defineServer({
// ...
express: (app) => {
app.use(express.json({ limit: "100kb" }));
app.get("/hello", (req, res) => {
res.json({ hello: "world" });
});
app.post("/profile", (req, res) => {
res.json({ received: req.body });
});
},
// ...
});See the Express routing guide for more details.
CORS
CORS is enabled by default. You can customize the headers:
import { matchMaker } from "colyseus";
matchMaker.controller.DEFAULT_CORS_HEADERS = {
'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept, Authorization',
'Access-Control-Allow-Methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Origin': '*',
'Access-Control-Max-Age': '2592000',
// ...
}You can also return custom CORS headers based on the request:
import { matchMaker } from "colyseus";
matchMaker.controller.getCorsHeaders = function(requestHeaders) {
// check for 'requestHeaders' and return custom key-value headers here.
return {};
}See MDN documentation on CORS for more information.
Frontend Usage
Use client.http.* methods to call your HTTP endpoints from the frontend.
See Client SDK → HTTP Requests for the full API reference.