# Hyper Middleware [![hyper-middleware crate](https://img.shields.io/crates/v/hyper-middleware.svg)](https://crates.io/crates/hyper-middleware) [![Released API docs](https://docs.rs/hyper-middleware/badge.svg)](https://docs.rs/hyper-middleware) [![hyper-middleware crate license](https://img.shields.io/crates/l/hyper-middleware)](./LICENSE-MIT) > A compact HTTP middleware and handler system for [Hyper](https://github.com/hyperium/hyper) `0.14.x`.
> **NOTE:** This crate is still under active development. ## Features - Compact Middleware and Handler System inspired by [The Iron Framework](https://github.com/iron/iron). - Simple [Hyper Service](https://docs.rs/hyper/latest/hyper/service/trait.Service.html) with convenient __Remote Address__ access. - Convenient `Error` and `Result` types powered by [anyhow](https://github.com/dtolnay/anyhow). - `Async` support via [async-trait](https://github.com/dtolnay/async-trait). - Macros to facilitate HTTP response errors or error casting. ## Example [examples/server.rs](examples/server.rs) ```rust use hyper::{header, Server, StatusCode}; use hyper_middleware::{ async_trait, AfterMiddleware, BeforeMiddleware, Body, Error, Handler, Middlewares, Request, Response, Result, Service, }; use std::{net::SocketAddr, path::PathBuf}; struct Config { pub root: PathBuf, } struct Application { opts: Config, } #[async_trait] impl Handler for Application { async fn handle(&self, req: &mut Request) -> Result { // Access the Hyper incoming Request println!("Application::handle() - URI Path: {}", req.uri().path()); // Access the custom app options println!( "Application::handle() - Config Root: {}", self.opts.root.display() ); // Access the Remote Address let remote_addr = req.extensions().get::().unwrap(); println!("Application::handle() - Remote Addr: {}", remote_addr); // Create a Hyper Response and send it back to the middlewares chain Ok(Response::new(Body::from("¡Hola!"))) } } struct FirstMiddleware {} #[async_trait] impl BeforeMiddleware for FirstMiddleware { async fn before(&self, req: &mut Request) -> Result { println!("FirstMiddleware::before()"); // Access the Hyper incoming Request println!("FirstMiddleware::before() - URI Path: {}", req.uri().path()); Ok(()) } async fn catch(&self, _: &mut Request, err: Error) -> Result { Err(err) } } struct SecondMiddleware {} #[async_trait] impl AfterMiddleware for SecondMiddleware { async fn after(&self, _: &mut Request, mut res: Response) -> Result { println!("SecondMiddleware::after()"); // Mutate the Hyper Response at convenience // and send it back to other middlewares on the chain res.headers_mut().insert( header::CONTENT_TYPE, "text/html; charset=utf-8".parse().unwrap(), ); Ok(res) } async fn catch(&self, _: &mut Request, err: Error) -> Result { Ok(Response::builder() .status(StatusCode::NOT_FOUND) .body(Body::from(err.to_string())) .unwrap()) } } #[tokio::main(flavor = "multi_thread")] async fn main() -> Result { // 0. Define some app options (example only) let opts = Config { root: std::env::current_dir().unwrap(), }; // 1. Create a custom middleware chain and plug in some custom middlewares let mut middlewares = Middlewares::new(Application { opts }); middlewares.link_before(FirstMiddleware {}); middlewares.link_after(SecondMiddleware {}); // 2. Create a Hyper service and set the current handler with its middlewares let service = Service::new(middlewares); // 3. Finally just run server using the service already created let addr = ([127, 0, 0, 1], 8787).into(); let server = Server::bind(&addr).serve(service); println!("Listening on http://{}", addr); server.await?; Ok(()) } ``` To run the example just type: ```sh cargo run --example server ``` ## Contributions Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in current work by you, as defined in the Apache-2.0 license, shall be dual licensed as described below, without any additional terms or conditions. Feel free to send some [Pull request](https://github.com/static-web-server/hyper-middleware/pulls) or file an [issue](https://github.com/static-web-server/hyper-middleware/issues). ## License This work is primarily distributed under the terms of both the [MIT license](LICENSE-MIT) and the [Apache License (Version 2.0)](LICENSE-APACHE). © 2022-present [Jose Quintana](https://joseluisq.net)