Skip to main content

HttpError

Derive Macro HttpError 

Source
#[derive(HttpError)]
{
    // Attributes available to this derive:
    #[http]
    #[http_error]
    #[tracing]
}
Expand description

Derive macro for HTTP error enums.

Generates implementations for:

  • From<Self> for JsonResponse - Converts error to JSON response
  • IntoResponse - Allows returning error directly from handlers

Note: Use with thiserror::Error for Display, Error, and #[from].

§Attributes

Enum-level defaults can be declared with #[http_error(...)] and overridden per variant with #[http(...)].

For direct responses:

  • code = <u16>: HTTP status code (required)
  • message = "<string>": Static client message (optional)
  • message = <field>: Uses a named field as the client message (optional)
  • error = <field>: Single error field to include (optional, named fields only)
  • errors = <field>: Multiple errors field to include (optional, named fields only)

For delegation:

  • transparent: Delegate to inner type’s From<T> for Json (for wrapping other HttpError types)

Tracing:

  • tracing = <level> inside #[http_error(...)] or #[http(...)]
  • #[tracing(level)]: Backward-compatible shorthand at variant level
    • level: One of trace, debug, info, warn, error
    • Uses the internal thiserror::Error display for the error log field
    • Logs variant fields as structured tracing fields when available
    • Compatible with RUST_LOG for filtering
    • Not allowed with transparent variants

§Tracing Output

The generated logs include:

  • error: The internal thiserror display string
  • error_type: The variant name as string
  • status_code: The HTTP status code
  • For named variants: Each field as field_name = ?field_value
  • For unnamed variants (single field): inner = ?field
  • Unit variants: error, error_type, and status_code

§Example

use sword::prelude::*;
use thiserror::Error;

#[derive(Debug, Error, HttpError)]
#[http_error(code = 500, tracing = error, message = "Internal server error")]
pub enum ApiError {
    #[error("Not found")]
    #[http(code = 404, message = "Not found", tracing = info)]
    NotFound,

    #[error("Conflict on field {field}: {value}")]
    #[http(code = 409, message = client_message, error = detail)]
    Conflict {
        client_message: String,
        field: String,
        value: String,
        detail: serde_json::Value,
    },

    #[error("IO Error: {0}")]
    Io(#[from] std::io::Error),

    #[error("Auth Error: {0}")]
    #[http(transparent)]  // Delegates to other "HttpError" derivation
    Auth(#[from] AuthError),
}