a little http router generator
- what is it?
- getting started
- language reference
- status
- more information
Routing configuration is almost universally done dynamically during application initialization, even in systems that tend towards a static style. But the lines of change of routing are much slower than runtime, and we can make things much easier on ourselves by accepting that -- we get static typing of our routes for free!
The philosophy of wayfinder
is to compile routes at build time,
allowing a server to route with code that performs as well as a
hand-written router. Isn't that what we all want?
We also declare the route parameter types ahead of time, so the code to parse them is produced automatically, and our application code can focus on the domain level.
use uuid::Uuid;
/
[lang: String]
users
GET -> People::Index
people
GET People::Index
POST People::Create
new
GET People::New
{id: Uuid}
GET People::Show
PUT People::Update
[name: String]
DELETE People::Destroy
edit
GET People::Edit
Look at the basic example configurations in examples.routes
and
common.routes
.
Check out the example application in examples/cli/
, which
runs the routing algorithm as a CLI. Try out:
> cargo run /books/
A route configuration file is composed of two parts: an optional
header and the main hierarchical route configuration section. The
header can be any Rust code to be passed through to the generated
module, mainly to use
any types referred to below.
The route configuration starts with a line containing the single character '/'. The routes form a hierarchy, and the structure is recursively defined. It is whitespace-sensitive, with indentation level corresponding to nesting level. Blank lines can be added anywhere.
Each route segment can have three types of children: query parameters, resources, and nested routes. They must be specified in that order.
Query parameters are a name-type pair written inside square brackets,
like so: [lang: String]
. They apply to every resource on that
route and every nested route.
Resources are particular HTTP verbs that your application will
respond to. They consist of two required parts and an optional one.
The verb itself is listed first, followed by the name of the resource.
If the route should redirect to that resource rather than directly
serving it, an arrow can be written between the parts. So a simple
resource might look like GET people
, and a redirect GET -> people
.
Resources can also have query parameters, they are written in a block
nested under the resource.
Nested routes come last. The consist of a path segment followed by
a nested block of query parameters, resources, and routes. The
path segment can be either a static string (e.g. people
) or a
path parameter written between curly braces, like {id: Uuid}
.
wayfinder
is currently a work-in-progress. Here is a summary of
the current status compared to planned/potential updates:
-
Required before publishing 0.1
- Drop or fix
http
feature - Rewrite generated docs so they're accurate
- De-crateify
- Triage inline TODO items
- Smoke test app
- Drop or fix
-
Route file syntax
- Parse & stringify route files
- More robust parsing error reporting
- Comments in route files
- Merge multiple route files
- Other indentation options or a non-whitespace style
- TOML?
- Abandon?
-
Route config core
- Merge multiple route configs
- Two level (controller-action) route types
- Any level (module*-route) route types
- Documentation on using the
config
types directly frombuild.rs
- Some simple static checks (uniqueness of params, existence of redirect)
- Cargo rerun-if-changed output for build
-
Runtime functionality
- Match static routes
- Match catch-all route parameters
- More complicated parameter matching (e.g. regex)
- Match const query params and route on them
- Actually handle query string parameters
- Correctly handle bad routes
- Method parser & HTTP first-line parser
-
http
lib support instead of or in addition to the above - Fix
http
support & add tests -
Into
impls flow upward -
ToPath
or something trait -
link_to
helper leveraging the above - Add more context to parse errors?
- Error type enum based on
<$TY as FromStr>::Error
- Not allowed error needs allowed method list (per spec)
- Redirect should provide the code?
-
Refactorings and cleanups
- Get rid of any runtime dep on this lib
- Accept
AsRef<str>
instead ofIterator<Item=char>
- Actually
AsRef<[u8]>
since it must be ASCII - Accept
Read
? - Accept
AsyncRead
? - Match chunk-wise, not char-wise
- Only try parsing if route actually matches otherwise
-
Other use-cases
- JS router for SPA
- WASM router for SPA
- API docs
- API clients
- CLI args??
-
Meta-concerns
- Address all inline TODO items
- Better test coverage
- Add lints - require docs, idioms, etc
- More complete inline docs
- README for the wayfinder crate
- More complete metadata for the crate
- Upgrade nom (and other deps)
- Make codegen not so painful
- Migrate last codegen unit tests to functional tests
- Security review
- Micro benchmarking to eke out the most perf
- Macro benchmarking against other routers
See the generated documentation for usage help, both for this module as well as for the generated routes.