Sign in

    mocket

    A web framework for MoonBit.

    http
    server
    Download zip
    Author
    Version
    0.5.0
    License
    Apache-2.0
    Last updated
    last year
    Downloads
    2K

    #oboard/mocket

    Version GitHub Workflow Status (with event) License

    A web framework for MoonBit.

    logo

    #Quick Start

    Mocket supports both js and native backends.

    #JavaScript Backend

    Set the backend of MoonBit to js in Visual Studio Code

    Command: MoonBit: Select Backend -> js

    moon run src/example --target js

    #Native Backend

    Set the backend of MoonBit to native in Visual Studio Code

    Command: MoonBit: Select Backend -> native

    moon run src/example --target native

    Then visit http://localhost:4000

    #Usage

    Minimum Example: https://github.com/oboard/mocket_example

    #Features

    #Dynamic Routes

    Support named parameters with :param syntax:

    app.get("/hello/:name", fn(event) {
    let name = event.params.get("name").or("World")
    Text("Hello, \{name}!")
    })

    #Wildcard Routes

    Support single and double wildcards:

    // Single wildcard - matches one path segment
    app.get("/hello/*", fn(event) {
    let name = event.params.get("_").or("World")
    Text("Hello, \{name}!")
    })

    // Double wildcard - matches multiple path segments
    app.get("/hello/**", fn(event) {
    let path = event.params.get("_").or("")
    Text("Hello, \{path}!")
    })

    #Async Support

    The library supports async/await for I/O operations:

    #Async /GET Example

    // async json data example
    app.get("/async_data", async fn(event) {
    Json({ "name": "John Doe", "age": 30, "city": "New York" })
    })

    #Route Groups

    Group related routes under a common base path with shared middleware:

    app.group("/api", group => {
    // Add group-level middleware
    group.use_middleware(event => println(
    "🔒 API Group Middleware: \{event.req.reqMethod} \{event.req.url}",
    ))

    // Routes under /api prefix
    group.get("/hello", _ => Text("Hello from API!"))
    group.get("/users", _ => Json({ "users": ["Alice", "Bob"] }))
    group.post("/data", e => e.req.body)
    })

    This creates routes:
    • GET /api/hello
    • GET /api/users
    • POST /api/data

    All routes in the group will execute the group middleware in addition to any global middleware.

    #Example usage

    let app = @mocket.new(logger=@mocket.new_debug_logger())

    // Register global middleware
    app
    ..use_middleware(event => println(
    "📝 Request: \{event.req.http_method} \{event.req.url}",
    ))

    // Text Response
    ..get("/", _event => Text("⚡️ Tadaa!"))

    // Hello World
    ..on("GET", "/hello", _ => Text("Hello world!"))
    ..group("/api", group => {
    // 添加组级中间件
    group.use_middleware(event => println(
    "🔒 API Group Middleware: \{event.req.http_method} \{event.req.url}",
    ))
    group.get("/hello", _ => Text("Hello world!"))
    group.get("/json", _ => Json({
    "name": "John Doe",
    "age": 30,
    "city": "New York",
    }))
    })

    // JSON Response
    ..get("/json", _event => Json({
    "name": "John Doe",
    "age": 30,
    "city": "New York",
    }))

    // Async Response
    ..get("/async_data", async fn(_event) noraise {
    Json({ "name": "John Doe", "age": 30, "city": "New York" })
    })

    // Dynamic Routes
    // /hello2/World = Hello, World!
    ..get("/hello/:name", fn(event) {
    let name = event.params.get("name").unwrap_or("World")
    Text("Hello, \{name}!")
    })
    // /hello2/World = Hello, World!
    ..get("/hello2/*", fn(event) {
    let name = event.params.get("_").unwrap_or("World")
    Text("Hello, \{name}!")
    })

    // Wildcard Routes
    // /hello3/World/World = Hello, World/World!
    ..get("/hello3/**", fn(event) {
    let name = event.params.get("_").unwrap_or("World")
    Text("Hello, \{name}!")
    })

    // Echo Server
    ..post("/echo", e => e.req.body)

    // 404 Page
    ..get("/404", e => {
    e.res.status_code = 404
    HTML(
    (
    #|<html>
    #|<body>
    #| <h1>404</h1>
    #|</body>
    #|</html>
    ),
    )
    })

    // Serve
    ..serve(port=4000)

    // Print Server URL
    for path in app.mappings.keys() {
    println("\{path.0} http://localhost:4000\{path.1}")
    }

    #Route Matching Examples

    Route PatternURLParameters
    /hello/:name/hello/worldname: "world"
    /hello/*/hello/world_: "world"
    /hello/**/hello/foo/bar_: "foo/bar"
    /users/:id/posts/:postId/users/123/posts/456id: "123", postId: "456"
    /api/**/api/v1/users/123_: "v1/users/123"
    group("/api", ...).get("/hello")/api/hello-
    group("/users", ...).get("/:id")/users/123id: "123"

    🙌快来吧!🙌

    QQ 群号:949886784

    QQ 群

    typealias Mocket as T

    ExecError

    pub suberror ExecError

    impl Show for ExecError

    IOError

    pub suberror IOError

    impl Show for IOError

    NetworkError

    pub suberror NetworkError

    HttpBody

    pub(all) enum HttpBody {
    Json(Json)
    Text(String)
    HTML(String)
    Bytes(Bytes)
    Empty
    }

    HttpEvent

    pub struct HttpEvent {
    req : HttpRequest
    res : HttpResponse
    params : Map[String, String]
    }

    HttpRequest

    pub struct HttpRequest {
    http_method : String
    url : String
    headers : Map[String, String]
    body : HttpBody
    }

    HttpResponse

    pub(all) struct HttpResponse {
    status_code : Int
    headers : Map[String, String]
    }

    LogLevel

    pub enum LogLevel {
    Debug
    Info
    Warn
    Error
    }

    Logger

    pub struct Logger {
    enabled : Bool
    level : LogLevel
    }

    Logger::debug

    fn Logger::debug(self : Logger, message_fn : () -> String) -> Unit

    Logger::debug_str

    fn Logger::debug_str(self : Logger, message : String) -> Unit

    Logger::error

    fn Logger::error(self : Logger, message_fn : () -> String) -> Unit

    Logger::info

    fn Logger::info(self : Logger, message_fn : () -> String) -> Unit

    Logger::route_added

    fn Logger::route_added(self : Logger, path : String) -> Unit

    Logger::route_created

    fn Logger::route_created(self : Logger, path : String) -> Unit

    Logger::route_dynamic

    fn Logger::route_dynamic(self : Logger, http_method : String, path : String) -> Unit

    Logger::route_found

    fn Logger::route_found(self : Logger, http_method : String, path : String) -> Unit

    Logger::route_lookup

    fn Logger::route_lookup(self : Logger, http_method : String, path : String) -> Unit

    Logger::route_merge_existing

    fn Logger::route_merge_existing(self : Logger, http_method : String) -> Unit

    Logger::route_merge_new

    fn Logger::route_merge_new(self : Logger, http_method : String) -> Unit

    Logger::route_not_found

    fn Logger::route_not_found(self : Logger, path : String) -> Unit

    Logger::route_register

    fn Logger::route_register(self : Logger, http_method : String, path : String) -> Unit

    Logger::route_static

    fn Logger::route_static(self : Logger, http_method : String, path : String) -> Unit

    Logger::routes_available

    fn Logger::routes_available(self : Logger, routes : Array[String]) -> Unit

    Logger::warn

    fn Logger::warn(self : Logger, message_fn : () -> String) -> Unit

    Mocket

    pub(all) struct Mocket {
    base_path : String
    mappings : Map[(String, String), async (HttpEvent) -> HttpBody noraise]
    middlewares : Array[(String, async (HttpEvent) -> Unit noraise)]
    static_routes : Map[String, Map[String, async (HttpEvent) -> HttpBody noraise]]
    dynamic_routes : Map[String, Array[(String, async (HttpEvent) -> HttpBody noraise)]]
    logger : Logger
    }

    Mocket::all

    fn Mocket::all(self : Mocket, path : String, handler : async (HttpEvent) -> HttpBody noraise) -> Unit

    Mocket::connect

    fn Mocket::connect(self : Mocket, path : String, handler : async (HttpEvent) -> HttpBody noraise) -> Unit

    Mocket::delete

    fn Mocket::delete(self : Mocket, path : String, handler : async (HttpEvent) -> HttpBody noraise) -> Unit

    Mocket::get

    fn Mocket::get(self : Mocket, path : String, handler : async (HttpEvent) -> HttpBody noraise) -> Unit

    Mocket::group

    fn Mocket::group(self : Mocket, base_path : String, configure : (Mocket) -> Unit) -> Unit

    Mocket::head

    fn Mocket::head(self : Mocket, path : String, handler : async (HttpEvent) -> HttpBody noraise) -> Unit

    Mocket::on

    fn Mocket::on(self : Mocket, event : String, path : String, handler : async (HttpEvent) -> HttpBody noraise) -> Unit

    Mocket::options

    fn Mocket::options(self : Mocket, path : String, handler : async (HttpEvent) -> HttpBody noraise) -> Unit

    Mocket::patch

    fn Mocket::patch(self : Mocket, path : String, handler : async (HttpEvent) -> HttpBody noraise) -> Unit

    Mocket::post

    fn Mocket::post(self : Mocket, path : String, handler : async (HttpEvent) -> HttpBody noraise) -> Unit

    Mocket::put

    fn Mocket::put(self : Mocket, path : String, handler : async (HttpEvent) -> HttpBody noraise) -> Unit

    Mocket::serve

    fn Mocket::serve(self : Mocket, port~ : Int) -> Unit

    Mocket::trace

    fn Mocket::trace(self : Mocket, path : String, handler : async (HttpEvent) -> HttpBody noraise) -> Unit

    Mocket::use_middleware

    fn Mocket::use_middleware(self : Mocket, middleware : async (HttpEvent) -> Unit noraise, base_path? : String) -> Unit

    new

    fn new(base_path? : String, logger? : Logger) -> Mocket

    new_debug_logger

    fn new_debug_logger() -> Logger

    new_logger

    fn new_logger(enabled? : Bool, level? : LogLevel) -> Logger

    new_production_logger

    fn new_production_logger() -> Logger

    run

    fn run(f : async () -> Unit noraise) -> Unit

    serve_ffi

    fn serve_ffi(mocket : Mocket, port~ : Int) -> Unit

    suspend

    async fn[T, E : Error] suspend(f : ((T) -> Unit, (E) -> Unit) -> Unit) -> T raise E

    suspend 会中断当前协程的运行。 suspend 会接受一个回调函数,并让这个回调函数来操作中断的协程