1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//! 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:
//!
//! ```ignore
//! 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:
//!
//! ```ignore
//! Builder::from_env()
//! .input_file("app.routes")
//! .output_file("routes.rs")
//! .build();
//! ```
//!
//! And import the generated route module into your app.
//!
//! ```ignore
//! include!(concat!(env!("OUT_DIR"), "/routes.rs"));
//! ```
//!
//! When a request comes in, match it against the route table:
//!
//! ```ignore
//! 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:
//!
//! ```
//! # use wayfinder::{get, post, param, header, RouteConfig, Routes, NestedRoutes};
//! 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:
//!
//! ```ignore
//! Builder::from_env()
//! .input_config(config)
//! .output_file("routes.rs")
//! .build();
//! ```
// TODO: crate-level docs
// TODO: better re-exports
pub use crate*;