Documentation menu
Package

serez-http

HTTP and WebSocket server for Serez Code — Express/Flask-style API with built-in rate limiting, CORS, and middleware support.

Install

sz install serez-http

Quick start

import "serez-http"

const app = new App()

app.GET("/", fn(req, res) {
    res.json({"message": "hello from serez-http"})
})

app.GET("/user/:id", fn(req, res) {
    let id = req["params"]["id"]
    res.json({"user_id": id})
})

app.POST("/echo", fn(req, res) {
    let data = JSON.parse(req["body"])
    res.json(data)
})

app.listen(3000, fn() {
    out "server running on port 3000"
})

Routes

Register handlers with GET, POST, PUT, and delete. Route patterns support :param segments captured in req["params"]:

app.GET("/posts/:id/comments/:cid", fn(req, res) {
    let post_id    = req["params"]["id"]
    let comment_id = req["params"]["cid"]
    res.status(200).json({"post": post_id, "comment": comment_id})
})

Request object

FieldTypeDescription
req["method"]stringHTTP verb: GET, POST, PUT, DELETE
req["path"]stringURL path without query string
req["query"]dictParsed query parameters
req["params"]dictRoute :param captures
req["body"]stringRaw request body
req["headers"]dictAll request headers (lowercase keys)
req["content_type"]stringContent-Type header value
req["authorization"]stringAuthorization header value
req["host"]stringHost header value
req["ip"]stringClient IP (from X-Forwarded-For)

Response methods

MethodDescription
res.json(obj)Send JSON body
res.send(text)Send plain text body
res.status(code)Set HTTP status code — chainable
res.header(key, val)Add a response header — chainable
res.cookie(name, val)Set a cookie header — chainable
res.redirect(url)302 redirect
res.sendfile(path)Send file contents
res.download(path)Trigger browser download
// Chaining status + json
res.status(404).json({"error": "not found"})

// Chaining header + json
res.header("X-Request-Id", "abc123").json({"ok": true})

Middleware

Register middleware with addMw. Each middleware receives req, res, and next. Call next() to pass control to the next middleware or route handler. Not calling it stops the chain.

// Logging middleware
app.addMw(fn(req, res, next) {
    out req["method"] + " " + req["path"]
    next()
})

// Auth middleware
app.addMw(fn(req, res, next) {
    let token = req["authorization"]
    if (token == "") {
        res.status(401).json({"error": "unauthorized"})
    } else {
        next()
    }
})

Security

Built-in rate limiting and CORS helpers:

// Rate limiting — max 100 requests per minute per IP
app.addMw(fn(req, res, next) {
    if (app.rateLimit(req["ip"], 100, 60)) {
        next()
    } else {
        res.status(429).json({"error": "too many requests"})
    }
})

// CORS middleware factory
app.addMw(corsMiddleware(
    "https://my-domain.com",
    "GET, POST, PUT, DELETE",
    "Content-Type, Authorization"
))

Error handler

app.error(fn(err, req, res) {
    out "error: " + err
    res.status(500).json({"error": "internal server error"})
})

WebSocket

WebSocket support is included in the API and will activate once the Serez Code core adds Crypto.sha1base64 and Socket.recvWsFrame / Socket.sendWsFrame. The API is already defined:

app.ws("/ws", fn(req, ws) {
    ws.on("message", fn(msg) {
        ws.send("echo: " + msg)
    })
    ws.on("close", fn() {
        out "client disconnected"
    })
    ws.listen()
})

Notes

serez-http is single-threaded — one connection is handled at a time. The server listens on 127.0.0.1; use serez-apipack to deploy to Docker with external access.