[−][src]Crate amiya
Amiya is a experimental middleware-based minimalism async HTTP server framework built up on
the smol
async runtime.
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
- 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 propety 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 Nodejs' Koa 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 - after
You can referer 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 catpure inner middleware's return
Result
- a
Router
, by looking the path then delegateContext
to other corresponding middleware - a access logger or time measurer, by print log before and after the
next
call - etc...
A middleware even does not have to call next
, in that statution no inner middlewares will
be executed. Middleware like Router
or login state checker can use this mechanism to make
unprocessable requests responsed 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; fn main() { let app = amiya::new().uses(m!(ctx => ctx.resp.set_body(format!("Hello World from: {}", ctx.path())); )); let fut = app.listen("[::]:8080"); // ... start a async runtime and block on `fut` ... }
You can await or block on this fut
to start the service.
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. |
Context | The context middleware works on. |
Mime | An IANA media type. |
Request | An HTTP request. |
Response | An HTTP response. |
Enums
Method | HTTP request methods. |
StatusCode | HTTP response status codes. |
Functions
new | Create a |
with_ex | Create a |
Type Definitions
Result | The Result type all middleware should returns. |
Attribute Macros
async_trait |