[][src]Crate wayfinder

A little HTTP route matcher generator.

Other route matchers are configured at runtime, which means they pay a hefty price of dynamic algorithms for something that is nearly always static. Wayfinder does things a little differently: configure routes at build-time.

You can specify the route structure in one of two ways. The most readable format is a route config file, which might look like:

This example is not tested
use uuid::Uuid;

/
  GET Index

  users
    GET Users::List
    POST Users::Create

    {id: uuid}
      GET Users::Show

Then add a build script to generate the route matching code:

This example is not tested
Builder::from_env()
    .input_file("app.routes")
    .output_file("routes.rs")
    .build();

And import the generated route module into your app.

This example is not tested
include!(concat!(env!("OUT_DIR"), "/routes.rs"));

When a request comes in, match it against the route table:

This example is not tested
use routes::{Match, Route};
match routes::match_route(path, method) {
    Ok(Match::Route(Route::Index(action))) => index_controller(action),
    Ok(Match::Route(Route::Users(action))) => users_controller(action),
    _ => error_handler(),
}

See the documentation for the generated module for more information, or the examples for a complete application.

You can also build up your route config using the structs and macros provided here. The equivalent code for the above routes might be:

let config = RouteConfig {
    headers: vec![header!(
        use uuid::Uuid;
    )],
    routes: Routes {
        resources: vec![
            get!(Index)
        ],
        routes: vec![NestedRoutes::new(
            "users",
            Routes {
                resources: vec![
                    get!(Users::List),
                    post!(Users::Create),
                ],
                routes: vec![NestedRoutes::new(
                    param!(id: Uuid),
                    Routes {
                        resources: vec![
                            get!(Users::Show)
                        ],
                        ..Routes::default()
                    }
                )],
                ..Routes::default()
            }
        )],
        ..Routes::default()
    },
};

Sure, it's a little more verbose, but you get the benefit of Rust's superb error handling, and it's much less magic. Update your build script to use the route config:

This example is not tested
Builder::from_env()
    .input_config(config)
    .output_file("routes.rs")
    .build();

Modules

build

Build helpers for using Wayfinder route matchers.

gen

Codegen utilities for producing route matchers.

parse

Parsing utilities for route config files.

Macros

delete

Create a Resource for an HTTP DELETE request.

get

Create a Resource for an HTTP GET request.

header

Create a Header, for instance to use a data type.

param

Create a Param to use as a path segment or query parameter.

post

Create a Resource for an HTTP POST request.

put

Create a Resource for an HTTP PUT request.

Structs

Header

A bit of inline code above the route table. Usually for use items.

NestedRoutes

A block of routes nested under a path segment.

Param

Path and query parameters have a name and type.

Resource

A resource available at a specific path.

RouteConfig

An entire routing file.

Routes

A listing of resources & routes.

Enums

Method

HTTP methods that resources can respond to.

PathSegment

A path segment is either a static string or a dynamic parameter.