Expand description
Amiya is a experimental middleware-based minimalism async HTTP server framework,
built up on smol-rs related asynchronous components.
It’s currently still working in progress and in a very early alpha stage.
API design may changes every day, DO NOT use it in any condition except for test or study!
§Goal
The goal of this project is try to build a (by importance order):
- Safe, with
#![forbid(unsafe_code)] - Async
- Middleware-based
- Minimalism
- Easy to use
- Easy to extend
HTTP framework for myself to write simple web services.
Amiya uses async-h1 to parse and process requests, so only HTTP version 1.1 is supported for
now. HTTP 1.0 or 2.0 is not in goal list, at least in the near future.
Performance is NOT in the list too, after all, Amiya is just a experimental for now, it uses
many heap alloc (Box) and dynamic dispatch (Trait Object) so there may be some performance loss
compare to use async-h1 directly.
§Concepts
To understand how this framework works, there are some concept need to be described first.
§Request, Response and the process pipeline
For every HTTP request comes to a Amiya server, the framework will create a Request struct
to represent it. It’s immutable in the whole request process pipeline.
And a Response is created at the same time. It’s a normal 200 OK empty header empty body
response at first, but it’s mutable and can be edit by middleware.
After all middleware has been executed, the Response maybe edited by many middleware, and
as the final result we will send to the client.
§Middleware
For ease of understanding, you can think this word is a abbreviation of “A function read
some property of Request and edit Response” or, a request handler, for now.
§Context
But middleware do not works on Request and Response directly. Context wraps the
immutable Request and mutable Response with some other information and shortcut
methods.
§Onion model
The execution process of middleware uses the onion model:

We reuse this famous picture from Python’s Pylons framework.
If we add middleware A, B and C to Amiya server, the running order(if not interrupted in the middle) will be: A -> B -> C -> C -> B -> A
So every middleware will be executed twice, but this does not mean same code is executed twice.
That’s why next method exists.
§next
The most important method Context gives us is next.
When a middleware calls ctx.next().await, the method will return after all inner middleware
finish, or, some of them returns a Error.
there is a simplest example:
use amiya::{Context, Result, m};
async fn a(mut ctx: Context<'_, ()>) -> Result {
println!("A - before");
ctx.next().await?;
println!("A - out");
Ok(())
}
async fn b(mut ctx: Context<'_, ()>) -> Result {
println!("B - before");
ctx.next().await?;
println!("B - out");
Ok(())
}
async fn c(mut ctx: Context<'_, ()>) -> Result {
println!("C - before");
ctx.next().await?;
println!("C - out");
Ok(())
}
let amiya = amiya::new().uses(m!(a)).uses(m!(b)).uses(m!(c));When a request in, the output will be:
A - before
B - before
C - before
C - after
B - after
A - afterYou can referrer to examples/middleware.rs for a more meaningful example.
§Middleware, the truth
So with the help of next method, a middleware can not only be a request handler, it can be:
- a error handler, by capture inner middleware returned
Result - a
Router, by looking the path then delegateContextto other corresponding middleware - a access logger or time measurer, by print log before and after the
nextcall - etc…
A middleware even does not have to call next, in that situation no inner middleware will
be executed. Middleware like Router or login state checker can use this mechanism to make
invalid requests respond early.
You can create you own Middleware by implement the trait for your type, or using the m
macro, see their document for detail.
§Examples
To start a very simple HTTP service that returns Hello World to the client in all paths:
use amiya::m;
let app = amiya::new().uses(m!(ctx =>
ctx.resp.set_body(format!("Hello World from: {}", ctx.path()));
));
app.listen("[::]:8080").unwrap();
// ... do other things ...Amiya has a built-in multi-thread async executor powered by async-executor and async-io,
amiya server will run in it. So Amiya::listen do not block your thread.
See Readme - Examples section for more examples to check.
Re-exports§
pub use middleware::Middleware;
Modules§
- middleware
- Built-in middleware.
Macros§
- m
- Writer middleware easily.
Structs§
- Amiya
- Amiya HTTP Server.
- Built
InExecutor - Amiya built-in multi-thread async executor.
- Context
- The context middleware works on.
- Mime
- An IANA media type.
- Request
- An HTTP request.
- Response
- An HTTP response.
Enums§
- Method
- HTTP request methods.
- Status
Code - HTTP response status codes.
Traits§
- Executor
- Provide you custom async executor to Amiya by impl this trait.
Functions§
- new
- Create a
Amiyainstance with extra data type(). - with_ex
- Create a
Amiyainstance with user defined extra data.