A fast, boilerplate free, web framework for Rust

Overview

Tower Web

A web framework for Rust with a focus on removing boilerplate.

Build Status License: MIT Crates.io Gitter

API Documentation

Tower Web is:

  • Fast: Fully asynchronous, built on Tokio and Hyper.
  • Ergonomic: Tower-web decouples HTTP from your application logic, removing all boilerplate.
  • Works on Rust stable: You can use it today.

Hello World

#[macro_use]
extern crate tower_web;
extern crate tokio;

use tower_web::ServiceBuilder;
use tokio::prelude::*;

/// This type will be part of the web service as a resource.
#[derive(Clone, Debug)]
struct HelloWorld;

/// This will be the JSON response
#[derive(Response)]
struct HelloResponse {
    message: &'static str,
}

impl_web! {
    impl HelloWorld {
        #[get("/")]
        #[content_type("json")]
        fn hello_world(&self) -> Result<HelloResponse, ()> {
            Ok(HelloResponse {
                message: "hello world",
            })
        }
    }
}

pub fn main() {
    let addr = "127.0.0.1:8080".parse().expect("Invalid address");
    println!("Listening on http://{}", addr);

    ServiceBuilder::new()
        .resource(HelloWorld)
        .run(&addr)
        .unwrap();
}

Overview

Tower Web aims to decouple all HTTP concepts from the application logic. You define a "plain old Rust method" (PORM?). This method takes only the data it needs to complete and returns a struct representing the response. Tower Web does the rest.

The impl_web macro looks at the definition and generates the glue code, allowing the method to respond to HTTP requests.

Getting Started

The best way to get started is to read the examples and API docs.

License

This project is licensed under the MIT license.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in tower-web by you, shall be licensed as MIT, without any additional terms or conditions.

Comments
  • Port tower-web to Edition 2018

    Port tower-web to Edition 2018

    Since I needed it to work with 2018 edition I've spend 10-15 minutes just porting it and at the end the async/await example also works!

    I've just ran the cargo fix --edition and fixed one place where ::Error was left. The rest was just changing the example and the Cargo.toml of the project and the example.

    Plus the features futures_api is not necessary any more.

    Fixes https://github.com/carllerche/tower-web/issues/192#issuecomment-482449190

    opened by elpiel 55
  • Stream of consciousness thoughts from a first-time user

    Stream of consciousness thoughts from a first-time user

    My context is evaluating replacements for Iron for the Rust Playground.

    I've just skimmed hello_world so far. My raw thoughts are:

    Why's all this code commented out?

    How do I serve a file?

    Ah, there's custom headers

    How do I handle CORS?

    Is there an overall vision for "features" and extensibility for tower-web? Do you want to farm things out to multiple crates, or have "most" / "common" things in one crate? Based on Tokio, I'm assuming many crates and perhaps re-export them in -web?

    How do I return a Future from a method?

    #[derive(Clone, Debug)]
    pub struct SelfServing;
    
    impl_web! {
        impl SelfServing {
            /// @get("/")
            /// @content_type("plain")
            fn x(&self) -> impl Future<Item = String, Error = ()> {
    
    error[E0599]: no method named `run` found for type `tower_web::ServiceBuilder<SelfServing, _>` in the current scope
      --> examples/static_file.rs:37:10
       |
    37 |         .run(&addr)
       |          ^^^
       |
       = note: the method `run` exists but the following trait bounds were not satisfied:
               `__IMPL_WEB_0_FOR_SelfServing::DispatchFuture<tower_web::response::DefaultSerializer, tower_web::run::LiftReqBody> : std::marker::Send`
    

    Content type feels like it should be a property of the return type, but maybe optionally overridable by an attribute

    opened by shepmaster 28
  • Fitting handlebars template engine into Response/Serializer or Middleware system

    Fitting handlebars template engine into Response/Serializer or Middleware system

    I was looking into tower-web to integrate handlebars into its system.

    The typical usage of handlebars in web application is to create a server-scoped registry, that holds all templates in memory. We use the registry to render templates returned from handler functions.

    The ideal API for tower-web in my mind is to create a Template struct, which contains template name and template data. The Template struct will implement Response to render the data structure into actual http response. The problem is Response trait only provides a request-scoped Context so there seems to be no way to access server-scoped handlebars registry.

    So is it possible to bind the registry into some data structure that has server-scoped lifetime? And be accessible from Response trait and middlewares.

    opened by sunng87 17
  • Edition 2018 updates

    Edition 2018 updates

    • removes extern crate
    • removes #[macro_use] attributes
    • applies the modules system changes from 2018 edition, removing the mod.rs file

    Opened questions:

    • Should we update all the code (including docs) to use 2018 edition?

    TODOs:

    • ~Remove other extern crate + #[macro_use]~ Done

    Maybe Resolves #37

    opened by elpiel 14
  • How to handle authentication

    How to handle authentication

    In our applications we use JSON Web Tokens in authorization header and in some cases an access_token parameter in query string to authenticate user requests. Since some resources may allow an anonymous access, while other restrict it to users with particular permissions, we need a way to determine if token was presented in a request and if it's presented – validate and extract an information from it (for instance, sub claim in our tokens contains a user identifier).

    Is there already any concept how it could be implemented?

    opened by manifest 12
  • Writing an HTTP proxy

    Writing an HTTP proxy

    I am exploring tower-web by writing a simple HTTP proxy. In this application, I would like to perform some header validation on each request, forward it to a pre-defined endpoint, and then forward the received response back to the original client. I am using a hyper::Client in each HTTP method handler to connect to the endpoint, but I am finding that I am duplicating the header validation code across each handler, which seems rather brittle to me. Is there a clean way to wrap a given type T where T implements IntoResource such that I can enforce this header validation for all incoming requests on all handlers in one place?

    enhancement 
    opened by ebkalderon 10
  • Percent-decode Strings and PathBufs

    Percent-decode Strings and PathBufs

    The user certainly wants this, and it helps with preventing directory traversal attacks.

    ~~The implementation supports arbitrary paths on Unix-like systems, and valid UTF-8 ones on Windows. I couldn't find a common way of percent-encoding Windows file paths, but this could potentially be improved in the future.~~

    The implementation doesn't support non-UTF-8 paths.

    Fixes #107.

    opened by lnicola 10
  • Returning different response types from the same handler

    Returning different response types from the same handler

    E.g. I want to return either a File or an HTML page. I could probably make do with an enum that implements Response, but the File and String impls have different item types, so it's awkward.

    Is there anything tower-web can do to make this easier?

    question 
    opened by lnicola 10
  • Use attribute syntax instead of magic comments

    Use attribute syntax instead of magic comments

    You'd asked me to open an issue to discuss strategy, so here we go. There are basically two options. Ultimately the whole thing is getting passed to a derive, so the simplest option is to not have impl_web! spit out the tokens its given unmodified, and instead have derive_resource! spit out its input (with the recognized attributes stripped) in addition to what it spits out today.

    You mentioned you had a solution which works and messes up error messages, so I'm assuming it's the solution above. The second option would be to run the tokens passed to impl_web! through another macro before outputting them. This would be a basic macro_rules! macro, which strips out regonized meta items.

    Both of these options are pretty simple to implement. Diesel does both in multiple places (depending on whether our macro is fundamentally a macro_rules! or procedural macro). Would love to hear more about whether this would somehow affect your error messages.

    opened by sgrif 10
  • Improve error when the templates directory is misplaced

    Improve error when the templates directory is misplaced

    Problem

    When I cargo run the following I get a 500. That's all I know. Nothing else is displayed, no warnings, errors, hints, nothing.

    Code

    ./src/main.rs:

    #[macro_use]
    extern crate tower_web;
    extern crate tokio;
    
    use tower_web::ServiceBuilder;
    use tokio::prelude::*;
    
    #[derive(Clone, Debug)]
    struct Service;
    
    #[derive(Response)]
    struct IndexModel {
        title: &'static str,
    }
    
    impl_web! {
        impl Service {
            #[get("/")]
            #[content_type("html")]
            #[web(template = "index")]
            fn get_index(&self) -> Result<IndexModel, ()> {
                Ok(IndexModel {
                    title: "hello world",
                })
            }
        }
    }
    
    pub fn main() {
        let addr = "127.0.0.1:8080".parse().expect("Invalid address");
        println!("Listening on http://{}", addr);
    
        ServiceBuilder::new()
            .resource(Service)
            .run(&addr)
            .unwrap();
    }
    

    ./src/templates/index.hbs:

    <html>
        <head>{{ title }}</head>
        <body>
            <div><h1>Winning!</h1></div>
        </body>
    </html>
    
    $ cargo run
       Compiling fieldmsg v0.1.0 (file:///Users/taryn/src/saas/fieldmsg)
    warning: unused import: `tokio::prelude`
     --> src/main.rs:6:5
      |
    6 | use tokio::prelude::*;
      |     ^^^^^^^^^^^^^^
      |
      = note: #[warn(unused_imports)] on by default
    
        Finished dev [unoptimized + debuginfo] target(s) in 3.12s
         Running `target/debug/fieldmsg`
    Listening on http://127.0.0.1:8080
    
    # in a different shell ...
    $ http localhost:8080
    
    HTTP/1.1 500 Internal Server Error
    content-type: text/plain
    date: Sun, 07 Oct 2018 12:15:01 GMT
    transfer-encoding: chunked
    
    internal server error
    

    What am I supposed to do with this? How can I troubleshoot?

    More info

    $ cargo --version
    cargo 1.29.0 (524a578d7 2018-08-05)
    $ rustc --version
    rustc 1.29.1 (b801ae664 2018-09-20)
    
    [dependencies]
    tower-web = "0.3.0"
    tokio = "0.1.11"
    serde = "1.0.79"
    

    Edit:

    I get the exact same result if I move templates/ to the root of the project (same dir as Cargo.toml).

    paper cut 
    opened by phrohdoh 9
  • Could `BufStream` be flattened?

    Could `BufStream` be flattened?

    As currently defined, BufStream produces a stream of Buf values, which in turn may contain multiple [u8] slices. I was curious what the tradeoffs were around, instead, having BufStream yield AsRef<[u8]> directly, thus "flattening" these two layers. I'm pretty sure there are straightforward ways to translate in either direction, but I may be missing something.

    opened by aturon 6
  • error: unused extern crate proc_macro when trying to run examples

    error: unused extern crate proc_macro when trying to run examples

    The examples fail to compile, could you fix? Steps to reproduce and error below.

    git clone https://github.com/carllerche/tower-web.git
    cd tower-web
    cargo build --example hello_world
    
       Compiling tower-web-macros v0.3.5 (/tower-web/tower-web-macros)
    warning: deny(rust_2018_idioms) is ignored unless specified at crate level
     --> tower-web-macros/src/lib.rs:2:8
      |
    2 | #[deny(rust_2018_idioms)]
      |        ^^^^^^^^^^^^^^^^
      |
      = note: `#[warn(unused_attributes)]` on by default
    
    warning: deny(rust_2018_idioms) is ignored unless specified at crate level
     --> tower-web-macros/src/lib.rs:2:8
      |
    2 | #[deny(rust_2018_idioms)]
      |        ^^^^^^^^^^^^^^^^
    
    error: unused extern crate
     --> tower-web-macros/src/lib.rs:4:1
      |
    2 | / #[deny(rust_2018_idioms)]
    3 | |
    4 | | extern crate proc_macro;
      | | ^^^^^^^^^^^^^^^^^^^^^^^-
      | |________________________|
      |                          help: remove it
      |
    note: the lint level is defined here
     --> tower-web-macros/src/lib.rs:2:8
      |
    2 | #[deny(rust_2018_idioms)]
      |        ^^^^^^^^^^^^^^^^
      = note: `#[deny(unused_extern_crates)]` implied by `#[deny(rust_2018_idioms)]`
    
    error: aborting due to previous error; 2 warnings emitted
    
    error: could not compile `tower-web-macros`
    

    OS: MacOS Big Sur 11.3.1 tower-web version: the latest one rustc 1.51.0 (2fd73fabe 2021-03-23) cargo 1.51.0 (43b129a20 2021-03-16)

    opened by bio 0
  • What should I add to

    What should I add to "Cargo.toml"?

    Hi, can you please add in the README here (and early on in the API docs website) what specifically to add to your Cargo.toml file to make the "hello world" example code work? 🙏

    Thanks!

    opened by JimLynchCodes 0
  • [Proposal] Contribute to a benchmark

    [Proposal] Contribute to a benchmark

    Hi,

    I'm leading a benchmarking project => https://github.com/the-benchmarker/web-frameworks

    The purpose of this project is to compare performances (other indicators will come), based on a fairest, as we can, comparison for rust frameworks (comparing on the same version, for example).

    Do you mind that I (or any member) add tower-web ? :heart:

    Regards,

    opened by waghanza 0
  • tower-web spends significant time copying data around

    tower-web spends significant time copying data around

    This is a relatively basic app that just listens to a HTTP POST request, to which I'm sending around ~2GB of data.

    image

    The framework seems to spends around 9 seconds copying data around, and around 6 seconds in generated code (the _IMPL_WEB_0 stuff).

    This is on Windows, reasonably fast machine (i9, 16G of ram etc), copying the same file around in explorer takes round 2-3 seconds.

    opened by Jasper-Bekkers 0
Owner
Carl Lerche
I do stuff, I say stuff. It's serious business.
Carl Lerche
Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust.

Actix Web Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust Features Supports HTTP/1.x and HTTP/2 Streaming and pipelining

Actix 16.3k Jan 8, 2023
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
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
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
A blazingly fast static web server with routing, templating, and security in a single binary you can set up with zero code. :zap::crab:

binserve ⚡ ?? A blazingly fast static web server with routing, templating, and security in a single binary you can set up with zero code. ?? UPDATE: N

Mufeed VH 722 Dec 27, 2022
Simple and fast web server

see Overview Simple and fast web server as a single executable with no extra dependencies required. Features Built with Tokio and Hyper TLS encryption

null 174 Dec 9, 2022
:zap: fast http framework for rust

zap ⚡ The mission of zap is, to deliver a basic, but fast rust web server library. Documentation About This code is based on tokio's minihttp project,

Daniel Oltmanns 51 Jun 7, 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