#[derive(AsApiError)]
{
// Attributes available to this derive:
#[api_error]
}
Expand description
Derives the AsApiErrorTrait
for an enum, allowing it to be converted into an ApiError
suitable for Actix-Web responses. It also conditionally implements std::fmt::Display
.
§Attributes
Attributes are placed on enum variants using #[api_error(...)]
:
-
code = <u16>
: Specifies a raw HTTP status code (e.g.,code = 404
). If bothcode
andstatus
are provided,code
takes precedence. -
status = "<StatusCodeString>"
: Specifies the HTTP status using a predefined string. (e.g.,status = "NotFound"
). See below for a list of supported strings. If neithercode
norstatus
is provided, defaults to500
(Internal Server Error). -
kind = "<string>"
: Sets thekind
field in theApiError
. Defaults to thesnake_case
version of the variant name (e.g.,MyVariant
becomes"my_variant"
). -
msg = "<string>"
: Provides a custom error message.- For variants with named fields:
msg = "Error for {field_name}"
. - For variants with unnamed (tuple) fields:
msg = "Error with value {0} and {1}"
. - If
msg
is not provided, the message is generated based on theDisplay
trait:- If this macro generates
Display
(see “Conditionalstd::fmt::Display
Implementation” below), it will be the variant name or a simple format derived from it. - If the user provides
Display
(e.g., viathiserror
), that implementation is used (self.to_string()
).
- If this macro generates
- For variants with named fields:
-
ignore = <bool>
: (Default:false
)- If
true
,msg
is not provided, and the macro does not generateDisplay
, the message will be the variant name, and fields will not be automatically formatted into the message. - This attribute does not prevent field interpolation if a
msg
attribute is provided (e.g.,#[api_error(msg = "Value: {0}", ignore)] MyVariant(i32)
will still print the value). - Its primary use is to simplify the message to just the variant name when no
msg
is given andDisplay
is not generated by this macro, overriding default field formatting.
- If
-
group = <bool>
: (Default:false
)- If
true
, the variant is expected to hold a single field that itself implementsAsApiErrorTrait
. Theas_api_error()
method of this inner error will be called. Other attributes likecode
,status
,msg
,kind
on the group variant are ignored.
- If
§Automatic details
Field Population
If a variant is not a group
and contains a single field of type serde_json::Value
or Option<serde_json::Value>
, this field’s value will automatically populate the
details
field of the generated ApiError
.
§Conditional std::fmt::Display
Implementation
The std::fmt::Display
trait is implemented for the enum by this macro if and only if
at least one variant has an explicit #[api_error(msg = "...")]
attribute.
- If implemented by the macro:
- Variants with
msg
will use that formatted message for theirDisplay
output. - Variants without
msg
will display as their variant name (e.g.,MyEnum::VariantName
displays as “VariantName”).
- Variants with
If no variants use #[api_error(msg = "...")]
, you are expected to provide your own
Display
implementation (e.g., using the thiserror
crate or manually).
The as_api_error
method will then use self.to_string()
for the ApiError
message if msg
is not set on the variant.
§Supported status
Strings and Their Codes
// "BadRequest" => 400
// "Unauthorized" => 401
// "Forbidden" => 403
// "NotFound" => 404
// "MethodNotAllowed" => 405
// "Conflict" => 409
// "Gone" => 410
// "PayloadTooLarge" => 413
// "UnsupportedMediaType" => 415
// "UnprocessableEntity" => 422
// "TooManyRequests" => 429
// "InternalServerError" => 500 (Default if no code/status is specified)
// "NotImplemented" => 501
// "BadGateway" => 502
// "ServiceUnavailable" => 503
// "GatewayTimeout" => 504
Using an unsupported string in status
will result in a compile-time error.
§Example
use actix_error_derive::AsApiError;
// Ensure ApiError and AsApiErrorTrait are in scope, typically via:
// use actix_error::{ApiError, AsApiErrorTrait};
use serde_json::json;
// Dummy AnotherErrorType for the group example
#[derive(Debug)]
pub struct AnotherErrorType;
impl actix_error::AsApiErrorTrait for AnotherErrorType {
fn as_api_error(&self) -> actix_error::ApiError {
actix_error::ApiError::new(401, "auth_failure", "Authentication failed".to_string(), None)
}
}
impl std::fmt::Display for AnotherErrorType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "AnotherErrorType: Authentication Failed")
}
}
#[derive(Debug, AsApiError)]
pub enum MyError {
#[api_error(status = "NotFound", msg = "Resource not found.")]
NotFound, // Display will be "Resource not found."
// No msg, so if Display is macro-generated, it's "InvalidInput".
// If user provides Display (e.g. with thiserror), that's used for ApiError.message.
#[api_error(code = 400, kind = "input_validation")]
InvalidInput { field: String, reason: String },
#[api_error(status = "UnprocessableEntity", msg = "Cannot process item: {0}")]
Unprocessable(String), // Display will be "Cannot process item: <value>"
// 'details' will be auto-populated from the serde_json::Value field.
// msg is present, so Display is "Detailed error occurred."
#[api_error(status = "BadRequest", msg = "Detailed error occurred.")]
DetailedError(serde_json::Value),
#[api_error(group)]
AuthError(AnotherErrorType), // Delegates to AnotherErrorType's AsApiErrorTrait
}
// Since MyError has variants with `msg`, `Display` is generated by AsApiError.
// If no variants had `msg`, you would need to implement `Display` manually or with `thiserror`:
//
// #[derive(Debug, AsApiError, thiserror::Error)] // Example with thiserror
// pub enum MyErrorWithoutMacroDisplay {
// #[error("Item {0} was not found")] // thiserror message
// #[api_error(status = "NotFound")]
// NotFound(String),
//
// #[error("Input is invalid: {reason}")]
// #[api_error(code = 400, kind = "bad_input")]
// InvalidInput { reason: String }
// }