Web framework in Rust

Overview

Rouille, a Rust web micro-framework

Rouille is a micro-web-framework library. It creates a listening socket and parses incoming HTTP requests from clients, then gives you the hand to process the request.

Rouille was designed to be intuitive to use if you know Rust. Contrary to express-like frameworks, it doesn't employ middlewares. Instead everything is handled in a linear way.

Concepts closely related to websites (like cookies, CGI, form input, etc.) are directly supported by rouille. More general concepts (like database handling or templating) are not directly handled, as they are considered orthogonal to the micro web framework. However rouille's design makes it easy to use in conjunction with any third-party library without the need for any glue code.

Documentation

Getting started

If you have general knowledge about how HTTP works, the documentation and the well-documented examples are good resources to get you started.

License

Licensed under either of

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual licensed as above, without any additional terms or conditions.

FAQ

What about performances?

Async I/O, green threads, coroutines, etc. in Rust are still very immature.

The rouille library just ignores this optimization and focuses on providing an easy-to-use synchronous API instead, where each request is handled in its own dedicated thread.

Even if rouille itself was asynchronous, you would need asynchronous database clients and asynchronous file loading in order to take advantage of it. There are currently no such libraries in the Rust ecosystem.

Once async I/O has been figured out, rouille will be (hopefully transparently) updated to take it into account.

But is it fast?

On the author's old Linux machine, some basic benchmarking with wrk -t 4 -c 4 shows the following results:

  • The hello-world example of rouille yields ~22k requests/sec.
  • A hello world in nodejs (with http.createServer) yields ~14k requests/sec.
  • The hello-world example of tokio-minihttp (which is supposedly the fastest HTTP server that currently exists) yields ~77k requests/sec.
  • The hello example of hyper (which uses async I/O with mio as well) yields ~53k requests/sec.
  • A hello world in Go yields ~51k requests/sec.
  • The default installation of nginx yields ~39k requests/sec.

While not the fastest, rouille has reasonable performances. Amongst all these examples, rouille is the only one to use synchronous I/O.

Are there plugins for features such as database connection, templating, etc.

It should be trivial to integrate a database or templates to your web server written with rouille. Moreover plugins need maintenance and tend to create a dependency hell. In the author's opinion it is generally better not to use plugins.

But I'm used to express-like frameworks!

Instead of doing this: (pseudo-code)

server.add_middleware(function() {
    // middleware 1
});

server.add_middleware(function() {
    // middleware 2
});

server.add_middleware(function() {
    // middleware 3
});

In rouille you just handle each request entirely manually:

// initialize everything here

rouille::start_server(..., move |request| {
    // middleware 1

    // middleware 2

    // middleware 3
});
Comments
  • modify router macro

    modify router macro

    issue #155

    • Modify router! to take a string expr url instead of a token sequence.
      • Allows arbitrary routes with numbers/periods/non-token-types
    • Url parameters must be specified in the url string and in a trailing identity: type pair.
    • Update usage/tests and examples

    problems:

    • ~~Uses a HashMap when pulling url params out of the url string so it's definitely slower than the current implementation. (only routes with url params)~~
    • ~~Still need to get multiple param parsing working e.g. (GET) ("/add/{a}/plus/{b}", a: u32, b: u32) .... The meat of the macro should work, but pattern matching that section is finicky and would likely require an ugly trailing separator for the no param variant: e.g. (GET) ("/home",) ...~~
    opened by jaemk 10
  • Numbers in url

    Numbers in url

    Hello,

    It looks like the application won't compile if the routes have hardcoded numbers in them. For example this works :

    fn main() {
        println!("Listening!");
    
        rouille::start_server("0.0.0.0:8080", move |request| {
    
            router!(request, 
                (GET) (/) => {
                    Response::text("Hello world!")
                },
    
                (GET) (/two) => {
                    Response::text("Hello two!")
                },
    
                _ => Response::empty_404()
            )
    
        });
    }
    

    But this doesn't :

    fn main() {
        rouille::start_server("0.0.0.0:8080", move |request| {
    
            router!(request, 
                (GET) (/) => {
                    Response::text("Hello world!")
                },
    
                (GET) (/2) => {
                    Response::text("Hello 2!")
                },
    
                _ => Response::empty_404()
            )
    
        });
    }
    

    It leads to the following error:

    error: no rules expected the token `request_url`
      --> src/main.rs:11:9
       |
    11 | /         router!(request,
    12 | |             (GET) (/) => {
    13 | |                 Response::text("Hello world!")
    14 | |             },
    ...  |
    20 | |             _ => Response::empty_404()
    21 | |         )
       | |_________^
       |
       = note: this error originates in a macro outside of the current crate
    
    error: Could not compile `rustit`.
    
    Caused by:
      process didn't exit successfully: `rustc --crate-name rustit src/main.rs --crate-type bin --emit=
    dep-info,link -C debuginfo=2 -C metadata=9a526171b8297007 -C extra-filename=-9a526171b8297007 --out
    -dir /home/antoine/src/rust/rustit/target/debug/deps -L dependency=/home/antoine/src/rust/rustit/ta
    rget/debug/deps --extern rouille=/home/antoine/src/rust/rustit/target/debug/deps/librouille-0f6c379
    9a677a040.rlib -L native=/home/antoine/src/rust/Rustit/target/debug/build/brotli-sys-faf770ae9206b3
    55/out -L native=/home/antoine/src/rust/Rustit/target/debug/build/miniz-sys-c9ca5bf082b97141/out` (
    exit code: 101)
    

    Is this normal behaviour? Is there anyway to get around this?

    bug 
    opened by zer0tonin 10
  • add support for Serde

    add support for Serde

    Serde is the replacement for rustc-serialize so add support for it under a feature flag so that users can continue to use rustc-serialize until they have migrated their code. fixes #149.

    opened by cardoe 9
  • Non-blocking WebSocket polling

    Non-blocking WebSocket polling

    Related to #137, would it be possible to have a non-blocking variant of WebSocket::next? The idea would be the same as Receiver<T>::try_recv, it returns the next message if there is one ready, but returns without blocking if there are none. Without this functionality, it seems like it isn't possible to do something like have a thread wait for either a WebSocket or another channel.

    I took a brief look at the implementation of WebSocket::next and it looks like its the underlying Box<ReadWrite>::read implementation that blocks waiting for data from the socket. Given that rouille is built on tiny_http, would it even be possible to implement a non-blocking read from the socket? Also, is it possible that I'm completely off-base in thinking that it's not possible to wait on both a WebSocket and another channel?

    opened by randomPoison 9
  • Unpin time-rs version

    Unpin time-rs version

    The pin for time =0.3.2, while helping you keep consistency on MSRV, unfortunately gets in the way of other crates that would like to depend on time ^0.3.5 for checked_add/checked_sub (which should really be used everywhere in preference over the panicky overloaded operators), but don't care that much about keeping their MSRV back.

    opened by mzabaluev 8
  • What or, is best used with Rouille?

    What or, is best used with Rouille?

    I am at a point where i can use rouille for a basic web app, but whatever i try i can not get mysql to work. I keep getting errors after error, even though it works in other examples.

    so what would be the best way to make rouille work with a database? Obviously the example isn’t good for me as it only handles one connection at a time.

    opened by jhjacobs81 7
  • Fix try! deprecation warnings

    Fix try! deprecation warnings

    Recent Rust version 1.39 marked the try! macro as deprecated. This patch replaces all usages of the try! macro with the recommended question mark operator.

    opened by jayson-lennon 7
  • Use a custom derive for POST input structs

    Use a custom derive for POST input structs

    This is a follow-up to #49

    Once it's stable (https://github.com/rust-lang/rust/issues/35900), we can use the custom derive system for POST structs instead of using rustc-serialize.

    This has the big advantage that we can adjust the corresponding trait to our needs, and make it work for files.

    trait DecodePostField {
        fn from_field(content: &str) -> Result<Self, PostError>;
        fn from_file<R: BufRead>(file: R, mime: &str) -> Result<Self, PostError>;
    }
    
    trait DecodePostInput {
        fn decode<I: Iterator<Item = PostInputElement>>(elements: I) -> Result<Self, PostError>;
    }
    

    Example in practice:

    #[derive(RouillePostDecode)]      // implements DecodePostInput on the struct
    struct Input {
        field1: i32,         // each field must implement DecodePostField
        field2: String,
        file: TemporaryFileStorage,
    }
    
    let input: Input = try_or_400!(rouille::post::decode(&request));
    

    If you read #49 I explain at the bottom that it isn't possible to do this. But if we use a trait other than the one in rustc-serialize, then it becomes a viable option.

    In this example, the from_file method of TemporaryFileStorage would write the file to a temporary directory by streaming from the user's request, and then will return a TemporaryFileStorage struct that contains the path to the file. If the TemporaryFileStorage struct gets dropped before being stored in a database (for example because of a panic), its destructor would automatically delete the file.

    Rouille could provide some helpers, like:

    • TemporaryFileStorage
    • BufferedFile (stores the content in memory)

    There is one unresolved question, however: how do we provide a configuration for TemporaryFileStorage or BufferedFile? While these two cases don't need a configuration, it would be nice if we could write a S3File struct that automatically uploads to S3 or a ProxyFile that transfers the file to another service. But doing so requires some sort of configuration to be passed to from_file.

    opened by tomaka 7
  • Stoppable server

    Stoppable server

    Summary

    Added the Server::stoppable() function which provides a method for gracefully stopping a Server.

    Motivation

    There was obvious way to gracefully stop a Rouille server, and I ended up implementing this code in my own project. Since it's fairly simple and a useful feature I figured I would contribute it back.

    See the provided documentation example for basic usage.

    opened by rushsteve1 6
  • Maintenance Status

    Maintenance Status

    Hi

    First off, thank you for creating Rouille, it's a wonderful library in a world of overcomplicated async frameworks.

    Correlated to https://github.com/tiny-http/tiny-http/issues/199, I wondered if there were any plans to continue maintaining this crate? I've noticed some bugfix and compatible enhancement PRs have been open for over two years without further comment.

    If you feel it's feature complete that's totally understandable, but if you would like some help responding to issues and PRs, or if you simply don't have time to remain involved with the project, then I'm ready to help.

    opened by bradfier 5
  • Fix some TODOs in Request and Content Encoding

    Fix some TODOs in Request and Content Encoding

    Hello there!

    With some time on my hands currently, I decided to fix some TODOs throughout the code base of Rouille.

    Let me know what you think. :)

    Cheers, Sven.

    opened by svenvdvoort 5
  • Remove dependency on num_cpus

    Remove dependency on num_cpus

    Replace the one call to num_cpus::get() with thread::available_parallelism() which has been stable since Rust 1.59 and has nearly identical functionality.

    This allows for removing the dependency on num_cpus entirely.

    opened by meesfrensel 0
  • Ssl server

    Ssl server

    Hello @tomaka @bradfier,

    I added two simple macros, in similar fashion as start_server but with an extra local SSL context, so we can deploy an HTTPS server easily

    opened by gwbres 0
  • Parse arbitrary types in forms

    Parse arbitrary types in forms

    If I want to be able to parse, say, std::net::Ipv4Addr I would have to:

    • impl DecodePostField<()> for std::net::Ipv4Addr which is not possible
    • I still can make a wrapper struct for which I'll implement it but it's still not possible because:
    • there's no PostFieldError variant I can return in case things go wrong

    How could I parse my own types ?

    opened by bestouff 0
  • Unix Domain?

    Unix Domain?

    Handling requests from an upstream server, or tor, is a must! If the upstream server is local it becomes encumbering to use ports on a localhost interface for IPC. Enter Unix Domain Sockets.

    opened by cheako 2
Releases(v3.6.1)
  • v3.6.1(Oct 12, 2022)

  • v3.6.0(Oct 12, 2022)

    Changes

    • Added rustls support (via tiny-http), if you're currently using the ssl feature you can switch from OpenSSL to Rustls by instead enabling the rustls feature in your Cargo.toml.
    • Added a number of default features to allow users to reduce their dependency graph where they don't need all the functionality Rouille provides. logging, assets, post and session are now optional, but enabled by default for backwards compatibility.
    • Correctly support 'flag' type query parameters where the parameter has no associated value. Previously a query like GET /?foo would return None from get_param, instead of Some("").
    • Updated tiny-http to 0.12.0, further reducing the dependency tree by breaking our hard requirement on time-rs. This version of tiny-http also enables Unix socket listeners, which will be exposed in a future release of Rouille.

    New Contributors

    • @HookedBehemoth made their first contribution in https://github.com/tomaka/rouille/pull/254
    • @vmiklos made their first contribution in https://github.com/tomaka/rouille/pull/265
    • @DeWarner made their first contribution in https://github.com/tomaka/rouille/pull/259

    Full Changelog: https://github.com/tomaka/rouille/compare/v3.5.0...v3.6.0

    Source code(tar.gz)
    Source code(zip)
  • v3.5.0(Dec 22, 2021)

    Changes

    • Replaced our use of the brotli2 crate with the alternative pure Rust implementation brotli. This removes Rouille's vulnerability to RUSTSEC-2021-0131, which existed due to brotli-sys bundling a vulnerable version of the underlying C library.
    • Unpinned time-rs and as a result increased our MSRV to 1.51, we don't have a formal MSRV policy and the ecosystem is making it more and more difficult to support compiler versions more than about 6 months old.

    All Changes: https://github.com/tomaka/rouille/compare/v3.4.0...v3.5.0

    Source code(tar.gz)
    Source code(zip)
  • v3.4.0(Nov 4, 2021)

    Changes

    • Resolved a number of cleanup & refactoring TODOs
    • Correctly identify non-lowercase content types as text (e.g. text/JSON would be incorrectly identified as non-text).
    • Pinned time-rs to 0.3.2 to avoid a semver-breaking change in their MSRV.
    • Bumped chrono to 0.4.19 and disabled their default feature set to avoid warnings about RUSTSEC-2020-0071 (Rouille was never vulnerable, but used a vulnerable version of chrono).
    Source code(tar.gz)
    Source code(zip)
  • v3.3.1(Sep 15, 2021)

    Changes

    • Use .strip_prefix in place of .starts_with where appropriate, this stops a Clippy lint from leaking out of our router! macro and into downstream code.
    Source code(tar.gz)
    Source code(zip)
  • v3.3.0(Sep 1, 2021)

    Changes

    • Bumped minimum supported Rust version to 1.48
    • Added module-level documentation for rouille::content_encoding
    • Updated time dependency to 0.3 and postgres to 0.19 to fix a compile failure due to a yanked version of sha1.
    • Fixed numerous typos in the crate documentation.
    Source code(tar.gz)
    Source code(zip)
  • v3.2.1(Jun 30, 2021)

  • v3.2.0(Jun 29, 2021)

    Changes

    • Add ResponseBody::from_reader_and_size for constructing a ResponseBody from a Reader and an already known size such that Content-Length may be set on the response.
    Source code(tar.gz)
    Source code(zip)
  • v3.1.0(Apr 25, 2021)

    Changes

    • Add Server::poll_timeout() for polling more efficiently.
    • Add Server::stoppable() for running a single, cancellable server thread.
    • Add Server::join() for finalising all in-flight requests before shutting down.
    • Prevent infinite loop on Websocket EOF
    • Update tiny-http to 0.8.1 containing fixes for:
      • HTTPS deadlock where one request holds a locked resource while another is attempting HTTPS negotiation
      • Fix RUSTSEC-2020-0031
      • Don't set Transfer-Encoding: chunked on 1xx or 204 responses (which can lead to clients hanging).
    • Bump minimum support Rust version to 1.41.1
    Source code(tar.gz)
    Source code(zip)
Owner
Pierre Krieger
Pierre Krieger
An Extensible, Concurrent Web Framework for Rust

Iron Extensible, Concurrency Focused Web Development in Rust. Response Timer Example Note: This example works with the current iron code in this repos

null 6.1k Dec 27, 2022
An expressjs inspired web framework for Rust

nickel.rs nickel.rs is a simple and lightweight foundation for web applications written in Rust. Its API is inspired by the popular express framework

null 3k Jan 3, 2023
A web framework for Rust.

Rocket Rocket is an async web framework for Rust with a focus on usability, security, extensibility, and speed. #[macro_use] extern crate rocket; #[g

Sergio Benitez 19.5k Jan 8, 2023
A lightweight web framework built on hyper, implemented in Rust language.

Sapper Sapper, a lightweight web framework, written in Rust. Sapper focuses on ergonomic usage and rapid development. It can work with stable Rust. Sa

Daogang Tang 622 Oct 27, 2022
Web framework in Rust

Rouille, a Rust web micro-framework Rouille is a micro-web-framework library. It creates a listening socket and parses incoming HTTP requests from cli

Pierre Krieger 840 Jan 1, 2023
A fast, boilerplate free, web framework for Rust

Tower Web A web framework for Rust with a focus on removing boilerplate. API Documentation Tower Web is: Fast: Fully asynchronous, built on Tokio and

Carl Lerche 969 Dec 22, 2022
Sincere is a micro web framework for Rust(stable) based on hyper and multithreading

The project is no longer maintained! Sincere Sincere is a micro web framework for Rust(stable) based on hyper and multithreading. Style like koa. The

null 94 Oct 26, 2022
Salvo is a powerful and simplest web server framework in Rust world

Salvo is an extremely simple and powerful Rust web backend framework. Only basic Rust knowledge is required to develop backend services.

Salvo 1.2k Jan 5, 2023
The light web framework for Rust.

Rusty Web Rusty web is a simple to use, fully customizable lightweight web framework for rust developers. Learn rusty web Installation [dependencies]

Tej Magar 5 Feb 27, 2024
A flexible web framework that promotes stability, safety, security and speed.

A flexible web framework that promotes stability, safety, security and speed. Features Stability focused. All releases target stable Rust. This will n

Gotham 2.1k Jan 3, 2023
Handlebars middleware for Iron web framework

handlebars-iron Handlebars middleware for the Iron web framework. This library, together with handlebars, iron and hyper, works on both stable and nig

Ning Sun 118 Jun 28, 2022
A toy web framework inspired by gin-gonic/gin and expressjs/express.

Rum Framework A toy web framework inspired by gin-gonic/gin and expressjs/express. Installation Just add rum_framework to the dependencies of Cargo.to

Hidetomo Kou(YingZhi 2 Dec 20, 2022
JSON Web Token implementation in Rust.

Frank JWT Implementation of JSON Web Tokens in Rust. Algorithms and features supported HS256 HS384 HS512 RS256 RS384 RS512 ES256 ES384 ES512 Sign Veri

Alex Maslakov 246 Dec 27, 2022
Source Code for 'Practical Rust Web Projects' by Shing Lyu

Apress Source Code This repository accompanies Practical Rust Web Projects by Shing Lyu (Apress, 2021). Download the files as a zip using the green bu

Apress 44 Nov 17, 2022
A web application completely written in Rust. 🌍

WebApp.rs A web application completely written in Rust Target of this project is to write a complete web application including backend and frontend wi

Sascha Grunert 2.1k Dec 30, 2022
Web Server made with Rust - for learning purposes

Web Server made with Rust - for learning purposes

Lílian 2 Apr 25, 2022
Archibald is my attempt at learning Rust and writing a HTTP 1.1 web server.

Archibald To be a butler, is to be able to maintain an even-temper, at all times. One must have exceptional personal hygiene and look sharp and profes

Daniel Cuthbert 4 Jun 20, 2022
VRS is a simple, minimal, free and open source static web server written in Rust

VRS is a simple, minimal, free and open source static web server written in Rust which uses absolutely no dependencies and revolves around Rust's std::net built-in utility.

null 36 Nov 8, 2022
Example Blog using Rust, Actix Web, HTMX, Mustache

Actix Blog An example blog built with Actix. It uses htmx and handlebar templates. Running To run the blog, you need to have a recent version of Rust

Dru Jensen 2 Nov 11, 2022