Я пытаюсь начать работу с деформацией и тестирую проверку ключа API. Следующий код работает, но это неприятно. Функция проверки извлекает ключ из заголовка. После успешной проверки ключ больше не используется, но функция handle_request должна иметь для него входной параметр.
Не могли бы вы посоветовать, как избежать этого нежелательного входного параметра и более чистого подхода к проверке ключей API с помощью деформации?
Заранее спасибо!
use std::convert::Infallible;
use std::error::Error;
use serde::{Deserialize, Serialize};
use warp::http::{Response, StatusCode};
use warp::{reject, Filter, Rejection, Reply};
//use futures::future;
// use headers::{Header, HeaderMapExt};
// use http::header::HeaderValue;
// use http::HeaderMap;
extern crate pretty_env_logger;
#[macro_use] extern crate log;
#[derive(Deserialize, Serialize)]
struct Params {
key1: String,
key2: u32,
}
#[derive(Debug)]
struct Unauthorized;
impl reject::Reject for Unauthorized {}
#[tokio::main]
async fn main() {
pretty_env_logger::init();
// get /exampel?key1=value&key2=42
let route1 = warp::get().and(key_validation())
.and(warp::query::<Params>())
.and_then(handle_request);
let routes = route1.recover(handle_rejection);
warp::serve(routes)
.run(([127, 0, 0, 1], 3030))
.await;
}
async fn handle_request(api_key:String, params: Params) -> Result<impl warp::Reply, warp::Rejection> {
Ok(Response::builder().body(format!("key1 = {}, key2 = {}", params.key1, params.key2)))
}
fn key_validation() -> impl Filter<Extract = (String,), Error = Rejection> + Copy {
warp::header::<String>("x-api-key").and_then(|n: String| async move {
if n == "test" {
Ok(n)
} else {
Err(reject::custom(Unauthorized))
}
})
}
// JSON replies
/// An API error serializable to JSON.
#[derive(Serialize)]
struct ErrorMessage {
code: u16,
message: String,
}
// This function receives a `Rejection` and tries to return a custom
// value, otherwise simply passes the rejection along.
async fn handle_rejection(err: Rejection) -> Result<impl Reply, Infallible> {
let code;
let message;
if err.is_not_found() {
code = StatusCode::NOT_FOUND;
message = "NOT_FOUND";
} else if let Some(Unauthorized) = err.find() {
code = StatusCode::UNAUTHORIZED;
message = "Invalide API key";
} else if let Some(_) = err.find::<warp::reject::MethodNotAllowed>() {
// We can handle a specific error, here METHOD_NOT_ALLOWED,
// and render it however we want
code = StatusCode::METHOD_NOT_ALLOWED;
message = "METHOD_NOT_ALLOWED";
} else {
// We should have expected this... Just log and say its a 500
error!("unhandled rejection: {:?}", err);
code = StatusCode::INTERNAL_SERVER_ERROR;
message = "UNHANDLED_REJECTION";
}
let json = warp::reply::json(&ErrorMessage {
code: code.as_u16(),
message: message.into(),
});
Ok(warp::reply::with_status(json, code))
}
Обновление: когда я пытаюсь избежать извлечения некоторых файлов с помощью функции key_validation, я получаю следующую ошибку:
error[E0271]: type mismatch resolving `<warp::filter::and_then::AndThen<impl warp::Filter+Copy, [closure@src/main.rs:44:50: 50:6]> as warp::filter::FilterBase>::Extract == ()`
--> src/main.rs:43:24
|
43 | fn key_validation() -> impl Filter<Extract = (), Error = Rejection> + Copy {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found `()`
|
= note: expected tuple `(_,)`
found unit type `()`
Чтобы исправить это, я попробовал:
async fn handle_request(params: Params) -> Result<impl warp::Reply, warp::Rejection> {
Ok(Response::builder().body(format!("key1 = {}, key2 = {}", params.key1, params.key2)))
}
fn key_validation() -> impl Filter<Extract = ((),), Error = Rejection> + Copy {
warp::header::<String>("x-api-key").and_then(|n: String| async move {
if n == "test" {
Ok(())
} else {
Err(reject::custom(Unauthorized))
}
})
}
что приводит к этому:
error[E0593]: function is expected to take 2 arguments, but it takes 1 argument
--> src/main.rs:31:19
|
31 | .and_then(handle_request);
| ^^^^^^^^^^^^^^ expected function that takes 2 arguments
...
39 | async fn handle_request(params: Params) -> Result<impl warp::Reply, warp::Rejection> {
| ------------------------------------------------------------------------------------ takes 1 argument
|
= note: required because of the requirements on the impl of `warp::generic::Func<((), Params)>` for `fn(Params) -> impl Future {handle_request}`
это используемые зависимости:
[dependencies]
log = "0.4"
pretty_env_logger = "0.4"
tokio = { version = "1", features = ["full"] }
warp = "0.3"
serde = { version = "1.0", features = ["derive"] }
futures = { version = "0.3", default-features = false, features = ["alloc"] }