macro_rules! define_custom_type {
    ($(#[$meta: meta])* type $rstyp: ident {
        type: $typ:literal,
        title: $title:literal,
        status: $status: expr,
        detail($prob: ident): $detail: expr,
        extensions: {
            $($field:ident: $field_ty: ty),* $(,)?
        } $(,)?
    }) => { ... };
}
Expand description

Define a new custom problem type.

Although defining a new custom type requires only implementing the CustomProblem trait, this macro simplifies the code, removing boilerplate from the definition.

Example

use http_problem::prelude::{StatusCode, Uri};
problem::define_custom_type! {
    /// An error that occurs when a transaction cannot be done
    /// because one of the accounts doesn't have enough credit.
    type OutOfCredit {
        type: "https://example.com/probs/out-of-credit",
        title: "You do not have enough credit",
        status: StatusCode::FORBIDDEN,
        detail(p): format!("You current balance is {}, but that costs {}", p.balance, p.cost),
        extensions: {
            balance: i64,
            cost: i64,
            accounts: Vec<String>
        }
    }
}

fn do_transaction() -> problem::Result<()> {
    Err(OutOfCredit {
        balance: 50,
        cost: 30,
        accounts: vec!["/account/12345".into(), "/account/67890".into()]
    }.into())
}

fn main() {
    let problem = do_transaction().unwrap_err();
    assert_eq!(problem.type_(), &Uri::from_static("https://example.com/probs/out-of-credit"));
    assert_eq!(problem.title(), "You do not have enough credit");
    assert_eq!(problem.status(), StatusCode::FORBIDDEN);
    assert_eq!(problem.details(), "You current balance is 50, but that costs 30");
    assert_eq!(problem.extensions().len(), 3);
}