moonbitstack/moonzero/rest does not have a README file

    Group

    pub struct Group {
    app :
    App

    prefix : String
    options : RouteOptions
    }

    A route group: registers a set of routes on an underlying moonapi.App under a shared path prefix and a shared set of route options, so related endpoints (everything under /api/v1, say) are declared without repeating either.

    Group::delete

    fn Group::delete(self : Group, path : String, handler : async (
    Context
    ) ->
    Response
    , summary? : String) -> Unit

    Register a DELETE route under the group's prefix.

    Group::get

    fn Group::get(self : Group, path : String, handler : async (
    Context
    ) ->
    Response
    , summary? : String) -> Unit

    Register a GET route under the group's prefix.

    Group::new

    fn Group::new(app :
    App
    , prefix : String) -> Group

    Open a group that prefixes every route it registers with prefix on app.

    Group::options

    fn Group::options(self : Group) -> RouteOptions

    The options every route in this group inherits.

    Group::options_

    fn Group::options_(self : Group, options : RouteOptions) -> Group

    A group that keeps this one's prefix and app with options in place of the inherited set. The prefixes still join, so Group::new(app, "/api").options_(RouteOptions::new().under("/v1")) serves /api/v1/....

    Group::patch

    fn Group::patch(self : Group, path : String, handler : async (
    Context
    ) ->
    Response
    , summary? : String) -> Unit

    Register a PATCH route under the group's prefix.

    Group::post

    fn Group::post(self : Group, path : String, handler : async (
    Context
    ) ->
    Response
    , summary? : String) -> Unit

    Register a POST route under the group's prefix.

    Group::prefix

    fn Group::prefix(self : Group) -> String

    The prefix this group joins onto each registered route.

    Group::put

    fn Group::put(self : Group, path : String, handler : async (
    Context
    ) ->
    Response
    , summary? : String) -> Unit

    Register a PUT route under the group's prefix.

    Group::route

    fn Group::route(self : Group, verb :
    Method
    , path : String, handler : async (
    Context
    ) ->
    Response
    , summary? : String) -> Unit

    Register a route for an explicit method under the group's prefix and options.

    Group::sse

    fn Group::sse(self : Group, path : String, handler : async (
    Context
    ) ->
    Response
    , summary? : String) -> Unit

    Register a server-sent-events route: a GET that answers with text/event-stream and is not cached.

    Group::sub

    fn Group::sub(self : Group, prefix : String) -> Group

    A sub-group under prefix, inheriting every option.

    JwtRoute

    pub(all) struct JwtRoute {
    enabled : Bool
    secret : String
    prev_secret : String?
    }

    JWT settings attached to a route: the current secret and, during a rotation, the previous one.

    Layer

    pub(all) struct Layer {
    name : String
    middleware : (async (
    Scope
    , async () ->
    Event
    , async (
    Event
    ) -> Unit) -> Unit) -> (async (
    Scope
    , async () ->
    Event
    , async (
    Event
    ) -> Unit) -> Unit)
    }

    One layer of the assembled chain: go-zero's name for the handler, and the middleware that stands in for it.

    RestEngine

    The engine that turns a RestConf into a runnable service. It owns the state the built-in layers need — the connection permits, the breaker window, the metric set, the two shedders — so every request shares one of each, and it installs exactly the layers Middlewares asks for.

    RestEngine::build

    Assemble app under the configured chain. The outermost layer is named first while Server::use_ makes the most recent layer outermost, so the list goes on back to front.

    RestEngine::conf

    The config the engine was built from.

    RestEngine::layers

    fn RestEngine::layers(self : RestEngine) -> Array[Layer]

    The chain the flags ask for, outermost first, in the order the reference implementation builds it: trace, log, prometheus, max conns, breaker, shedding, timeout, recover, max bytes, gunzip — with the content-security layer ahead of all of them when a verifier is configured, because it must see the body before anything else reads it.

    A layer whose configured value disables it is left out even when its flag is on: no shedder without a CpuThreshold, no timeout without a budget, no body cap without a MaxBytes.

    go-zero's Metrics flag is its internal stat.Metrics sink, which records the same numbers the Prometheus families do here; it loads and installs nothing.

    RestEngine::metrics

    The metric set the prometheus layer records into — the same one mount_metrics publishes.

    RestEngine::names

    fn RestEngine::names(self : RestEngine) -> Array[String]

    The names of the layers layers would install, outermost first.

    RestEngine::new

    Build the engine for conf, pointing the logger at the configured level.

    usage is the CPU meter the shedder reads, per mille; tracer decides where spans go (the default keeps them in an in-process recorder the engine owns); signature is the verifier the content-security layer checks against.

    Raises Refused for a strict signature config with no keys, and for a metric registry that will not register its families.

    RestEngine::priority_shedder

    The shedder a route opts into with RouteOptions::priority: it sheds at half the distance to saturation, so a busy service sacrifices ordinary traffic before these calls.

    RestEngine::shedder

    The shedder ordinary routes draw on.

    RestEngine::spans

    The spans the engine's default tracer has finished, oldest first. A read-out for tests and for a service that ships spans somewhere of its own.

    RestEngine::tracer

    The tracer the trace layer runs on.

    RouteOptions

    pub(all) struct RouteOptions {
    prefix : String
    jwt : JwtRoute
    signature :
    SignatureVerifier
    ?
    timeout_ms : Int64
    max_bytes : Int
    priority_shedder :
    Shedder
    ?
    sse : Bool
    clock :
    Clock

    }

    The per-route settings. Every one of them defaults to "inherit": no timeout, no body cap, no JWT, no signature, ordinary priority, no SSE.

    RouteOptions::jwt

    fn RouteOptions::jwt(self : RouteOptions, secret~ : String, prev_secret? : String) -> RouteOptions

    Require a valid Authorization: Bearer <jwt> on this route. prev_secret is the secret a rotation is retiring: a token signed with it is still accepted until the rotation window closes, which is what lets clients refresh without a coordinated deploy.

    RouteOptions::max_bytes

    fn RouteOptions::max_bytes(self : RouteOptions, bytes : Int) -> RouteOptions

    Give this route its own Content-Length cap in bytes.

    RouteOptions::new

    Options that change nothing: no prefix, no auth, no deadline, no cap.

    RouteOptions::priority

    Draw this route from the priority shedder, so a CPU spike sheds ordinary traffic before it touches these calls.

    RouteOptions::signature

    Require a verified X-Content-Security signature on this route.

    RouteOptions::sse

    Mark this route as a server-sent-event stream: the response carries the SSE media type, no caching, and a keep-alive connection.

    RouteOptions::timeout

    fn RouteOptions::timeout(self : RouteOptions, ms : Int64) -> RouteOptions

    Give this route its own deadline in milliseconds.

    RouteOptions::under

    fn RouteOptions::under(self : RouteOptions, prefix : String) -> RouteOptions

    Join group onto this option set's prefix, so a sub-group inherits the parent prefix as well as its own.

    Server

    A moonzero service: its config plus the assembled application (a moonapi App with any middleware already wrapped around it).

    Server::describe

    fn Server::describe(self : Server) -> String

    A human-readable description of what this service binds to.

    Server::files

    fn Server::files(self : Server, prefix : String, files :
    Files
    ) -> Server

    Serve files under prefix. The mount is a layer, so file responses still pass through CORS, tracing and access logging.

    Server::mounted

    fn Server::mounted(self : Server) -> Array[String]

    The prefixes this service serves files from.

    Server::new

    Assemble a service from config and a moonapi application.

    Server::to_asgi

    The assembled AsgiApp, ready for a server (mooncat) to run.

    Server::use_

    Wrap the current application in another middleware layer (outermost last).

    hoops_of

    The hoops options asks for, outermost first: signature, JWT, body cap, deadline, priority shedding, then the SSE stamp. Checks that refuse come before the ones that only measure, so a refused request costs nothing.

    join_path

    fn join_path(prefix : String, path : String) -> String

    Join a prefix with a path into a single, normalised path: at most one slash between the two, a guaranteed leading slash, and "/" for the empty result.

    join_prefix

    fn join_prefix(prefix : String, path : String) -> String

    join_path for a prefix that may be absent: two empty prefixes stay empty rather than collapsing to the root path, so a group with no prefix of its own adds nothing to a route.

    jwt_accepts

    fn jwt_accepts(setting : JwtRoute, token : String?, now_secs : Int64) -> Bool

    Whether token verifies against the route's current secret, or against the one a rotation is retiring, at now_secs.

    max_bytes_hoop

    The max-bytes hoop: refuse a body whose declared length exceeds limit.

    no_jwt

    let no_jwt : JwtRoute

    JWT settings that authenticate nothing.

    not_allowed

    Replace the reply a request with a known path but an unsupported method gets (← WithNotAllowedHandler), normally 405 Method Not Allowed.

    not_found

    Replace the reply an unmatched request gets (← WithNotFoundHandler). The handler runs inside the application, so the chain around it — tracing, access logging, CORS — has already run.

    priority_hoop

    The priority hoop: draw this route from shedder. A refused call answers 503, the status go-zero's shedding interceptor uses.

    signature_hoop

    The signature hoop: verify the X-Content-Security MAC and timestamp on this route. A payload the envelope declares encrypted is not decrypted here — a hoop cannot rewrite the request — so a route that takes encrypted bodies wants the service-level content_security layer, which can.

    sse_hoop

    The SSE hoop: stamp the event-stream media type, no caching and a kept-alive connection onto a buffered response. A streamed reply declares its own headers and is left alone.

    timeout_hoop

    The timeout hoop: run the rest of the chain under a budget, and answer 503 when it runs out. The deadline is enforced here rather than on the response path, so a handler that never returns is abandoned instead of hanging the request forever.