logo
pub trait Middleware<E: Endpoint> {
    type Output: Endpoint;
    fn transform(&self, ep: E) -> Self::Output;
}
Expand description

Represents a middleware trait.

Create you own middleware

use poem::{handler, web::Data, Endpoint, EndpointExt, Middleware, Request, Result};

/// A middleware that extract token from HTTP headers.
struct TokenMiddleware;

impl<E: Endpoint> Middleware<E> for TokenMiddleware {
    type Output = TokenMiddlewareImpl<E>;

    fn transform(&self, ep: E) -> Self::Output {
        TokenMiddlewareImpl { ep }
    }
}

/// The new endpoint type generated by the TokenMiddleware.
struct TokenMiddlewareImpl<E> {
    ep: E,
}

const TOKEN_HEADER: &str = "X-Token";

/// Token data
struct Token(String);

#[poem::async_trait]
impl<E: Endpoint> Endpoint for TokenMiddlewareImpl<E> {
    type Output = E::Output;

    async fn call(&self, mut req: Request) -> Result<Self::Output> {
        if let Some(value) = req
            .headers()
            .get(TOKEN_HEADER)
            .and_then(|value| value.to_str().ok())
        {
            // Insert token data to extensions of request.
            let token = value.to_string();
            req.extensions_mut().insert(Token(token));
        }

        // call the next endpoint.
        self.ep.call(req).await
    }
}

#[handler]
async fn index(Data(token): Data<&Token>) -> String {
    token.0.clone()
}

// Use the `TokenMiddleware` middleware to convert the `index` endpoint.
let ep = index.with(TokenMiddleware);

let mut resp = ep
    .call(Request::builder().header(TOKEN_HEADER, "abc").finish())
    .await
    .unwrap();
assert_eq!(resp.take_body().into_string().await.unwrap(), "abc");

Create middleware with functions

use std::sync::Arc;

use poem::{handler, web::Data, Endpoint, EndpointExt, IntoResponse, Request, Result};
const TOKEN_HEADER: &str = "X-Token";

#[handler]
async fn index(Data(token): Data<&Token>) -> String {
    token.0.clone()
}

/// Token data
struct Token(String);

async fn token_middleware<E: Endpoint>(next: E, mut req: Request) -> Result<E::Output> {
    if let Some(value) = req
        .headers()
        .get(TOKEN_HEADER)
        .and_then(|value| value.to_str().ok())
    {
        // Insert token data to extensions of request.
        let token = value.to_string();
        req.extensions_mut().insert(Token(token));
    }

    // call the next endpoint.
    next.call(req).await
}

let ep = index.around(token_middleware);

let mut resp = ep
    .call(Request::builder().header(TOKEN_HEADER, "abc").finish())
    .await
    .unwrap();
assert_eq!(resp.take_body().into_string().await.unwrap(), "abc");

Associated Types

New endpoint type.

If you don’t know what type to use, then you can use BoxEndpoint, which will bring some performance loss, but it is insignificant.

Required methods

Transform the input Endpoint to another one.

Implementations on Foreign Types

Implementors