admin管理员组文章数量:1289362
When handling JSON in Actix Web using serde
, the default deserialization errors (missing field ...
) do not provide a list of all missing fields. Instead, serde
stops at the first missing field and returns an error like:
missing field `firstname` at line 4 column 1
I want to modify this behavior to return all missing fields in a structured JSON format like this:
{
"status": "error",
"errors": {
"validate": {
"missing_value": ["lastname", "password"]
}
}
}
I found that serde
provides an error macro:
fn missing_field(field: &'static str) -> Self {
Error::custom(format_args!("missing field `{}`", field))
}
However, I couldn't figure out how to override it so that it collects all missing fields into a Vec<String>
instead of stopping at the first one. Ideally, I want to be able to process the collected errors and return them in different formats (JSON, XML, etc.).
Here is my current Actix Web handler:
use actix_web::{web, HttpResponse, Responder};
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize)]
pub struct RegisterRequest {
login: String,
password: String,
firstname: String,
lastname: String,
}
#[derive(Debug, Serialize)]
struct RegisterResponse {
message: String,
}
pub async fn register(payload: web::Json<RegisterRequest>) -> impl Responder {
let response = RegisterResponse {
message: format!("User {} registered successfully", payload.login),
};
HttpResponse::Ok().json(response)
}
When handling JSON in Actix Web using serde
, the default deserialization errors (missing field ...
) do not provide a list of all missing fields. Instead, serde
stops at the first missing field and returns an error like:
missing field `firstname` at line 4 column 1
I want to modify this behavior to return all missing fields in a structured JSON format like this:
{
"status": "error",
"errors": {
"validate": {
"missing_value": ["lastname", "password"]
}
}
}
I found that serde
provides an error macro:
fn missing_field(field: &'static str) -> Self {
Error::custom(format_args!("missing field `{}`", field))
}
However, I couldn't figure out how to override it so that it collects all missing fields into a Vec<String>
instead of stopping at the first one. Ideally, I want to be able to process the collected errors and return them in different formats (JSON, XML, etc.).
Here is my current Actix Web handler:
use actix_web::{web, HttpResponse, Responder};
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize)]
pub struct RegisterRequest {
login: String,
password: String,
firstname: String,
lastname: String,
}
#[derive(Debug, Serialize)]
struct RegisterResponse {
message: String,
}
pub async fn register(payload: web::Json<RegisterRequest>) -> impl Responder {
let response = RegisterResponse {
message: format!("User {} registered successfully", payload.login),
};
HttpResponse::Ok().json(response)
}
Share
Improve this question
asked Feb 20 at 13:49
ShvargonShvargon
113 bronze badges
1 Answer
Reset to default 0You can achieve this by defining a custom error type which will collect all the missing attributes. Sample implementation below.
use actix_web::{web, HttpResponse, Responder};
use serde::{Deserialize, Deserializer};
use serde::de::{self, Visitor, MapAccess};
use std::fmt;
#[derive(Debug)]
struct MissingFieldsError {
missing_fields: Vec<String>,
}
impl MissingFieldsError {
fn new() -> Self {
MissingFieldsError {
missing_fields: Vec::new(),
}
}
fn add_field(&mut self, field: &str) {
self.missing_fields.push(field.to_string());
}
}
impl fmt::Display for MissingFieldsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "missing fields: {:?}", self.missing_fields)
}
}
impl std::error::Error for MissingFieldsError {}
#[derive(Debug)]
struct RegisterRequest {
login: String,
password: String,
firstname: String,
lastname: String,
}
impl<'de> Deserialize<'de> for RegisterRequest {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
enum Field { Login, Password, Firstname, Lastname }
struct RegisterRequestVisitor {
missing_fields: MissingFieldsError,
}
impl<'de> Visitor<'de> for RegisterRequestVisitor {
type Value = RegisterRequest;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct RegisterRequest")
}
fn visit_map<V>(mut self, mut map: V) -> Result<RegisterRequest, V::Error>
where
V: MapAccess<'de>,
{
let mut login = None;
let mut password = None;
let mut firstname = None;
let mut lastname = None;
while let Some(key) = map.next_key()? {
match key {
Field::Login => {
if login.is_some() {
return Err(de::Error::duplicate_field("login"));
}
login = Some(map.next_value()?);
}
Field::Password => {
if password.is_some() {
return Err(de::Error::duplicate_field("password"));
}
password = Some(map.next_value()?);
}
Field::Firstname => {
if firstname.is_some() {
return Err(de::Error::duplicate_field("firstname"));
}
firstname = Some(map.next_value()?);
}
Field::Lastname => {
if lastname.is_some() {
return Err(de::Error::duplicate_field("lastname"));
}
lastname = Some(map.next_value()?);
}
}
}
if login.is_none() {
self.missing_fields.add_field("login");
}
if password.is_none() {
self.missing_fields.add_field("password");
}
if firstname.is_none() {
self.missing_fields.add_field("firstname");
}
if lastname.is_none() {
self.missing_fields.add_field("lastname");
}
if !self.missing_fields.missing_fields.is_empty() {
return Err(de::Error::custom(self.missing_fields));
}
Ok(RegisterRequest {
login: login.unwrap(),
password: password.unwrap(),
firstname: firstname.unwrap(),
lastname: lastname.unwrap(),
})
}
}
const FIELDS: &'static [&'static str] = &["login", "password", "firstname", "lastname"];
deserializer.deserialize_struct("RegisterRequest", FIELDS, RegisterRequestVisitor { missing_fields: MissingFieldsError::new() })
}
}
#[derive(Debug, Serialize)]
struct RegisterResponse {
message: String,
}
pub async fn register(payload: web::Json<RegisterRequest>) -> impl Responder {
let response = RegisterResponse {
message: format!("User {} registered successfully", payload.login),
};
HttpResponse::Ok().json(response)
}
本文标签: validationHow to get a list of all missing fields when deserializing a JSON with serdeStack Overflow
版权声明:本文标题:validation - How to get a list of all missing fields when deserializing a JSON with serde? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741430481a2378328.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论