Sign in

    moonbitstack/moonapi/route does not have a README file

    ApiHandler

    A route handler (← a FastAPI path operation): the request context in, a response out. It runs async, so it can await a database or another service; a plain closure is one too, and a named function that is not async is registered as ctx => f(ctx). It may raise an HttpException (or any error) instead of returning — the app maps it to a response through the registered exception handlers.

    Hoop

    A middleware on a route or on a router node (← Salvo's hoops, Starlette's route middleware): the request context and the rest of the route in, the reply out. It runs inside the app's own middleware and outside the route's security, validation and dependencies, so it can answer for the route — refuse, redirect, serve from a cache — or change what the route produced, and it can hand next a context of its own.

    Method

    The request method a route binds to: the nine standard ones and any other token, from moonhttp.

    StreamHandler

    A streaming route's handler (← a FastAPI path operation returning a StreamingResponse): the response it returns writes its body while it is sent.

    Url

    type Url = (Router) -> Unit

    One entry of a route table: what it registers, given the router it lands on. path, view, websocket and group make them.

    View

    A type answering the methods of one path (← Django's class-based View). Implement the methods it answers, each giving back its handler; the rest answer None, and a request for one of those gets a 405 whose Allow lists what the view does answer.

    struct Articles { db : Db }

    impl @moonapi.View for Articles with get(self) {
    Some(ctx => self.db.list(ctx))
    }

    impl @moonapi.View for Articles with post(self) {
    Some(ctx => self.db.create(ctx))
    }

    app.view("/articles", Articles::{ db })

    Convertor

    pub(all) enum Convertor {
    Str
    Int
    Float
    Uuid
    Path
    } derive(Eq,
    Debug
    )

    What a path parameter accepts (← Starlette's convertors). Str is one segment or part of one; Path is the rest of the path, slashes included.

    Convertor::equal

    fn Convertor::equal(Convertor, Convertor) -> Bool

    Convertor::not_equal

    fn Convertor::not_equal(x : Convertor, y : Convertor) -> Bool

    Convertor::of

    fn Convertor::of(name : StringView) -> Convertor?

    The convertor named name, as a template spells it after the colon.

    Pattern

    pub(all) struct Pattern {
    source : String
    pieces : Array[Piece]
    } derive(Eq,
    Debug
    )

    A route path read as a template: /users/{id:int}, /files/{name}.json, /static/{rest:path}. A parameter without a convertor is str.

    Pattern::bind

    fn Pattern::bind(self : Pattern, path : StringView) -> Map[String, String]?

    The parameters path binds, or None when it does not match. The whole path must match: a trailing slash is a different path.

    Pattern::equal

    fn Pattern::equal(Pattern, Pattern) -> Bool

    Pattern::fill

    fn Pattern::fill(self : Pattern, params : Map[String, String]) -> String?

    The path with params substituted (← Starlette's url_path_for); None when one is missing or does not fit its convertor.

    Pattern::not_equal

    fn Pattern::not_equal(x : Pattern, y : Pattern) -> Bool

    Pattern::params

    fn Pattern::params(self : Pattern) -> Array[(String, Convertor)]

    The parameters in the order the path names them.

    Pattern::parse

    fn Pattern::parse(path : String) -> Pattern

    Read path as a template. An unclosed brace, an empty name, an unknown convertor or two parameters with nothing between them is a mistake in the program, not in a request, so it aborts at registration — the way Starlette refuses such a route when the application starts.

    Pattern::template

    fn Pattern::template(self : Pattern) -> String

    The path as an OpenAPI template expression: every parameter as {name}, the convertor left to the parameter's schema.

    Pattern::to_repr

    Piece

    pub(all) enum Piece {
    Literal(String)
    Param(name~ : String, convertor~ : Convertor)
    } derive(Eq,
    Debug
    )

    One piece of a path template: text matched as written, or a parameter.

    Piece::equal

    fn Piece::equal(Piece, Piece) -> Bool

    Piece::not_equal

    fn Piece::not_equal(x : Piece, y : Piece) -> Bool

    Piece::to_repr

    Reply

    What a route produced: a response with its body in hand, or one that writes its body as it goes.

    Route

    pub(all) struct Route {
    verb :
    Method

    path : String
    pattern : Pattern
    run : async (
    Context
    ) -> Reply
    summary : String
    description : String
    tags : Array[String]
    deprecated : Bool
    operation_id : String
    status_code : Int?
    responses : Array[
    ResponseSpec
    ]
    name : String
    openapi_extra : Json?
    endpoint :
    Endpoint
    ?
    security : Array[
    SecurityRequirement
    ]
    dependencies : Array[String]
    callbacks : Array[Route]
    hoops : Array[async (
    Context
    , async (
    Context
    ) -> Reply) -> Reply]
    include_in_schema : Bool
    validate : Bool
    }

    One registered route, the record an app keeps for each operation — what FastAPI calls APIRoute. Public so a program can list and inspect an app's routes; building one by hand is possible but the App methods are the way.

    security is the per-operation requirements (emitted as OpenAPI security and enforced before the handler when their scheme has an enforcer).

    Router

    pub struct Router {
    routes : Array[Route]
    ws_routes : Array[WsRoute]
    hoops : Array[async (
    Context
    , async (
    Context
    ) -> Reply) -> Reply]
    }

    A collection of routes built away from any application and folded into one with App::include_router (← FastAPI's APIRouter). It carries the registration surface of an App and nothing else: middleware, mounts, security schemes, documentation and lifespan belong to the application that includes it.

    Router::delete

    fn Router::delete(self : Router, path : String, handler : async (
    Context
    ) ->
    Response
    , summary? : String, description? : String, tags? : Array[String], deprecated? : Bool, operation_id? : String, status_code? : Int, responses? : Array[
    ResponseSpec
    ], name? : String, endpoint? :
    Endpoint
    , security? : Array[
    SecurityRequirement
    ], dependencies? : Array[String], include_in_schema? : Bool, validate? : Bool, openapi_extra? : Json, callbacks? : Array[Route], hoops? : Array[async (
    Context
    , async (
    Context
    ) -> Reply) -> Reply]) -> Unit

    Register a DELETE route. A shorthand for route(Delete, ...).

    Router::get

    fn Router::get(self : Router, path : String, handler : async (
    Context
    ) ->
    Response
    , summary? : String, description? : String, tags? : Array[String], deprecated? : Bool, operation_id? : String, status_code? : Int, responses? : Array[
    ResponseSpec
    ], name? : String, endpoint? :
    Endpoint
    , security? : Array[
    SecurityRequirement
    ], dependencies? : Array[String], include_in_schema? : Bool, validate? : Bool, openapi_extra? : Json, callbacks? : Array[Route], hoops? : Array[async (
    Context
    , async (
    Context
    ) -> Reply) -> Reply]) -> Unit

    Register a GET route. A shorthand for route(Get, ...).

    Router::head

    fn Router::head(self : Router, path : String, handler : async (
    Context
    ) ->
    Response
    , summary? : String, description? : String, tags? : Array[String], deprecated? : Bool, operation_id? : String, status_code? : Int, responses? : Array[
    ResponseSpec
    ], name? : String, endpoint? :
    Endpoint
    , security? : Array[
    SecurityRequirement
    ], dependencies? : Array[String], include_in_schema? : Bool, validate? : Bool, openapi_extra? : Json, callbacks? : Array[Route], hoops? : Array[async (
    Context
    , async (
    Context
    ) -> Reply) -> Reply]) -> Unit

    Register a HEAD route. A shorthand for route(Head, ...).

    Router::hoop

    Put hoop around every route of this router (← Salvo's Router::hoop). The router's hoops reach its routes when it is included, outside each route's own, in the order they were added.

    Router::include_router

    fn Router::include_router(self : Router, router : Router, prefix? : String, tags? : Array[String], security? : Array[
    SecurityRequirement
    ], dependencies? : Array[String], responses? : Array[
    ResponseSpec
    ], deprecated? : Bool, include_in_schema? : Bool, hoops? : Array[async (
    Context
    , async (
    Context
    ) -> Reply) -> Reply]) -> Unit

    Fold router's routes into this one under prefix (← FastAPI's APIRouter.include_router), so routers nest into a tree and the tree is included into an app once. The arguments reach every route folded in:

    • tags, security, dependencies and hoops are placed before the route's own, so a group's tag leads and a group-wide requirement, dependency or hoop cannot be dropped by a route that adds one of its own; router's own hoops come between the two;
    • responses are documented under the route's, which therefore wins any status both name;
    • deprecated marks the whole group, and include_in_schema=false hides it, neither of which a route can undo.

    WebSocket routes take the prefix, the security and the dependencies.

    Router::new

    fn Router::new() -> Router

    An empty router. The prefix and the attributes its routes share are given at include_router rather than here, so one router can be included twice — under a second prefix, or on another app with different tags.

    Router::options

    fn Router::options(self : Router, path : String, handler : async (
    Context
    ) ->
    Response
    , summary? : String, description? : String, tags? : Array[String], deprecated? : Bool, operation_id? : String, status_code? : Int, responses? : Array[
    ResponseSpec
    ], name? : String, endpoint? :
    Endpoint
    , security? : Array[
    SecurityRequirement
    ], dependencies? : Array[String], include_in_schema? : Bool, validate? : Bool, openapi_extra? : Json, callbacks? : Array[Route], hoops? : Array[async (
    Context
    , async (
    Context
    ) -> Reply) -> Reply]) -> Unit

    Register a OPTIONS route. A shorthand for route(Options, ...).

    Router::patch

    fn Router::patch(self : Router, path : String, handler : async (
    Context
    ) ->
    Response
    , summary? : String, description? : String, tags? : Array[String], deprecated? : Bool, operation_id? : String, status_code? : Int, responses? : Array[
    ResponseSpec
    ], name? : String, endpoint? :
    Endpoint
    , security? : Array[
    SecurityRequirement
    ], dependencies? : Array[String], include_in_schema? : Bool, validate? : Bool, openapi_extra? : Json, callbacks? : Array[Route], hoops? : Array[async (
    Context
    , async (
    Context
    ) -> Reply) -> Reply]) -> Unit

    Register a PATCH route. A shorthand for route(Patch, ...).

    Router::post

    fn Router::post(self : Router, path : String, handler : async (
    Context
    ) ->
    Response
    , summary? : String, description? : String, tags? : Array[String], deprecated? : Bool, operation_id? : String, status_code? : Int, responses? : Array[
    ResponseSpec
    ], name? : String, endpoint? :
    Endpoint
    , security? : Array[
    SecurityRequirement
    ], dependencies? : Array[String], include_in_schema? : Bool, validate? : Bool, openapi_extra? : Json, callbacks? : Array[Route], hoops? : Array[async (
    Context
    , async (
    Context
    ) -> Reply) -> Reply]) -> Unit

    Register a POST route. A shorthand for route(Post, ...).

    Router::put

    fn Router::put(self : Router, path : String, handler : async (
    Context
    ) ->
    Response
    , summary? : String, description? : String, tags? : Array[String], deprecated? : Bool, operation_id? : String, status_code? : Int, responses? : Array[
    ResponseSpec
    ], name? : String, endpoint? :
    Endpoint
    , security? : Array[
    SecurityRequirement
    ], dependencies? : Array[String], include_in_schema? : Bool, validate? : Bool, openapi_extra? : Json, callbacks? : Array[Route], hoops? : Array[async (
    Context
    , async (
    Context
    ) -> Reply) -> Reply]) -> Unit

    Register a PUT route. A shorthand for route(Put, ...).

    Router::route

    fn Router::route(self : Router, verb :
    Method
    , path : String, handler : async (
    Context
    ) ->
    Response
    , summary? : String, description? : String, tags? : Array[String], deprecated? : Bool, operation_id? : String, status_code? : Int, responses? : Array[
    ResponseSpec
    ], name? : String, endpoint? :
    Endpoint
    , security? : Array[
    SecurityRequirement
    ], dependencies? : Array[String], include_in_schema? : Bool, validate? : Bool, openapi_extra? : Json, callbacks? : Array[Route], hoops? : Array[async (
    Context
    , async (
    Context
    ) -> Reply) -> Reply]) -> Unit

    Register a route on the router for an explicit method. An optional endpoint descriptor makes the route fully typed (its parameters, request body, and responses surface in the OpenAPI document and drive validation); security attaches per-operation requirements (emitted as OpenAPI security and enforced before the handler when their scheme has an enforcer); dependencies names provider keys resolved through the app's container (App::depends) before the handler and torn down after it, whatever the handler did.

    The rest describe the operation: summary and description are its prose, operation_id the stable handle client generators name their method after, status_code the status its success response is documented under, responses further documented responses, name the handle App::url_for resolves, openapi_extra a fragment merged over the generated operation object, and callbacks the requests this operation makes back to its caller, written as routes whose paths are runtime expressions — the same keyword arguments FastAPI's path operations take. hoops wrap this one route, inside any its routers put around it.

    Router::route_stream

    fn Router::route_stream(self : Router, verb :
    Method
    , path : String, handler : async (
    Context
    ) ->
    Stream
    , summary? : String, description? : String, tags? : Array[String], deprecated? : Bool, operation_id? : String, status_code? : Int, responses? : Array[
    ResponseSpec
    ], name? : String, endpoint? :
    Endpoint
    , security? : Array[
    SecurityRequirement
    ], dependencies? : Array[String], include_in_schema? : Bool, validate? : Bool, openapi_extra? : Json, callbacks? : Array[Route], hoops? : Array[async (
    Context
    , async (
    Context
    ) -> Reply) -> Reply]) -> Unit

    Register a streaming route (← a FastAPI path operation returning a StreamingResponse). The handler's chunks reach the client as separate body events, so a long or open-ended reply starts arriving before it is finished.

    A stream is only streamed as far as the app can honestly keep it one: a middleware that rewrites the body — gzip does — collapses the reply to a single chunk. Everything else about the route is ordinary; it documents, validates and enforces security exactly as route does.

    Router::stream

    fn Router::stream(self : Router, path : String, handler : async (
    Context
    ) ->
    Stream
    , summary? : String, description? : String, tags? : Array[String], deprecated? : Bool, operation_id? : String, status_code? : Int, responses? : Array[
    ResponseSpec
    ], name? : String, endpoint? :
    Endpoint
    , security? : Array[
    SecurityRequirement
    ], dependencies? : Array[String], include_in_schema? : Bool, validate? : Bool, openapi_extra? : Json, callbacks? : Array[Route], hoops? : Array[async (
    Context
    , async (
    Context
    ) -> Reply) -> Reply]) -> Unit

    Register a streaming GET route — the verb a stream is nearly always read over, and what an SSE endpoint is. A shorthand for route_stream(Get, ...).

    Router::trace

    fn Router::trace(self : Router, path : String, handler : async (
    Context
    ) ->
    Response
    , summary? : String, description? : String, tags? : Array[String], deprecated? : Bool, operation_id? : String, status_code? : Int, responses? : Array[
    ResponseSpec
    ], name? : String, endpoint? :
    Endpoint
    , security? : Array[
    SecurityRequirement
    ], dependencies? : Array[String], include_in_schema? : Bool, validate? : Bool, openapi_extra? : Json, callbacks? : Array[Route], hoops? : Array[async (
    Context
    , async (
    Context
    ) -> Reply) -> Reply]) -> Unit

    Register a TRACE route. A shorthand for route(Trace, ...).

    Router::urls

    fn Router::urls(self : Router, urls : Array[(Router) -> Unit]) -> Unit

    Register every entry of urls, in order — the order a request tries them in.

    Router::view

    fn Router::view(self : Router, path : String, view : &View, name? : String, tags? : Array[String], security? : Array[
    SecurityRequirement
    ], dependencies? : Array[String], deprecated? : Bool, include_in_schema? : Bool, hoops? : Array[async (
    Context
    , async (
    Context
    ) -> Reply) -> Reply]) -> Unit

    Register the methods view answers at path, each as its own route sharing the arguments given here. A view that answers no method is a mistake in the program and aborts.

    Router::websocket

    fn Router::websocket(self : Router, path : String, handler : async (
    WebSocket
    ) -> Unit, name? : String, security? : Array[
    SecurityRequirement
    ], dependencies? : Array[String]) -> Unit

    Register a WebSocket route on the router (← APIRouter.websocket). It takes the including prefix like any other route. security and dependencies are checked before the handler runs, as on an HTTP route, and a refusal declines the handshake; name is the handle App::url_for resolves. The OpenAPI attributes do not apply, since a WebSocket route is not an operation.

    WsRoute

    pub(all) struct WsRoute {
    path : String
    pattern : Pattern
    handler : async (
    WebSocket
    ) -> Unit
    name : String
    security : Array[
    SecurityRequirement
    ]
    dependencies : Array[String]
    }

    One registered WebSocket route (← Starlette's WebSocketRoute). security and dependencies are settled before the handler is called, so a connection they turn away is declined at the handshake rather than accepted and dropped.

    group

    fn group(prefix : String, urls : Array[(Router) -> Unit], tags? : Array[String], security? : Array[
    SecurityRequirement
    ], dependencies? : Array[String], hoops? : Array[async (
    Context
    , async (
    Context
    ) -> Reply) -> Reply]) -> ((Router) -> Unit)

    urls under prefix (← Django's include, Starlette's Mount with routes; include is a reserved word). The arguments reach every route of the group as Router::include_router describes, and a group may hold groups.

    join_prefix

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

    A route path under prefix, written as FastAPI writes it: the prefix with its trailing slashes dropped, then the path as given, so ("/sub", "/items/") is /sub/items/ and ("/sub", "/") is /sub/. A path keeps its own trailing slash because a trailing slash is part of what a route matches.

    path

    fn path(path : String, handler : async (
    Context
    ) ->
    Response
    , methods? : Array[
    Method
    ], name? : String) -> ((Router) -> Unit)

    handler at path for each of methods (← Django's path, Starlette's Route, whose default is the same GET, which answers HEAD too).

    segments

    fn segments(path : String) -> Array[String]

    Split a path into its non-empty segments.

    view

    fn view(path : String, view : &View, name? : String) -> ((Router) -> Unit)

    The methods view answers at path.

    websocket

    fn websocket(path : String, handler : async (
    WebSocket
    ) -> Unit, name? : String) -> ((Router) -> Unit)

    A WebSocket route at path (← Starlette's WebSocketRoute).