Как мне превратить недопустимые варианты перечисления в None при использовании в качестве параметров запроса в actix-web

#rust #serde #actix-web

#Ржавчина #серде #actix-web

Вопрос:

С примером, приведенным в документации для actix_web::web::Query , как я могу response_type прибегнуть к None при предоставлении неизвестного варианта?

Если у меня есть следующее:

 use actix_web::{web, App, HttpServer};
use serde::Deserialize;

#[derive(Debug, Deserialize)]
pub enum ResponseType {
    Token,
    Code,
}

#[derive(Deserialize)]
pub struct AuthRequest {
    id: u64,
    response_type: Option<ResponseType>,
}

async fn index(web::Query(info): web::Query<AuthRequest>) -> String {
    format!(
        "Authorization request for client with id={} and type={:?}!",
        info.id, info.response_type
    )
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| App::new().route("/", web::get().to(index)))
        .bind(("127.0.0.1", 8080))?
        .run()
        .await
}
 

И я посещаю http://localhost:8080/?id=1amp;response_type=foo , я получаю этот 400- й ответ:

Ошибка десериализации запроса: неизвестный вариант foo , ожидаемый Token или Code

Когда я вместо этого хотел бы, чтобы он принимал только значения Перечисления в качестве допустимых значений, и если значение не указано или указано недопустимое значение, я хочу, чтобы оно было установлено None равным.

Ответ №1:

С этим можно справиться с помощью deserialize_with .

 use actix_web::{web, App, HttpServer};
use serde::Deserialize;
use serde::de::{Deserializer};

#[derive(Debug, Deserialize)]
pub enum ResponseType {
    Token,
    Code,
}

fn from_response_type<'de, D>(deserializer: D) -> Result<Option<ResponseType>, D::Error>
where
    D: Deserializer<'de>,
{
    let res: Option<ResponseType> = Deserialize::deserialize(deserializer).unwrap_or(None);
    Ok(res)
}

#[derive(Debug, Deserialize)]
pub struct AuthRequest {
    id: u64,
    #[serde(deserialize_with = "from_response_type")]
    response_type: Option<ResponseType>,
}

async fn index(web::Query(info): web::Query<AuthRequest>) -> String {
    format!(
        "Authorization request for client with id={} and type={:?}!",
        info.id, info.response_type
    )
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| App::new().route("/", web::get().to(index)))
        .bind(("127.0.0.1", 8080))?
        .run()
        .await
}
 

Любое недопустимое значение считается a None . Ключевая строка

 let res: Option<ResponseType> = Deserialize::deserialize(deserializer).unwrap_or(None);