XyPriss Routing System
XyPriss provides a flexible routing system with Express-like API but without Express dependency. The routing system supports advanced pattern matching, middleware, and modular route organization.
Table of Contents
- Basic Routing
- Route Parameters
- Wildcard Routes
- Router System
- Middleware
- Advanced Examples
- API Reference
Basic Routing
XyPriss supports all standard HTTP methods with Express-like syntax:
import { createServer } from "xypriss";
const app = createServer();
// Basic HTTP methods
app.get("/", (req, res) => {
res.json({ message: "GET request" });
});
app.post("/users", (req, res) => {
res.json({ message: "POST request", data: req.body });
});
app.put("/users/:id", (req, res) => {
res.json({ message: "PUT request", id: req.params.id });
});
app.delete("/users/:id", (req, res) => {
res.json({ message: "DELETE request", id: req.params.id });
});
app.patch("/users/:id", (req, res) => {
res.json({ message: "PATCH request", id: req.params.id });
});
app.options("/users", (req, res) => {
res.json({ message: "OPTIONS request" });
});
app.head("/users", (req, res) => {
res.status(200).end();
});
Route Parameters
Single Parameters
// Single parameter
app.get("/users/:id", (req, res) => {
const userId = req.params.id;
res.json({ userId });
});
// Parameter with validation
app.get("/posts/:postId", (req, res) => {
const { postId } = req.params;
if (!postId || isNaN(Number(postId))) {
return res.status(400).json({ error: "Invalid post ID" });
}
res.json({ postId: Number(postId) });
});
Multiple Parameters
// Multiple parameters
app.get("/users/:userId/posts/:postId", (req, res) => {
const { userId, postId } = req.params;
res.json({ userId, postId });
});
// Nested resource parameters
app.get("/organizations/:orgId/teams/:teamId/members/:memberId", (req, res) => {
const { orgId, teamId, memberId } = req.params;
res.json({ orgId, teamId, memberId });
});
Wildcard Routes
XyPriss supports two types of wildcards with different behaviors:
Single Wildcard (*) - One Path Segment
The single wildcard * matches exactly one path segment (no forward slashes).
// Matches: /files/document.pdf, /files/image.jpg
// Does NOT match: /files/folder/document.pdf, /files/a/b/c.txt
app.get("/files/*", (req, res) => {
const filename = req.params["*"];
res.json({
message: "Single wildcard match",
filename,
type: "file"
});
});
// Example matches:
// GET /files/document.pdf → { filename: "document.pdf" }
// GET /files/image.jpg → { filename: "image.jpg" }
// GET /files/folder/doc.pdf → 404 (not matched)
Double Wildcard (**) - Multiple Path Segments
The double wildcard ** matches multiple path segments (including forward slashes).
// Matches: /api/v1/users, /api/v1/users/123/posts, /api/v1/admin/settings/security
app.get("/api/**", (req, res) => {
const path = req.params["**"];
res.json({
message: "Double wildcard match",
capturedPath: path,
segments: path.split("/")
});
});
// Example matches:
// GET /api/v1/users → { capturedPath: "v1/users" }
// GET /api/v1/users/123/posts → { capturedPath: "v1/users/123/posts" }
// GET /api/admin/deep/nested/path → { capturedPath: "admin/deep/nested/path" }
Combined Parameters and Wildcards
// Parameter + single wildcard
app.get("/users/:id/files/*", (req, res) => {
const { id } = req.params;
const filename = req.params["*"];
res.json({ userId: id, filename });
});
// Parameter + double wildcard
app.get("/users/:id/data/**", (req, res) => {
const { id } = req.params;
const dataPath = req.params["**"];
res.json({ userId: id, dataPath });
});
Router System
Create modular, reusable route groups using the Router system:
Basic Router Usage
import { createServer, Router } from "xypriss";
const app = createServer();
// Create a router
const userRouter = Router();
// Add routes to router
userRouter.get("/", (req, res) => {
res.json({ message: "Get all users" });
});
userRouter.get("/:id", (req, res) => {
res.json({ message: "Get user", id: req.params.id });
});
userRouter.post("/", (req, res) => {
res.json({ message: "Create user", data: req.body });
});
userRouter.put("/:id", (req, res) => {
res.json({ message: "Update user", id: req.params.id, data: req.body });
});
userRouter.delete("/:id", (req, res) => {
res.json({ message: "Delete user", id: req.params.id });
});
// Mount router at /api/users
app.use("/api/users", userRouter);
Router with Middleware
const adminRouter = Router();
// Router-level middleware
adminRouter.use((req, res, next) => {
console.log("Admin route accessed");
// Simple authentication check
if (!req.headers.authorization) {
return res.status(401).json({ error: "Unauthorized" });
}
next();
});
adminRouter.get("/dashboard", (req, res) => {
res.json({ message: "Admin dashboard" });
});
adminRouter.get("/users", (req, res) => {
res.json({ message: "Admin users list" });
});
app.use("/admin", adminRouter);
Nested Routers
// API v1 router
const v1Router = Router();
v1Router.get("/users", (req, res) => {
res.json({ version: "v1", users: [] });
});
v1Router.get("/posts", (req, res) => {
res.json({ version: "v1", posts: [] });
});
// API v2 router
const v2Router = Router();
v2Router.get("/users", (req, res) => {
res.json({
version: "v2",
users: [],
pagination: { page: 1, limit: 10 }
});
});
v2Router.get("/posts", (req, res) => {
res.json({
version: "v2",
posts: [],
meta: { total: 0 }
});
});
// Mount versioned APIs
app.use("/api/v1", v1Router);
app.use("/api/v2", v2Router);
Middleware
Global Middleware
// Global middleware - applies to all routes
app.use((req, res, next) => {
console.log(`${new Date().toISOString()} - ${req.method} ${req.path}`);
next();
});
// CORS middleware
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
next();
});
Route-Specific Middleware
// Authentication middleware
const authenticate = (req, res, next) => {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ error: "No token provided" });
}
// Validate token (simplified)
if (token !== "Bearer valid-token") {
return res.status(401).json({ error: "Invalid token" });
}
req.user = { id: 1, name: "John Doe" };
next();
};
// Protected route with middleware
app.get("/protected", authenticate, (req, res) => {
res.json({
message: "Protected resource",
user: req.user
});
});
// Multiple middleware functions
app.post("/api/data",
authenticate,
(req, res, next) => {
// Validation middleware
if (!req.body.name) {
return res.status(400).json({ error: "Name is required" });
}
next();
},
(req, res) => {
res.json({
message: "Data created",
data: req.body,
user: req.user
});
}
);
Advanced Examples
File Server with Wildcards
// Static file serving with single wildcard
app.get("/static/*", (req, res) => {
const filename = req.params["*"];
const filepath = path.join(__dirname, "public", filename);
// Security check - prevent directory traversal
if (filename.includes("..")) {
return res.status(400).json({ error: "Invalid filename" });
}
res.sendFile(filepath);
});
// Documentation with double wildcard
app.get("/docs/**", (req, res) => {
const docPath = req.params["**"];
const sections = docPath.split("/");
res.json({
documentPath: docPath,
sections,
breadcrumb: sections.map((section, index) => ({
name: section,
path: sections.slice(0, index + 1).join("/")
}))
});
});
API with Complex Routing
// Product catalog API
const catalogRouter = Router();
// Categories with subcategories (double wildcard)
catalogRouter.get("/categories/**", (req, res) => {
const categoryPath = req.params["**"];
const categories = categoryPath.split("/");
res.json({
categoryPath: categories,
products: `Products in ${categories.join(" > ")}`
});
});
// Product search with single wildcard for search terms
catalogRouter.get("/search/*", (req, res) => {
const searchTerm = req.params["*"];
res.json({
searchTerm,
results: `Search results for "${searchTerm}"`
});
});
// Specific product by ID
catalogRouter.get("/products/:id", (req, res) => {
const { id } = req.params;
res.json({
productId: id,
name: `Product ${id}`,
category: "Electronics"
});
});
app.use("/api/catalog", catalogRouter);
API Reference
App Methods
app.get(path, ...handlers)- Handle GET requestsapp.post(path, ...handlers)- Handle POST requestsapp.put(path, ...handlers)- Handle PUT requestsapp.delete(path, ...handlers)- Handle DELETE requestsapp.patch(path, ...handlers)- Handle PATCH requestsapp.options(path, ...handlers)- Handle OPTIONS requestsapp.head(path, ...handlers)- Handle HEAD requestsapp.use(path?, middleware)- Add middleware or mount router
Router Methods
Router()- Create a new router instancerouter.get(path, ...handlers)- Add GET route to routerrouter.post(path, ...handlers)- Add POST route to routerrouter.put(path, ...handlers)- Add PUT route to routerrouter.delete(path, ...handlers)- Add DELETE route to routerrouter.patch(path, ...handlers)- Add PATCH route to routerrouter.options(path, ...handlers)- Add OPTIONS route to routerrouter.head(path, ...handlers)- Add HEAD route to routerrouter.use(middleware)- Add middleware to router
Route Patterns
/path- Exact path match/path/:param- Parameter capture/path/*- Single wildcard (one segment)/path/**- Double wildcard (multiple segments)/path/:param/*- Combined parameter and wildcard/path/:param/**- Combined parameter and multi-wildcard
Request Object
req.params- Route parameters objectreq.query- Query string parametersreq.body- Request body (parsed)req.headers- Request headersreq.method- HTTP methodreq.path- Request pathreq.url- Full request URL
Response Object
res.json(data)- Send JSON responseres.send(data)- Send responseres.status(code)- Set status coderes.setHeader(name, value)- Set response headerres.redirect(url)- Redirect response