[][src]Crate vial

~ vial: a micro micro-framework ~

Vial is a small web "framework" for making small web sites.

It only includes a few basics:

  • routes!: Macro for mapping URLs to handlers.
  • Request: Information about the current request, such as form data or URL path segments.
  • Response: Response to deliver to the client.
  • Responder: Trait to convert your types or a few built-ins like String into a Response.
  • asset: Serving of static files and support for bundling into the release binary.

Everything else... well, that's up to you.

The goal is an as-few-as-possible-dependencies web library you can use to test out an idea quickly or get a personal project rolling. Single file, server side apps? You bet! Fast compilation? Yes please! À la carte dependencies? Now you're talkin'!

It's sort of like a picnic where the playlist is all 90s music and you have to bring your own beverages. And food.

To learn more, keep reading or visit one of these links:

Status: Vial is currently in early development. It is being developed alongside [deadwiki], but that is strictly for personal use. Proceed with caution.

To get started, just add vial to your Cargo.toml:

vial = "0.1"

There are a handful of --features that you can enable, most of which add additional dependencies that need to be included:

vial = { version = "*", features = ["horror", "cookies"] }

This list is a work in progress:

  • [x] horror: Small & fast macro-based HTML builder, via [horrowshow].
  • [x] json_serde: Request::json and Response::with_json powers, via Serde.
  • [x] cookies: Cookie monster!
  • [ ] sessions: Session support
  • [ ] multipart: Multipart form data (file uploads)
  • [ ] log: Access logging

~ hello world ~

As is tradition:

vial::routes! {
    GET "/" => |_| "Hello, world!";

fn main() {

For a bit more sanity, you can route to functions directly:

use vial::prelude::*;

routes! {
    GET "/echo" => echo;
    POST "/echo" => post;

fn echo(_: Request) -> &'static str {
    "<form method='POST'>
        <input type='text' name='echo'/>
        <input type='submit'/>

fn post(req: Request) -> String {
        req.form("echo").unwrap_or("You didn't say anything!")

fn main() {

To really break the mold, you can split your site into different modules:

mod wiki {
    vial::routes! {
        GET "/wiki" => |_| Response::from_file("wiki.html");
        // etc...

mod blog {
    vial::routes! {
        GET "/blog" => |_| Response::from_file("wiki.html");
        // etc...

mod index {
    use vial::prelude::*;
    routes! {
        GET "/" => |_| Response::from_file("index.html");

fn main() {
    // The order matters here - if `wiki` and `blog` both define "/",
    // the `mod index` version will match first and get run.
    vial::run!(index, wiki, blog);

But hey, who wants to putz around with HTML when you can be writing Rust? Enable the horror feature and you're on your way:

This example is not tested
use vial::prelude::*;

routes! {
    GET "/" => |_| html! {
        p {
            : "You're looking for this: ";
            a(href="/echo") { : "echo" }
    GET "/echo" => echo;
    POST "/echo" => post;

fn echo(_: Request) -> impl Responder {
    html! {
        form(method="POST") {
            p {
            : "Type something: ";
                input(type="text", name="echo");

fn post(req: Request) -> impl Responder {
    owned_html! {
        h1: req.form("echo")
            .unwrap_or("You didn't say anything!");

fn main() {

~ performance ~

We want to keep Vial snappy, but this is not a production web server that's competing in any shootouts. Our bigger priority is keeping the base dependency count and compilation time low.

~ when to use ~

Probably never, or only ever to quickly test an idea. Certainly not for personal wikis or small hobby projects, unless you insisted.



Vial can serve static files out of an asset directory and optionally bundle them into your application in --release mode.


The prelude pulls in all the main types, traits, and macros:



Vial can serve static files out of an asset directory, complete with ETag support so your browser isn't constantly re-downloading.


If you want to bundle your assets into your final binary in release mode, then you need to call vial::bundle_assets!() with the path to your asset directory in a build.rs file.


The vial::routes! macro, they say, is half of the battle, with the other 50% being a toss up between "knowledge" and the vial::run! macro you use to start your app.


The vial::run! macro is the preferred way of starting your Vial application after you've defined one or more routes using vial::routes!. run! performs a bit of necessary setup, then starts listening for client requests at by default.


Same as vial::run!(), but allows setting a banner that will be printed to the console when your Vial web app starts.


Gives Vial a state object to manage globally. You can access it by calling request.state::<YourStruct>() in an action.



Contains information about a single request.


Each request ultimately ends in a Response that is served to the client and then discarded, like fallen flower petals. Together with Request and Responder it forms the holy trinity of R's in Vial.


Router keeps track of all the routes defined by vial::routes! and can produce an action for a given HTTP Method and URL path combination using action_for.


The TypeCache is heavily inspired by the state crate and the way the Rocket framework handles global and local state. You could say we've immutably borrowed some ideas. Rim-shot!



Possible Vial errors.


Method is just an enum representing the HTTP methods Vial supports. Which is not all of them.



Date and time this program was compiled.


Crate version



Directory where assets are stored, if any.


Assets bundled into the binary in release mode.



The Responder trait converts your custom types or a few basic Rust types into a Response that gets hand delivered to the HTTP client in a timley fashion, barring any weather delays.

Type Definitions


Convenience Result that returns vial::Error.