use crate::status::Status;
use bon::Builder;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Serialize, Deserialize)]
pub enum ProblemType {
ValidationError,
NotFound,
InternalServerError,
Custom(String),
}
impl ProblemType {
fn as_str(&self) -> String {
match self {
ProblemType::ValidationError => {
"https://example.com/problems/validation-error".to_string()
}
ProblemType::NotFound => "https://example.com/problems/not-found".to_string(),
ProblemType::InternalServerError => {
"https://example.com/problems/internal-server-error".to_string()
}
ProblemType::Custom(s) => s.clone(),
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ExtraKv {
inner: HashMap<String, String>,
}
impl ExtraKv {
fn new() -> Self {
ExtraKv {
inner: HashMap::new(),
}
}
fn is_empty(&self) -> bool {
self.inner.is_empty()
}
fn insert(mut self, k: &str, v: &str) -> Self {
self.inner.insert(k.to_string(), v.to_string());
self
}
}
#[derive(Debug, Serialize, Deserialize, Builder)]
pub struct Problem {
#[serde(rename = "type")]
#[serde(default = "default_problem_type")]
pub problem_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<Status>,
#[serde(skip_serializing_if = "Option::is_none")]
pub detail: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub instance: Option<String>,
#[serde(flatten)]
#[serde(skip_serializing_if = "ExtraKv::is_empty")]
pub extra: ExtraKv,
}
fn default_problem_type() -> String {
"about:blank".to_string()
}
impl Problem {
pub fn new() -> Self {
Problem {
problem_type: default_problem_type(),
title: None,
status: None,
detail: None,
instance: None,
extra: ExtraKv::new(),
}
}
pub fn problem_type(mut self, problem_type: ProblemType) -> Self {
self.problem_type = problem_type.as_str();
self
}
}
#[cfg(test)]
mod test {
use crate::problem_spec::{ExtraKv, Problem, ProblemType};
use std::collections::HashMap;
#[test]
fn test_ok() {
let extra = ExtraKv::new();
let problem_spec = Problem::builder()
.problem_type(ProblemType::ValidationError.as_str())
.title("happen".to_string())
.detail("fund".to_string())
.extra(extra)
.build();
println!("{:?}", serde_json::to_string(&problem_spec).unwrap());
}
}