Thruster - An fast and intuitive rust web framework

Overview

Thruster Build Status Crates.io Crates.io Discord

An fast and intuitive rust web framework

Runs in stable Runs fast Doesn't use unsafe

Documentation

Features

Motivation

Thruster is a web framework that aims for developers to be productive and consistent across projects and teams. Its goals are to be:

  • Performant
  • Simple
  • Intuitive

Thruster also

  • Does not use unsafe
  • Works in stable rust

Fast

Thruster can be run with different server backends and represents a nicely packaged layer over them. This means that it can keep up with the latest and greatest changes from the likes of Hyper, Actix, or even ThrusterServer, a home-grown http engine.

Intuitive

Based on frameworks like Koa, and Express, thruster aims to be a pleasure to develop with.

Example

To run the example cargo run --example . For example, cargo run --example hello_world and open http://localhost:4321/

Middleware Based

The core parts that make the new async await code work is designating middleware functions with the #[middleware_fn] attribute (which marks the middleware so that it's compatible with the stable futures version that thruster is built on,) and then the async_middleware! macro in the actual routes.

A simple example for using async await is:

) -> MiddlewareResult { let val = "Hello, World!"; context.body(val); Ok(context) } #[middleware_fn] async fn four_oh_four(mut context: Ctx, _next: MiddlewareNext) -> MiddlewareResult { context.status(404); context.body("Whoops! That route doesn't exist!"); Ok(context) } #[tokio::main] fn main() { println!("Starting server..."); let mut app = App::::new_basic(); app.get("/plaintext", m![profile, plaintext]); app.set404(m![four_oh_four]); let server = Server::new(app); server.build("0.0.0.0", 4321).await; } ">
use std::boxed::Box;
use std::future::Future;
use std::pin::Pin;
use std::time::Instant;

use thruster::{App, BasicContext as Ctx, Request};
use thruster::{m, middleware_fn, MiddlewareNext, MiddlewareResult, Server, ThrusterServer};

#[middleware_fn]
async fn profile(context: Ctx, next: MiddlewareNext) -> MiddlewareResult {
    let start_time = Instant::now();

    context = next(context).await;

    let elapsed_time = start_time.elapsed();
    println!(
        "[{}μs] {} -- {}",
        elapsed_time.as_micros(),
        context.request.method(),
        context.request.path()
    );

    Ok(context)
}

#[middleware_fn]
async fn plaintext(mut context: Ctx, _next: MiddlewareNext) -> MiddlewareResult {
    let val = "Hello, World!";
    context.body(val);
    Ok(context)
}

#[middleware_fn]
async fn four_oh_four(mut context: Ctx, _next: MiddlewareNext) -> MiddlewareResult {
    context.status(404);
    context.body("Whoops! That route doesn't exist!");
    Ok(context)
}

#[tokio::main]
fn main() {
    println!("Starting server...");

    let mut app = App::<Request, Ctx, ()>::new_basic();

    app.get("/plaintext", m![profile, plaintext]);
    app.set404(m![four_oh_four]);

    let server = Server::new(app);
    server.build("0.0.0.0", 4321).await;
}

Error handling

It's recommended to use the map_try! macro from the main package. This has the same function as try!, but with the ability to properly map the error in a way that the compiler knows that execution ends (so there's no movement issues with context.)

This ends up looking like:

) -> MiddlewareResult { let res = "Hello, world".parse::(); let non_existent_param = map_try!(res, Err(_) => { Error { context, message: "Parsing failure!".to_string(), status: 400 } } ); context.body(&format!("{}", non_existent_param)); Ok(context) } #[middleware_fn] async fn json_error_handler(context: Ctx, next: MiddlewareNext) -> MiddlewareResult { let res = next(context).await; let ctx = match res { Ok(val) => val, Err(e) => { let mut context = e.context; context.body(&format!( "{{\"message\": \"{}\",\"success\":false}}", e.message )); context.status(e.status); context } }; Ok(ctx) } #[tokio::main] fn main() { println!("Starting server..."); let mut app = App::::new_basic(); app.use_middleware("/", m![json_error_handler]); app.get("/plaintext", m![plaintext]); app.get("/error", m![error]); let server = Server::new(app); server.build("0.0.0.0", 4321).await; } ">
use thruster::errors::ThrusterError as Error;
use thruster::proc::{async_middleware, middleware_fn};
use thruster::{map_try, App, BasicContext as Ctx, Request};
use thruster::{MiddlewareNext, MiddlewareResult, MiddlewareReturnValue, Server, ThrusterServer};

#[middleware_fn]
async fn plaintext(mut context: Ctx, _next: MiddlewareNext) -> MiddlewareResult {
    let val = "Hello, World!";
    context.body(val);
    Ok(context)
}

#[middleware_fn]
async fn error(mut context: Ctx, _next: MiddlewareNext) -> MiddlewareResult {
    let res = "Hello, world".parse::<u32>();
    let non_existent_param = map_try!(res, Err(_) => {
        Error {
          context,
          message: "Parsing failure!".to_string(),
          status: 400
        }
      }
    );

    context.body(&format!("{}", non_existent_param));

    Ok(context)
}

#[middleware_fn]
async fn json_error_handler(context: Ctx, next: MiddlewareNext) -> MiddlewareResult {
    let res = next(context).await;

    let ctx = match res {
        Ok(val) => val,
        Err(e) => {
            let mut context = e.context;
            context.body(&format!(
                "{{\"message\": \"{}\",\"success\":false}}",
                e.message
            ));
            context.status(e.status);
            context
        }
    };

    Ok(ctx)
}

#[tokio::main]
fn main() {
    println!("Starting server...");

    let mut app = App::<Request, Ctx, ()>::new_basic();

    app.use_middleware("/", m![json_error_handler]);

    app.get("/plaintext", m![plaintext]);
    app.get("/error", m![error]);

    let server = Server::new(app);
    server.build("0.0.0.0", 4321).await;
}

Quick setup without a DB

The easiest way to get started is to just clone the starter kit

> git clone [email protected]:trezm/thruster-starter-kit.git
> cd thruster-starter-kit
> cargo run

The example provides a simple plaintext route, a route with JSON serialization, and the preferred way to organize sub routes using sub apps.

Quick setup with postgres

The easiest way to get started with postgres is to install thruster-cli,

> cargo install thruster-cli

And then to run

> thruster-cli init MyAwesomeProject
> thruster-cli component Users
> thruster-cli migrate

Which will generate everything you need to get started! Note that this requires a running postgres connection and assumes the following connection string is valid:

postgres://postgres@localhost/

This is all configurable and none of it is hidden from the developer. It's like seeing the magic trick and learning how it's done! Check out the docs for thruster-cli here.

Testing

Thruster provides an easy test suite to test your endpoints, simply include the testing module as below:

let mut app = App::<Request, Ctx, ()>::new_basic();

...

app.get("/plaintext", m![plaintext]);

...

let result = testing::get(app, "/plaintext");

assert!(result.body == "Hello, World!");

Make your own middleware modules

Middleware is super easy to make! Simply create a function and export it at a module level. Below, you'll see a piece of middleware that allows profiling of requests:

#[middleware_fn]
async fn profiling'static + Context + Send>(
    mut context: C,
    next: MiddlewareNext,
) -> MiddlewareResult {
    let start_time = Instant::now();

    context = next(context).await?;

    let elapsed_time = start_time.elapsed();
    info!("[{}μs] {}", elapsed_time.as_micros(), context.route());

    Ok(context)
}

You might find that you want to allow for more specific data stored on the context, for example, perhaps you want to be able to hydrate query parameters into a hashmap for later use by other middlewares. In order to do this, you can create an additional trait for the context that middlewares downstream must adhere to. Check out the provided query_params middleware for an example.

Other, or Custom Backends

Thruster is capable of just providing the routing layer on top of a server of some sort, for example, in the Hyper snippet above. This can be applied broadly to any backend, as long as the server implements ThrusterServer.

use async_trait::async_trait;

#[async_trait]
pub trait ThrusterServer {
    type Context: Context + Send;
    type Response: Send;
    type Request: RequestWithParams + Send;

    fn new(App<Self::Request, Self::Context>) -> Self;
    async fn build(self, host: &str, port: u16);
}

There needs to be:

  • An easy way to create a server.
  • A function to build the server into a future that could be loaded into an async runtime.

Within the build function, the server implementation should:

  • Start up some sort of listener for connections
  • Call let matched = app.resolve_from_method_and_path(, ); (This is providing the actual routing.)
  • Call app.resolve(, matched) (This runs the chained middleware.)

Using cargo generate

Note: This hasn't yet been updated for the latest version of thruster

If you have cargo generate installed, you can simply run the cargo generator

cargo generate --git https://github.com/ami44/thruster-basic-template.git --name myproject
Comments
  • Serving of moderate size assets > 1MiB super slow

    Serving of moderate size assets > 1MiB super slow

    As the title says responses with significant size take a lot of time such that i can't get more than 300 requests per second for a 1MiB image that is cached in ram.

    opened by xacrimon 17
  • How to set CORS with thruster?

    How to set CORS with thruster?

    Hi @trezm I run a thruster-socketio server, need to set some special domains, but I didn't find any examples to show how to set CORS. May I know how to set CORS with Thruster?

    Thanks a lot.

        use thruster::middleware::cors::cors;
        ...
        app.use_middleware("/", async_middleware!(Ctx, [cors]));
        ...
    
    opened by rts-gordon 14
  • Application State

    Application State

    Are there plans to allow storing application state in some form? Like an R2D2 connection manager that can be used within routes to retrieve a database session?

    opened by inzanez 8
  • feat: Add better error handling [#108]

    feat: Add better error handling [#108]

    Adds better error handling via a new macro -- map_try.

    Error handling in Thruster at the moment is painful to say the least. It usually involves multiple levels of error handling and far too much indentation, or it involves layers of enums and implementations of contexts.

    Ideally, we'd be able to simply have the solution:

    async fn endpoint(context: BasicContext, next: MiddlewareNext<BasicContext>) -> Result<Ctx, ThrusterError> {
      let s = some_call()?;
    
      context.body(s);
    
      Ok(context)
    }
    

    However, in order for the error to be properly mapped down the line, the resulting calls to next need access to a context, as the context they were supplied with as an argument is moved when next(context) is called. This means we need a thruster specific error, ThrusterError, that contains a context. Naively we would think that this should work:

    async fn endpoint(context: BasicContext, next: MiddlewareNext<BasicContext>) -> Result<Ctx, ThrusterError> {
      let s = some_call()
        .map_err(|_| {
          Error {
            context,
            message: "Parsing failure!".to_string(),
            status: 400
          }
        })?;
    
      context.body(s);
    
      Ok(context)
    }
    

    However, the compiler isn't clever enough to see that if map_err is called, then context.body is not thanks to the ? operator.

    If we are explicit about this using a match, like the expansion of try!, however, the compiler sees the code paths and is able to adjust accordingly. This PR adds map_try!, which does just that and allows for a mapping block to correctly convert the error type.

    async fn endpoint(context: BasicContext, next: MiddlewareNext<BasicContext>) -> Result<Ctx, ThrusterError> {
      let res = "Hello, world".parse::<u32>();
      let non_existent_param = map_try!(res, Err(_) => {
          Error {
            context,
            message: "Parsing failure!".to_string(),
            status: 400
          }
        }
      );
    
      context.body(&format!("{}", non_existent_param));
    
      Ok(context)
    }
    

    Full example:

    extern crate thruster;
    
    use thruster::{MiddlewareNext, MiddlewareReturnValue, MiddlewareResult};
    use thruster::{App, BasicContext as Ctx, Request, map_try};
    use thruster::server::Server;
    use thruster::errors::ThrusterError as Error;
    use thruster::ThrusterServer;
    use thruster::thruster_proc::{async_middleware, middleware_fn};
    
    async fn plaintext(mut context: Ctx, _next: MiddlewareNext<Ctx>) -> MiddlewareResult<Ctx> {
      let val = "Hello, World!";
      context.body(val);
      Ok(context)
    }
    
    async fn error(mut context: Ctx, _next: MiddlewareNext<Ctx>) -> MiddlewareResult<Ctx> {
      let res = "Hello, world".parse::<u32>();
      let non_existent_param = map_try!(res, Err(_) => {
          Error {
            context,
            message: "Parsing failure!".to_string(),
            status: 400
          }
        }
      );
    
      context.body(&format!("{}", non_existent_param));
    
      Ok(context)
    }
    
    async fn json_error_handler(context: Ctx, next: MiddlewareNext<Ctx>) -> MiddlewareResult<Ctx> {
      let res = await!(next(context));
    
      let ctx = match res {
        Ok(val) => val,
        Err(e) => {
          let mut context = e.context;
          context.body(&format!("{{\"message\": \"{}\",\"success\":false}}", e.message));
          context.status(e.status);
          context
        }
      };
    
      Ok(ctx)
    }
    
    fn main() {
      println!("Starting server...");
    
      let mut app = App::<Request, Ctx>::new_basic();
    
      app.use_middleware("/", async_middleware!(Ctx, [json_error_handler]));
    
      app.get("/plaintext", async_middleware!(Ctx, [plaintext]));
      app.get("/error", async_middleware!(Ctx, [error]));
    
      let server = Server::new(app);
      server.start("0.0.0.0", 4321);
    }
    

    Delivers [#108]

    opened by trezm 8
  • A few usage questions

    A few usage questions

    Hello and thanks for working on Thruster! I have been experimenting with various Rust web frameworks over the past few days to potentially replace my usage of Rocket. So far Thruster has been one of the more promising candidates. I love the simplicity of the API and how easy it is to create, manipulate and pass around the App type.

    I have a few questions on how to use the framework correctly:

    • Is the best/only way to serve static files to write a middleware which loads the entire file in memory and calls context.body(entire_file_content)? This seems very inefficient if that is the case :(
    • Also on the subject of serving static files, how would you recommend matching the trailing portion of a route? For example, let's say I want to make all URL starting with /swagger to serve the corresponding files in a ./docs directory on disk. For instance, hitting /swagger/img/logo.png should serve /docs/img/logo.png
    • When using App::create, it would be very useful if it was possible to pass in a closure as the generate_context argument. As it stands, I am not sure how to shove any data that is determined during application startup into the context objects. EDIT: I guess this is the answer: https://github.com/trezm/Thruster/issues/130

    Many thanks in advance!

    opened by agersant 7
  • Example error handling

    Example error handling

    To help with complex error handling on ThrusterError I added some convenience methods for downcasting the cause.

    An additional proposal is to implement StdError for ThrusterError with fn cause returning the cause.

    Thoughts?

    opened by kjvalencik 7
  • Alias ideas

    Alias ideas

    Hey,

    Here's a small collection of alias ideas that I find to be fitting.

    Ordered from best to worst, IMO.

    use_sub_app

    • nest
    • app
    • sub

    use_middleware

    • middleware
    • with
    • mid

    I might come up with some more alias ideas soon 👍

    opened by ynuwenhof 6
  • Using unix domain socket

    Using unix domain socket

    Hello, is there any way to use thruster with unix domain sockets? If they is no way to do that now, I wonder if is possible to add a method .build_from_incoming which use hyper::Server::builder instead hyper::Server::bind for create the underlying hyper::Server

    or maybe just a new type of server thruster::UsdHyperServer which impl the ThrusterServer trait but ignoring the port argument, like this:

    use thruster::{
        context::basic_hyper_context::{
            generate_context, BasicHyperContext as Ctx, HyperRequest,
        },
        async_middleware, middleware_fn,
        App, Context, ThrusterServer,
        MiddlewareNext, MiddlewareResult,
    };
    
    use hyper::{
        service::{make_service_fn, service_fn},
        Body, Request, Response, Server,
        server::accept,
    };
    
    use std::sync::Arc;
    use async_trait::async_trait;
    use tokio::net::UnixListener;
    
    pub struct UdsHyperServer<T: 'static + Context + Send> {
        app: App<HyperRequest, T>,
    }
    
    impl<T: 'static + Context + Send> UdsHyperServer<T> { }
    
    #[async_trait]
    impl<T: Context<Response = Response<Body>> + Send> ThrusterServer for UdsHyperServer<T> {
        type Context = T;
        type Response = Response<Body>;
        type Request = HyperRequest;
    
        fn new(app: App<Self::Request, T>) -> Self {
            UdsHyperServer { app }
        }
    
        async fn build(mut self, path: &str, _port: u16) {
            self.app._route_parser.optimize();
    
            let arc_app = Arc::new(self.app);
    
            async move {
                let service = make_service_fn(|_| {
                    let app = arc_app.clone();
                    async {
                        Ok::<_, hyper::Error>(service_fn(move |req: Request<Body>| {
                            let matched = app.resolve_from_method_and_path(
                                &req.method().to_string(),
                                &req.uri().to_string(),
                            );
    
                            let req = HyperRequest::new(req);
                            app.resolve(req, matched)
                        }))
                    }
                });
    
                let mut listener = UnixListener::bind(path).unwrap();
                let incoming = listener.incoming();
                let incoming = accept::from_stream(incoming);
    
                let server = Server::builder(incoming).serve(service);
    
                server.await?;
    
                Ok::<_, hyper::Error>(())
            }
            .await
            .expect("hyper server failed");
        }
    }
    
    #[middleware_fn]
    async fn plaintext(mut context: Ctx, _next: MiddlewareNext<Ctx>) -> MiddlewareResult<Ctx> {
        let val = "Hello, World!";
        context.body(val);
        Ok(context)
    }
    
    fn main() {
        println!("Starting server...");
    
        let mut app = App::<HyperRequest, Ctx>::create(generate_context);
    
        app.get("/plaintext", async_middleware!(Ctx, [plaintext]));
    
        let server = UdsHyperServer::new(app);
        server.start("/tmp/thruster.sock", 4321);
    
        // test the server with the following command:
        // curl --unix-socket /tmp/thruster.sock http://host/plaintext
    }
    
    
    opened by encendre 6
  • Improve Thruster Server struct performance

    Improve Thruster Server struct performance

    Would love to get the home-grown implementation of an http encoder/decoder more in line with hyper's perf.

    For perf focused users, you can now easily use Hyper as the backend, but it would be nice to be on level playing fields in the future.

    opened by trezm 6
  • [feature request] Make context.set(header_key, header_value) available to set header

    [feature request] Make context.set(header_key, header_value) available to set header

    In several places of the documentation and examples, it mentions the use of context.set. i.e.:

    https://github.com/thruster-rs/Thruster/blob/d80cf36ca3f8f40324dc5325a3c150aa5c833953/thruster/examples/custom_cors.rs#L39-L50

    But when inspecting the types shows that set is not in the public API: https://github.com/thruster-rs/Thruster/blob/d80cf36ca3f8f40324dc5325a3c150aa5c833953/thruster/src/context/basic_context.rs#L191-L193

    (the same in all possible contexts)

    How can I set the headers without it? Or can this be in the public API?

    Use cases

    My specific usecase is to implement a middleware like helmet.js or csrf. I need to Remove certain headers, modify others, and create new ones.

    What I tried

    use hyper::header;
    use thruster::context::basic_hyper_context::BasicHyperContext as Ctx;
    use thruster::{middleware, MiddlewareNext, MiddlewareResult};
    
    #[middleware]
    pub async fn helmet(mut context: Ctx, next: MiddlewareNext<Ctx>) -> MiddlewareResult<Ctx> {
        match &context.hyper_request {
            Some(hyper_request) => {
                let mut headers = hyper_request.request.headers().to_owned();
    
                headers.remove(header::SERVER); // X-Powered-By or X-AspNet-Version are not used on thruster
                headers.append(
                    header::CONTENT_SECURITY_POLICY,
                    "default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors \
                     'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src \
                     'self' https: 'unsafe-inline';upgrade-insecure-requests"
                        .parse()
                        .unwrap(),
                );
            }
            None => panic!("Problem when setting helmet headers."),
        }
        // context.set(some_key, some_value) <~ error here
        context = next(context).await?;
    
        Ok(context)
    }
    

    Error output

    image

    My PC

    # Some info of my system
    Linux Pop_OS! 22.10 Nvidia, x86_64, linux 5.19.0, bash
    # Rust Version running
    rustc 1.65.0-nightly
    # in my Cargo.toml
    thruster = { version = "1.2.4", features = ["hyper_server"]}
    
    opened by Israel-Laguan 5
  • Proposal: Using traits instead of static fn for middleware chains

    Proposal: Using traits instead of static fn for middleware chains

    RFC:

    I'm proposing moving middleware chains to using traits rather than static fns. It'll make it significantly easier to add objects to chains, rather than creating a new function for each chain item. Moreover, traits can respond dynamically rather than using a static function whose definition can't be changed.

    This is similar to how Nickel.rs does it. You can take a look at that here: https://github.com/nickel-org/nickel.rs/blob/master/src/middleware.rs

    opened by rakshith-ravi 5
  • [REQUEST] Remove Releases and packages from GitHub repos

    [REQUEST] Remove Releases and packages from GitHub repos

    I notice the latest version available is in Crates.io, which differs from the version on the Releases section on GitHub:

    In Crates.io | In GitHub :-- | :-- image | image 1.3.0 | 1.1.14

    This can produce confusion among certain visitors to this repo, as the repo is often considered "the source of truth" as it has the code.

    Proposal

    • Remove the sections "Releases" and "Packages" from GitHub repos
    • Highlight in the Readme that the latest version is in Crates.io
    • Highlight the version on the documentation site Gitbook (OPTIONAL)
    opened by Israel-Laguan 0
Releases(v1.1.14)
  • v1.1.14(Mar 15, 2022)

    What's Changed

    • bug: Explicitly allow upgrades within hyper server by @trezm in https://github.com/thruster-rs/Thruster/pull/204
    • bug: Fix option to options by @trezm in https://github.com/thruster-rs/Thruster/pull/205
    • bug: Missed an additional option -> options by @trezm in https://github.com/thruster-rs/Thruster/pull/206
    • feat: Middleware alias for middleware_fn by @ynuwenhof in https://github.com/thruster-rs/Thruster/pull/207
    • chore: Minor README issues by @ynuwenhof in https://github.com/thruster-rs/Thruster/pull/208
    • feat: Consuming app builder pattern by @ynuwenhof in https://github.com/thruster-rs/Thruster/pull/210
    • bug: Add default status codes by @trezm in https://github.com/thruster-rs/Thruster/pull/211
    • chore: Bump version by @trezm in https://github.com/thruster-rs/Thruster/pull/212

    New Contributors

    • @ynuwenhof made their first contribution in https://github.com/thruster-rs/Thruster/pull/207

    Full Changelog: https://github.com/thruster-rs/Thruster/compare/v1.1.11...v1.1.14

    Source code(tar.gz)
    Source code(zip)
  • v1.1.11(Dec 4, 2021)

    A small release, simply adds a mitigation for slowloris attacks (via connection timeouts) and adds information about Jab dependency injection library.

    Source code(tar.gz)
    Source code(zip)
  • v1.1.10(Sep 18, 2021)

    • Adds strict mode, i.e. the ability to strictly distinguish between routes like /a and /a/. This behavior is disabled by default.
    • Adds the actix-web backend server
    • Update the readme a bit ;)
    Source code(tar.gz)
    Source code(zip)
  • v1.1.9(Jun 23, 2021)

    Main changes in this were to remove Sync requirements from futures. Also fixes many of the servers that were broken but hidden behind feature flags.

    Source code(tar.gz)
    Source code(zip)
  • v1.1.4(Jun 7, 2021)

  • v1.1.3(Jun 7, 2021)

    chore: Update version and make release notes feat: add json and set_status methods for basic context (#185) chore: Add middleware how-to to readme chore: Update readme location (#184)

    Source code(tar.gz)
    Source code(zip)
  • v1.1.2(Jun 5, 2021)

    • Rebuilt entire parser from scratch
    • Rebuilt middleware system from scratch (should be 8% faster now!)
    • Added m! macro to soon replace async_middleware!. They do basically the same thing, except m! doesn't need the context type passed in
    • Upgraded library dependencies
    Source code(tar.gz)
    Source code(zip)
  • v1.0.1(Oct 14, 2020)

    General bug fixes including:

    • Fixing route parameters, which were broken -- eek!
    • Fixing the cookie system to not be so insane
    • Fixing query parameters
    Source code(tar.gz)
    Source code(zip)
  • cargo(Aug 27, 2020)

Owner
null
Sauron is an html web framework for building web-apps. It is heavily inspired by elm.

sauron Guide Sauron is an web framework for creating fast and interactive client side web application, as well as server-side rendering for back-end w

Jovansonlee Cesar 1.7k Dec 26, 2022
A (flash) message framework for actix-web. A port to Rust of Django's message framework.

actix-web-flash-messages Flash messages for actix-web Web applications sometimes need to show a one-time notification to the user - e.g. an error mess

Luca Palmieri 31 Dec 29, 2022
Seed is a Rust front-end framework for creating fast and reliable web apps with an Elm-like architecture.

Seed is a Rust front-end framework for creating fast and reliable web apps with an Elm-like architecture.

null 3.6k Jan 6, 2023
Perseus is a blazingly fast frontend web development framework built in Rust with support for major rendering strategies

Perseus is a blazingly fast frontend web development framework built in Rust with support for major rendering strategies, reactivity without a virtual DOM, and extreme customizability

arctic_hen7 1.2k Jan 8, 2023
Super Fast & High Performance minimalist web framework for rust

Super Fast & High Performance minimalist web framework for rust

null 6 Oct 12, 2022
Ergonomic and modular web framework built with Tokio, Tower, and Hyper

axum axum is a web application framework that focuses on ergonomics and modularity. More information about this crate can be found in the crate docume

Tokio 7.9k Dec 31, 2022
A rust web framework with safety and speed in mind.

darpi A web api framework with speed and safety in mind. One of the big goals is to catch all errors at compile time, if possible. The framework uses

null 32 Apr 11, 2022
A full-featured and easy-to-use web framework with the Rust programming language.

Poem Framework A program is like a poem, you cannot write a poem without writing it. --- Dijkstra A full-featured and easy-to-use web framework with t

Poem Web 2.2k Jan 6, 2023
Implementation of the RealWorld backend API spec in Actix, Rust's powerful actor system and most fun web framework.

Actix codebase containing real world examples (CRUD, auth, advanced patterns, etc) that adheres to the RealWorld spec and API. ❗ (2021/05/13) This cod

Allen 475 Jan 2, 2023
Demo of Rust and axum web framework

Demo of Rust and axum web framework Demonstration of: Rust: programming language that focuses on reliability and stability. axum: web framework that f

Joel Parker Henderson 115 Dec 29, 2022
The simplest build-time framework for writing web apps with html templates and typescript

Encoped A build-time fast af tool to write static apps with html and TypeScript Features Template-based ESLint, Prettier and Rollup integration No ext

null 1 Dec 11, 2021
Hirola is an opinionated web framework for that is focused on simplicity and predictability.

Hirola Hirola is an opinionated web framework for that is focused on simplicity and predictability. Goals Keep it simple. Most Rust web frameworks hav

null 27 Nov 3, 2022
Starter template for use with the Leptos web framework and Axum.

Leptos Axum Starter Template This is a template for use with the Leptos web framework and the cargo-leptos tool using Axum. Creating your template rep

Leptos 10 Mar 4, 2023
axum-serde is a library that provides multiple serde-based extractors and responders for the Axum web framework.

axum-serde ?? Overview axum-serde is a library that provides multiple serde-based extractors / responses for the Axum web framework. It also offers a

GengTeng 3 Dec 12, 2023
Hot reload static web server for deploying mutiple static web site with version control.

SPA-SERVER It is to provide a static web http server with cache and hot reload. 中文 README Feature Built with Hyper and Warp, fast and small! SSL with

null 7 Dec 18, 2022
Code template for a production Web Application using Axum: The AwesomeApp Blueprint for Professional Web Development.

AwesomeApp rust-web-app More info at: https://awesomeapp.dev/rust-web-app/ rust-web-app YouTube episodes: Episode 01 - Rust Web App - Course to Produc

null 45 Sep 6, 2023
A highly customizable, full scale web backend for web-rwkv, built on axum with websocket protocol.

web-rwkv-axum A axum web backend for web-rwkv, built on websocket. Supports BNF-constrained grammar, CFG sampling, etc., all streamed over network. St

Li Junyu 12 Sep 25, 2023
A Rust web framework

cargonauts - a Rust web framework Documentation cargonauts is a Rust web framework intended for building maintainable, well-factored web apps. This pr

null 179 Dec 25, 2022
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.4k Jan 4, 2023