Giter VIP home page Giter VIP logo

poem-route-macro's Introduction

poem-route-macro

Provides a simple macro to ease the definition of routes in Poem.

Example

Here is an example use of the macro to construct a Poem Route that has a number of end-points and a nested static files endpoint.

use poem::{endpoint::StaticFilesEndpoint, EndpointExt, IntoEndpoint, Route};

fn build_routes(my_data: MyData) -> impl IntoEndpoint {
    define_routes!(Route::new(), {
        // Nest a static files endpoint
        *"/static"      { StaticFilesEndpoint::new("./static") }

        // Standard routes
        "/"             index               GET
        "/pastes"       paste::pastes       GET
        "/pastes/:id"   paste::paste        GET POST

        // A nested route for administration
        *"/admin"       { admin::build_routes() }
    })
    .data(my_data)
}

// Handlers names are constructed by prefixing the method (followed by an underscore):

// This handler is used in the GET "/" route, so we prefix 'get_' to it's name
pub fn get_index() { ... }

mod paste {
    // Corresponds to: paste::pastes GET
    pub fn get_pastes() { ... }

    // Correspond to: paste::paste GET POST
    pub fn get_paste(_: Path<PasteId>) { ... }
    pub fn post_paste(_: Path<PasteId>) { ... }
}

The above will generate the following code:

fn build_routes() -> Route {
    Route::new()
        .nest("/static", StaticFilesEndpoint::new("./static"))
        .at("/", poem::get(index::get_index))
        .at("/pastes", poem::get(paste::get_pastes))
        .at("/pastes/:id", poem::get(paste::get_paste).post(post_paste))
        .nest("/admin", admin::build_routes())
}

How to use

The optional first argument to the define_routes macro is the expression to which all the routes are applied in a builder pattern. If this expression is missing, it defaults to Route::new(). As such, these two are equivalent:

fn build_routes_no_expr() -> Route {
    define_routes!({
        "/" index GET
    })
}

fn build_routes_with_expr() -> Route {
    define_routes!(Route::new(), {
        "/" index GET
    })
}

This can be useful, as you might want to have something before the endpoints are added builder-style to the router.

After the optional expression, the routes are specified, wrapped in braces.

define_routes!({
    // routes go here
})

There are two routes supported: nested and normal.

Nested Endpoints

A nested route is indicated by an asterisk, followed by the path on which to nest the endpoint.

define_routes!({
    // A nested route under "/static", e.g. "/static/foo"
    *"/static" { my_nested_router }
})

After the path string there should be an expression block, being some Rust statements in braces. This code should evaluate to something that implements IntoEndpoint.

This can be useful to nest multiple routers together:

fn admin_routes() -> Route {
    define_route!({
        "/"         admin::index    GET
        "/users"    admin::users    GET POST
    })
}

fn post_routes() -> Route {
    define_route!({
        "/"         posts::posts    GET
        "/:id"      posts::post     GET POST
    })
}

fn build_routes() -> Route {
    define_route!({
        *"/admin"   { admin_routes() }
        *"/posts"   { post_routes() }
    })
}

Normal Endpoints

Normal endpoints are specified by the path string, then the handler name template, followed by a list of methods. The handler name template is a Rust path, such as handler or module::handler. This path is more like that found in a use statement, in that it cannot include generic parameters in any of its segments.

The handler name template is modified for each method by prefixing the method, lower-case, to the last element in the handler name template, separated by an underscore. For example, if the handler name template was s3::bucket and the methods where GET and POST, the handler names generated will be s3::get_bucket and s3::post_bucket

Consider the following set of handlers:

// Let's define a handler in our current module that we'll use for the "/" route.
#[handler]
fn get_index() -> poem::Result<()> { todo!() }

// Define a couple more handlers for signing in under "/user/signin"
#[handler]
fn get_user_signin() -> poem::Result<()> { todo!() }
#[handler]
fn post_user_signin() -> poem::Result<()> { todo!() }

// Now let's define a couple of handlers for S3 buckets in their own module.
mod s3 {
    #[handler]
    pub fn get_bucket() -> poem::Result<()> { todo!() }

    #[handler]
    pub fn post_bucket() -> poem::Result<()> { todo!() }
}

We can then wire-up these handlers with the define_route as follows:

fn build_routes() -> Route {
    define_route!({
        // Handler template 'index' becomes 'get_index'
        "/"             index           GET

        // Handler template 'user_signin' becomes 'get_user_signin' and 'post_user_signin'
        "/user/signin"  user_signin     GET POST

        // Wire up the S3 bucket handlers the same way.
        "/s3/:bucket"   s3::bucket      GET POST
    })
}

Grammar

The grammar for this simple routing table DSL is given in the following rough eBNF:

body = { EXPR "," } "{" routes "}" ;

routes = route { route } ;

route = "*" LIT_STR EXPR_BLOCK
      |     LIT_STR path methods
      ;

path = IDENT { "::" IDENT } ;

methods = method { method } ;

method = "GET" | "POST" | "DELETE" | "PUT" ;

poem-route-macro's People

Contributors

blakerain avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.