Crate rweb

Source
Expand description

A macro to convert a function to rweb handler.

All parameters should satisfy one of the following.

  • Has a path parameter with same name.
  • Annotated with the annotations documented below.
  • Has a type which implements FromRequest.

§Path parmeters

§Attributes on function item

§#[header("content-type", "application/json")]

Make a route matches only if value of the header matches provided value.

use rweb::*;

#[get("/")]
#[header("accept", "*/*")]
fn routes() -> &'static str {
   "This route matches only if accept header is '*/*'"
}

fn main() {
    serve(routes());
}

§#[cors]

use rweb::*;

#[get("/")]
#[cors(origins("example.com"), max_age = 600)]
fn cors_1() -> String {
   unreachable!()
}

#[get("/")]
#[cors(origins("example.com"), methods(get), max_age = 600)]
fn cors_2() -> String {
   unreachable!()
}

#[get("/")]
#[cors(origins("*"), methods(get), max_age = 600)]
fn cors_3() -> String {
   unreachable!()
}

#[get("/")]
#[cors(
    origins("*"),
    methods(get, post, patch, delete),
    headers("accept"),
    max_age = 600
)]
fn cors_4() -> String {
   unreachable!()
}

§#[body_size(max = "8192")]

use rweb::*;

#[get("/")]
#[body_size(max = "8192")]
fn body_size() -> String {
   unreachable!()
}

§Attributes on parameters

§#[body]

Parses request body. Type is bytes::Bytes.

use rweb::*;
use http::Error;
use bytes::Bytes;

#[post("/body")]
fn body(#[body] body: Bytes) -> Result<String, Error> {
   let _ = body;
   Ok(String::new())
}

fn main() {
    serve(body());
}

§#[form]

Parses request body. Content-Type should be x-www-form-urlencoded.

use rweb::*;
use serde::Deserialize;

#[derive(Deserialize)]
struct LoginForm {
    id: String,
    password: String,
}

#[post("/form")]
fn form(#[form] body: LoginForm) -> String {
   String::from("Ok")
}

fn main() {
    serve(form());
}

§#[json]

Parses request body. Content-Type should be application/json.

use rweb::*;
use serde::Deserialize;

#[derive(Deserialize)]
struct LoginForm {
    id: String,
    password: String,
}

#[post("/json")]
fn json(#[json] body: LoginForm) -> String {
    String::from("Ok")
}

fn main() {
    serve(json());
}

Note that you can mix the order of parameters.

use rweb::*;
use serde::Deserialize;

#[derive(Deserialize)]
struct LoginForm {
    id: String,
    password: String,
}

#[get("/param/{a}/{b}")]
fn body_between_path_params(a: u32, #[json] body: LoginForm, b: u32) ->
String {     assert_eq!(body.id, "TEST_ID");
    assert_eq!(body.password, "TEST_PASSWORD");
    (a + b).to_string()
}

fn main() {
    serve(body_between_path_params());
}

§#[query]

Parses query string.

use rweb::*;

#[get("/")]
fn use_query(#[query] qs: String) -> String {
    qs
}

fn main() {
    serve(use_query());
}

§#[header = "header-name"]

Value of the header.

use rweb::*;

#[get("/")]
fn ret_accept(#[header = "accept"] accept: String) -> String {
    accept
}
fn main() {
    serve(ret_accept());
}

Value of the header.

use rweb::*;

#[get("/")]
fn cookie(#[header = "sess"] sess_id: String) -> String {
    sess_id
}
fn main() {
    serve(cookie());
}

§#[filter = "path_to_fn"]

Calls function.

Note: If the callee returns (), you should use () as type. (Type alias is not allowed)

use std::num::NonZeroU16;
use rweb::*;
use serde::Serialize;

#[derive(Serialize)]
struct Math {
    op: String,
    output: u16,
}

#[get("/math/{num}")]
fn math(num: u16, #[filter = "div_by"] denom: NonZeroU16) -> impl Reply {
    rweb::reply::json(&Math {
        op: format!("{} / {}", num, denom),
        output: num / denom.get(),
    })
}

fn div_by() -> impl Filter<Extract = (NonZeroU16,), Error = Rejection> +Copy
{    rweb::header::<u16>("div-by").and_then(|n: u16| async move {
       if let Some(denom) = NonZeroU16::new(n) {
           Ok(denom)
       } else {
           Err(reject::custom(DivideByZero))
       }
   })
}

#[derive(Debug)]
struct DivideByZero;

impl reject::Reject for DivideByZero {}

fn main() {
    serve(math());
}

§#[data]

use futures::lock::Mutex;
use rweb::*;
use std::sync::Arc;

#[derive(Clone, Default)]
struct Db {
   items: Arc<Mutex<Vec<String>>>,
}

#[get("/")]
async fn index(#[data] db: Db) -> Result<String, Rejection> {
   let items = db.items.lock().await;

   Ok(items.len().to_string())
}

fn main() {
    let db = Default::default();
    serve(index(db));
}

§FromRequest

use http::StatusCode;
use rweb::{filters::BoxedFilter, *};

impl FromRequest for User {
   type Filter = BoxedFilter<(User,)>;

   fn new() -> Self::Filter {
       // In real world, you can use a header like Authorization
       header::<String>("x-user-id").map(|id| User { id }).boxed()
   }
}


#[derive(Schema)]
struct User {
   id: String,
}

#[get("/")]
fn index(user: User) -> String {
   user.id
}

fn main() {
    serve(index());
}

§Guards

use rweb::*;

// This handler is invoked only if x-appengine-cron matches 1 (case insensitive).
#[get("/")]
#[header("X-AppEngine-Cron", "1")]
fn gae_cron() -> String {
    String::new()
}

§#[router]

#[router] can be used to group routes.

§#[data]

You can use #[data] with a router.

use rweb::*;

#[derive(Default, Clone)]
struct Db {}

#[get("/use")]
fn use_db(#[data] _db: Db) -> String {
   String::new()
}

#[router("/data", services(use_db))]
fn data_param(#[data] db: Db) {}

§Guard

use rweb::*;

#[get("/")]
fn admin_index() -> String {
   String::new()
}

#[get("/users")]
fn admin_users() -> String {
   String::new()
}

#[router("/admin", services(admin_index, admin_users))]
#[header("X-User-Admin", "1")]
fn admin() {}

Re-exports§

Modules§

Macros§

  • Convenient way to chain multiple path filters together.
  • Helper macro to chain multiple routes with .or(route()) between them.

Structs§

  • Errors that can happen inside warp.
  • Represents a request body with www-url-form-encoded content type.
  • Represents request body or response.
  • Represents all query parameters.
  • Rejection of a request by a Filter.
  • A Warp Server ready to filter requests.
  • A Warp Server ready to filter requests over TLS.

Traits§

  • Read bytes from a buffer.
  • Composable request filters.
  • A future represents an asynchronous computation obtained by use of async.
  • Types that can be converted into a Response.
  • A Sink is a value into which other values can be sent, asynchronously.
  • A stream of values produced asynchronously.

Functions§

  • A filter that matches any route.
  • Creates a Filter that requires a cookie by name.
  • Create a wrapping filter that exposes CORS behavior for a wrapped filter.
  • Create a Filter that requires the request method to be DELETE.
  • Create a Filter that requires the request method to be GET.
  • Create a Filter that requires the request method to be HEAD.
  • Create a Filter that tries to parse the specified header.
  • Create a wrapping filter with the specified name as the target.
  • Extract the Method from the request.
  • Create a Filter that requires the request method to be OPTIONS.
  • Create a Filter that requires the request method to be PATCH.
  • Create an exact match path segment Filter.
  • Create a Filter that requires the request method to be POST.
  • Create a Filter that requires the request method to be PUT.
  • Creates a Filter that decodes query parameters to the type T.
  • A simple 301 permanent redirect to a different location.
  • Rejects a request with 404 Not Found.
  • Returns an empty Reply with status code 200 OK.
  • Create a Server with the provided Filter.
  • Convert a Filter into a Service.
  • Create a wrapping filter that instruments every request with a custom tracing Span provided by a function.
  • Function that receives a filter to be combined with pre and after filters
  • Creates a Websocket Filter.

Attribute Macros§

Derive Macros§

  • Implements Entity for the type.