Есть ли способ сделать проверку как часть фильтра в Warp? - PullRequest
1 голос
/ 06 марта 2020

У меня есть маршрут и определена функция конечной точки. Я также ввел некоторые зависимости.

pub fn route1() -> BoxedFilter<(String, ParamType)> {
    warp::get()
        .and(warp::path::param())
        .and(warp::filters::query::query())
        .and(warp::path::end())
        .boxed()
}

pub async fn handler1(
    query: String,
    param: ParamType,
    dependency: DependencyType,
) -> Result<impl warp::Reply, warp::Rejection> {
}
let api = api::routes::route1()
    .and(warp::any().map(move || dependency))
    .and_then(api::hanlders::hander1);

Кажется, все работает нормально.

Однако я хочу иметь возможность иметь что-то, что находится перед несколькими конечными точками который проверяет действительный ключ в параметре запроса. Внутри handler1 я могу добавить:

if !param.key_valid {
    return Ok(warp::reply::with_status(
        warp::reply::json(&""),
        StatusCode::BAD_REQUEST,
    ));
}

Я не хочу добавлять это к каждому обработчику индивидуально.

Кажется, я должен быть в состоянии сделать это через filter, но я не могу понять это. Я попытался использовать .map(), но затем, возвращая несколько элементов, сдвигает его в кортеж, и мне приходится менять сигнатуру функции нижестоящего элемента. В идеале я хочу найти способ добавить проверки или другие фильтры, которые могут отклонить запрос без каких-либо нижестоящих значений о них.

1 Ответ

2 голосов
/ 11 марта 2020

Это эффективно демонстрируется примером отклонения деформации :

Отклонения представляют случаи, когда фильтр не должен продолжать обработку запроса, но другой фильтр может обработайте его.

Извлеките знаменатель из заголовка div-by или отклоните с помощью DivideByZero.

Вам необходимо

  1. Используйте Filter::and_then, чтобы взять существующий фильтр (в данном случае query()) и выполнить проверку. Если проверка не удалась, верните пользовательский отказ.
  2. Используйте Filter::recover для надлежащей обработки пользовательского отказа и любых других возможных ошибок.

Применимо к вашему Ситуация:

use serde::Deserialize;
use std::{convert::Infallible, net::IpAddr};
use warp::{filters::BoxedFilter, http::StatusCode, reject::Reject, Filter, Rejection, Reply};

fn route1() -> BoxedFilter<(String, ParamType)> {
    warp::get()
        .and(warp::path::param())
        .and(validated_query())
        .and(warp::path::end())
        .boxed()
}

#[derive(Debug)]
struct Invalid;
impl Reject for Invalid {}

fn validated_query() -> impl Filter<Extract = (ParamType,), Error = Rejection> + Copy {
    warp::filters::query::query().and_then(|param: ParamType| async move {
        if param.valid {
            Ok(param)
        } else {
            Err(warp::reject::custom(Invalid))
        }
    })
}

async fn report_invalid(r: Rejection) -> Result<impl Reply, Infallible> {
    let reply = warp::reply::reply();

    if let Some(Invalid) = r.find() {
        Ok(warp::reply::with_status(reply, StatusCode::BAD_REQUEST))
    } else {
        // Do better error handling here
        Ok(warp::reply::with_status(
            reply,
            StatusCode::INTERNAL_SERVER_ERROR,
        ))
    }
}

async fn handler1(
    _query: String,
    _param: ParamType,
    _dependency: DependencyType,
) -> Result<impl warp::Reply, warp::Rejection> {
    Ok(warp::reply::reply())
}

struct DependencyType;

#[derive(Deserialize)]
struct ParamType {
    valid: bool,
}

#[tokio::main]
async fn main() {
    let api = route1()
        .and(warp::any().map(move || DependencyType))
        .and_then(handler1)
        .recover(report_invalid);

    let ip: IpAddr = "127.0.0.1".parse().unwrap();
    let port = 8888;
    warp::serve(api).run((ip, port)).await;
}

И вывод curl с нерелевантными строками убран:

% curl -v '127.0.0.1:8888/dummy/?valid=false'
< HTTP/1.1 400 Bad Request

% curl -v '127.0.0.1:8888/dummy/?valid=true'
< HTTP/1.1 200 OK

Car go .toml

[dependencies]
warp = "0.2.2"
serde = { version = "1.0.104", features = ["derive"] }
tokio = { version = "0.2.13", features = ["full"] }
...