### Run Web Framework Integration Example Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Run the web framework integration example to test how apiresponse works with different web frameworks. This helps in verifying setup and basic usage. ```bash # Web framework integration cargo run --example web_framework_example ``` -------------------------------- ### Run Complete Feature Demonstration Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Execute the complete example to see all features of the apiresponse crate in action. This is useful for understanding the full capabilities and integration. ```bash # Complete feature demonstration cargo run --example complete_example ``` -------------------------------- ### Automatic Module Prefixing Example Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Demonstrates how error messages automatically include module paths with the `#[response(module = "...")]` attribute. Also shows `module_path()` and `raw_message()` methods. ```rust #[derive(Debug, Error, Response)] #[response(module = "payment.stripe", base = 2000)] pub enum PaymentError { #[error("Insufficient balance")] InsufficientBalance, // Error code: 2000 } let err = PaymentError::InsufficientBalance; err.message() // → "[payment.stripe] Insufficient balance" err.module_path() // → "payment.stripe" err.raw_message() // → "Insufficient balance" ``` -------------------------------- ### Transparent Error Delegation Example Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Shows how to use `#[response(transparent)]` to delegate error handling to an inner error type, allowing for proper error propagation and consistent API responses. ```rust #[derive(Debug, Error, Response)] #[response(module = "api")] pub enum ApiError { #[error(transparent)] #[response(transparent)] Auth(#[from] AuthError), // Delegates to inner error } // When ApiError::Auth(AuthError::UserNotFound) occurs: let error = ApiError::Auth(AuthError::UserNotFound); error.message() // → "[auth] User not found" (from AuthError) error.module_path() // → "auth" (from AuthError) error.error_code() // → 1000 (from AuthError) ``` -------------------------------- ### Derive macro for error enums Source: https://context7.com/zhenglongbing/apiresponse/llms.txt Demonstrates how to use the `#[derive(Response)]` macro on an error enum to automatically implement methods for error code, module path, raw message, and HTTP status code retrieval. This example shows auto-numbering of error codes and setting HTTP status codes. ```APIDOC ## `#[derive(Response)]` — Derive macro for error enums Implements the `Response` trait on an error enum. Generates `error_code()`, `module_path()`, `raw_message()`, and `http_status_code()` match arms at compile time. Only works on enums; applying it to a struct or union is a compile error. ```rust use apiresponse::Response; use thiserror::Error; // Auto-numbering: codes start at `base` and increment by variant index. // module_path() returns "auth.login" for all variants. #[derive(Debug, Error, Response)] #[response(module = "auth.login", base = 1000)] pub enum AuthError { #[error("User does not exist")] UserNotFound, // code = 1000, status = 200 #[error("Incorrect password")] PasswordWrong, // code = 1001, status = 200 #[error("Token expired")] #[response(status = 401)] TokenExpired, // code = 1002, status = 401 #[error("Account is locked")] #[response(code = 1010, status = 403)] // override auto-number AccountLocked, // code = 1010, status = 403 } fn main() { let e = AuthError::UserNotFound; assert_eq!(e.error_code(), 1000); assert_eq!(e.module_path(), "auth.login"); assert_eq!(e.raw_message(), "User does not exist"); assert_eq!(e.message(), "[auth.login] User does not exist"); assert_eq!(e.http_status_code(), 200); let locked = AuthError::AccountLocked; assert_eq!(locked.error_code(), 1010); assert_eq!(locked.http_status_code(), 403); } ``` ``` -------------------------------- ### RESTful API Error Handling with UserError Enum Source: https://github.com/zhenglongbing/apiresponse/blob/main/apiresponse-macro/README.md Demonstrates defining custom API errors using the `Response` derive macro for a 'user' module with a base error code of 1000. Includes examples of handling these errors in API handlers. ```APIDOC ## RESTful API Error Handling ### UserError Enum Definition ```rust #[derive(Debug, Error, Response)] #[response(module = "user", base = 1000)] pub enum UserError { #[error("User not found")] #[response(status = 404)] NotFound, #[error("Permission denied")] #[response(status = 403)] PermissionDenied, } ``` ### API Handler Example ```rust // In API handler async fn get_user(id: u64) -> Result, UserError> { let user = find_user(id).ok_or(UserError::NotFound)?; check_permission(&user).ok_or(UserError::PermissionDenied)?; Ok(Json(user)) } ``` ``` -------------------------------- ### Error Definition Without Module Attribute Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Example of defining an error enum without the `module` attribute in `#[response]`. This results in error messages without a module prefix and an empty `module_path()`. ```rust #[derive(Debug, Error, Response)] #[response(base = 6000)] pub enum SimpleError { #[error("Generic error")] GenericError, // Code: 6000, no module prefix #[error("Another error")] AnotherError, // Code: 6001, no module prefix } // Usage let err = SimpleError::GenericError; err.message() // → "Generic error" (no module prefix) err.module_path() // → "" ``` -------------------------------- ### Define RESTful API Errors with ApiResponse Source: https://github.com/zhenglongbing/apiresponse/blob/main/apiresponse/README.md Define custom error types for your API using derive macros. Specify HTTP status codes and error messages directly on the enum variants. This example shows how to define user-related errors like 'NotFound' and 'PermissionDenied'. ```rust use apiresponse::Response; use thiserror::Error; #[derive(Debug, Error, Response)] #[response(module = "user", base = 1000)] pub enum UserError { #[error("User not found")] #[response(status = 404)] NotFound, #[error("Permission denied")] #[response(status = 403)] PermissionDenied, } // In API handler async fn get_user(id: u64) -> Result, UserError> { let user = find_user(id).ok_or(UserError::NotFound)?; check_permission(&user).ok_or(UserError::PermissionDenied)?; Ok(Json(user)) } ``` -------------------------------- ### Derive Response for AuthError Enum Source: https://context7.com/zhenglongbing/apiresponse/llms.txt Implement the Response trait for an error enum using #[derive(Response)]. Configure module path and base error code. Variants automatically get codes and messages, with options to override. ```rust use apiresponse::Response; use thiserror::Error; // Auto-numbering: codes start at `base` and increment by variant index. // module_path() returns "auth.login" for all variants. #[derive(Debug, Error, Response)] #[response(module = "auth.login", base = 1000)] pub enum AuthError { #[error("User does not exist")] UserNotFound, // code = 1000, status = 200 #[error("Incorrect password")] PasswordWrong, // code = 1001, status = 200 #[error("Token expired")] #[response(status = 401)] TokenExpired, // code = 1002, status = 401 #[error("Account is locked")] #[response(code = 1010, status = 403)] // override auto-number AccountLocked, // code = 1010, status = 403 } fn main() { let e = AuthError::UserNotFound; assert_eq!(e.error_code(), 1000); assert_eq!(e.module_path(), "auth.login"); assert_eq!(e.raw_message(), "User does not exist"); assert_eq!(e.message(), "[auth.login] User does not exist"); assert_eq!(e.http_status_code(), 200); let locked = AuthError::AccountLocked; assert_eq!(locked.error_code(), 1010); assert_eq!(locked.http_status_code(), 403); } ``` -------------------------------- ### Web Framework Integration - Axum Source: https://github.com/zhenglongbing/apiresponse/blob/main/apiresponse/README.md Illustrates how to integrate `ApiResponse` with the Axum web framework to automatically handle error responses. ```APIDOC ## Web Framework Integration ### Axum Example of using `ApiResponse` with Axum to return errors. ```rust use axum::{routing::get, Router}; use apiresponse::ApiResponse; async fn handler() -> ApiResponse { // ApiResponse automatically implements IntoResponse // HTTP status code is set from the status_code field ApiResponse::from_error(AuthError::UserNotFound) } let app = Router::new().route("/user", get(handler)); ``` ``` -------------------------------- ### Axum Web Framework Integration Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Demonstrates how to use ApiResponse with the Axum web framework to return structured API responses, including errors. ```APIDOC ## Web Framework Integration ### Axum ```rust use axum::{routing::get, Router}; use apiresponse::ApiResponse; async fn handler() -> ApiResponse { // ApiResponse automatically implements IntoResponse // HTTP status code is set from the status_code field ApiResponse::from_error(AuthError::UserNotFound) } let app = Router::new().route("/user", get(handler)); ``` ``` -------------------------------- ### Web Framework Integration - Actix-web Source: https://github.com/zhenglongbing/apiresponse/blob/main/apiresponse-macro/README.md Demonstrates integrating `ApiResponse` with Actix-web, showing how `ApiResponse` can be used as a `Responder` for custom error responses. ```APIDOC ### Actix-web ```rust use actix_web::{get, HttpResponse}; use api_response::ApiResponse; #[get("/user")] async fn handler() -> ApiResponse { // ApiResponse implements Responder ApiResponse::from_error(AuthError::UserNotFound) } ``` ``` -------------------------------- ### Web Framework Integration - Actix-web Source: https://github.com/zhenglongbing/apiresponse/blob/main/apiresponse/README.md Demonstrates integrating `ApiResponse` with Actix-web for seamless error response handling. ```APIDOC ### Actix-web Example of using `ApiResponse` with Actix-web to return errors. ```rust use actix_web::{get, HttpResponse}; use apiresponse::ApiResponse; #[get("/user")] async fn handler() -> ApiResponse { // ApiResponse implements Responder ApiResponse::from_error(AuthError::UserNotFound) } ``` ``` -------------------------------- ### Web Framework Integration - Axum Source: https://github.com/zhenglongbing/apiresponse/blob/main/apiresponse-macro/README.md Illustrates how to integrate `ApiResponse` with the Axum web framework, enabling custom error responses to be automatically converted into HTTP responses. ```APIDOC ## Web Framework Integration ### Axum ```rust use axum::{routing::get, Router}; use api_response::ApiResponse; async fn handler() -> ApiResponse { // ApiResponse automatically implements IntoResponse // HTTP status code is set from the status_code field ApiResponse::from_error(AuthError::UserNotFound) } let app = Router::new().route("/user", get(handler)); ``` ``` -------------------------------- ### Actix-web Integration Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Illustrates integrating ApiResponse with the Actix-web framework for creating API responses. ```APIDOC ### Actix-web ```rust use actix_web::{get, HttpResponse}; use apiresponse::ApiResponse; #[get("/user")] async fn handler() -> ApiResponse { // ApiResponse implements Responder ApiResponse::from_error(AuthError::UserNotFound) } ``` ``` -------------------------------- ### Web Framework Integration - Poem Source: https://github.com/zhenglongbing/apiresponse/blob/main/apiresponse/README.md Shows how to use `ApiResponse` with the Poem web framework for error response management. ```APIDOC ### Poem Example of using `ApiResponse` with Poem to return errors. ```rust use poem::{get, handler, Route}; use apiresponse::ApiResponse; #[handler] async fn handler() -> ApiResponse { // ApiResponse implements IntoResponse ApiResponse::from_error(AuthError::UserNotFound) } let app = Route::new().at("/user", get(handler)); ``` ``` -------------------------------- ### Poem Integration with ApiResponse Source: https://context7.com/zhenglongbing/apiresponse/llms.txt Demonstrates how to integrate ApiResponse with the Poem framework for handling errors. Requires `apiresponse` with the `poem` feature enabled. The `ApiResponse` type implements `IntoResponse` for Poem, and errors implementing `Response` can be converted into `ApiResponse`. ```rust // Cargo.toml: apiresponse = { version = "0.1", features = ["poem"] } use apiresponse::{ApiResponse, Response}; use poem::{Route, Server, handler, listener::TcpListener, get}; use thiserror::Error; #[derive(Debug, Error, Response)] #[response(module = "items", base = 2000)] pub enum ItemError { #[error("Item not found")] #[response(status = 404)] NotFound, } #[handler] fn get_item() -> ApiResponse { let result: Result<&str, ItemError> = Err(ItemError::NotFound); result.into() // HTTP 404, body: {"code":2000,"message":"[items] Item not found","data":null} } #[tokio::main] async fn main() -> Result<(), std::io::Error> { let app = Route::new().at("/item", get(get_item)); Server::new(TcpListener::bind("0.0.0.0:3000")) .run(app) .await } ``` -------------------------------- ### Multi-level Module Names Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Demonstrates how to define hierarchical module names for errors using the `#[response(module = ...)]` attribute, resulting in prefixed messages like `[api.v1.auth] ...`. ```APIDOC ### Multi-level Module Names ```rust #[response(module = "api.v1.auth")] pub enum AuthError { /* ... */ } // Messages will be prefixed with [api.v1.auth] ``` ``` -------------------------------- ### Poem Integration Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Shows how to use ApiResponse with the Poem web framework to handle API responses. ```APIDOC ### Poem ```rust use poem::{get, handler, Route}; use api_response::ApiResponse; #[handler] async fn handler() -> ApiResponse { // ApiResponse implements IntoResponse ApiResponse::from_error(AuthError::UserNotFound) } let app = Route::new().at("/user", get(handler)); ``` ``` -------------------------------- ### Manual Error Code and Status Assignment Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Demonstrates manual assignment of error codes and HTTP status codes using `#[response(code = ..., status = ...)]` when a `base` is not provided or needs to be overridden. ```rust #[derive(Debug, Error, Response)] #[response(module = "validation")] pub enum ValidationError { #[error("Invalid email")] #[response(code = 4001, status = 400)] InvalidEmail, #[error("Weak password")] #[response(code = 4002, status = 400)] WeakPassword, } ``` -------------------------------- ### Advanced Features - Access Metadata Source: https://github.com/zhenglongbing/apiresponse/blob/main/apiresponse/README.md Demonstrates how to access metadata like module path and messages from error objects. ```APIDOC ## Advanced Features ### Access Metadata Retrieve detailed information from error objects. ```rust // Get module path let module = error.module_path(); // "auth.login" // Raw vs Formatted messages error.raw_message() // → "User not found" error.message() // → "[auth.login] User not found" ``` ``` -------------------------------- ### Add apiresponse to Cargo.toml Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Add the apiresponse crate to your project's Cargo.toml file. For web framework integration, enable the appropriate feature flag. ```toml [dependencies] apiresponse = "0.1" thiserror = "1.0" # For error definitions ``` ```toml [dependencies] apiresponse = { version = "0.1", features = ["axum"] } # or "actix", "poem" ``` -------------------------------- ### Using Error Type Methods Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Once defined, your error type provides methods for formatted messages, error codes, and HTTP status codes. The message includes an automatic module prefix. ```rust let error = AuthError::UserNotFound; // Automatic module prefix println!("{}", error.message()); // Output: [auth] User not found // Error code (auto-numbered) println!("{}", error.error_code()); // Output: 1000 // HTTP status code println!("{}", error.http_status_code()); // Output: 404 ``` -------------------------------- ### Advanced Features - Multi-level Module Names Source: https://github.com/zhenglongbing/apiresponse/blob/main/apiresponse/README.md Explains how to use hierarchical module names for better organization of error messages. ```APIDOC ### Multi-level Module Names Organize errors using nested module paths for clarity. ```rust #[response(module = "api.v1.auth")] pub enum AuthError { /* ... */ } // Messages will be prefixed with [api.v1.auth] ``` ``` -------------------------------- ### Poem Integration with ApiResponse Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Integrate `ApiResponse` with Poem by returning `ApiResponse` from handlers. Poem's `IntoResponse` implementation for `ApiResponse` ensures correct response handling. ```rust use poem::{get, handler, Route}; use api_response::ApiResponse; #[handler] async fn handler() -> ApiResponse { // ApiResponse implements IntoResponse ApiResponse::from_error(AuthError::UserNotFound) } let app = Route::new().at("/user", get(handler)); ``` -------------------------------- ### Add api-response to Cargo.toml Source: https://github.com/zhenglongbing/apiresponse/blob/main/apiresponse-macro/README.md Include the api-response crate in your project's dependencies. For web framework integration, enable the appropriate feature flag. ```toml [dependencies] api-response = "0.1" thiserror = "1.0" # For error definitions ``` ```toml [dependencies] api-response = { version = "0.1", features = ["axum"] } # or "actix", "poem" ``` -------------------------------- ### Actix-web Integration with ApiResponse Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Integrate `ApiResponse` with Actix-web by returning `ApiResponse` from handlers. `ApiResponse` implements the `Responder` trait, allowing Actix-web to handle it directly. ```rust use actix_web::{get, HttpResponse}; use apiresponse::ApiResponse; #[get("/user")] async fn handler() -> ApiResponse { // ApiResponse implements Responder ApiResponse::from_error(AuthError::UserNotFound) } ``` -------------------------------- ### Actix-web Integration with ApiResponse Source: https://github.com/zhenglongbing/apiresponse/blob/main/apiresponse-macro/README.md Integrate `ApiResponse` with Actix-web by returning `ApiResponse` from handlers. `ApiResponse` implements the `Responder` trait for seamless integration. ```rust use actix_web::{get, HttpResponse}; use api_response::ApiResponse; #[get("/user")] async fn handler() -> ApiResponse { // ApiResponse implements Responder ApiResponse::from_error(AuthError::UserNotFound) } ``` -------------------------------- ### Axum Integration for ApiResponse Source: https://context7.com/zhenglongbing/apiresponse/llms.txt Enables `impl IntoResponse for ApiResponse` by enabling the `axum` feature. This allows `ApiResponse` to be directly returned from Axum route handlers, automatically serializing to JSON with the correct HTTP status. ```rust // Cargo.toml: apiresponse = { version = "0.1", features = ["axum"] } use apiresponse::{ApiResponse, Response}; use axum::{Router, routing::get}; use thiserror::Error; #[derive(Debug, Error, Response)] #[response(module = "user", base = 1000)] pub enum UserError { #[error("User not found")] #[response(status = 404)] NotFound, #[error("Forbidden")] #[response(status = 403)] Forbidden, } async fn get_user(/* axum::extract::Path(id): Path */) -> ApiResponse { // Simulated lookup failure let result: Result = Err(UserError::NotFound); result.into() // HTTP 404, body: {"code":1000,"message":"[user] User not found","data":null} } async fn health() -> ApiResponse { ApiResponse::ok() // HTTP 200, body: {"code":0,"message":"OK","data":null} } #[tokio::main] async fn main() { let app = Router::new() .route("/user", get(get_user)) .route("/health", get(health)); let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); axum::serve(listener, app).await.unwrap(); } ``` -------------------------------- ### Actix-web Integration for ApiResponse Source: https://context7.com/zhenglongbing/apiresponse/llms.txt Enables `impl Responder for ApiResponse` by enabling the `actix` feature. This allows `ApiResponse` to be returned directly from Actix-web route handlers, serializing to JSON with the correct HTTP status code. ```rust // Cargo.toml: apiresponse = { version = "0.1", features = ["actix"] } use actix_web::{get, web, App, HttpServer}; use apiresponse::{ApiResponse, Response}; use thiserror::Error; #[derive(Debug, Error, Response)] #[response(module = "auth", base = 1000)] pub enum AuthError { #[error("Unauthorized")] #[response(status = 401)] Unauthorized, } #[get("/protected")] async fn protected() -> ApiResponse { let result: Result<&str, AuthError> = Err(AuthError::Unauthorized); result.into() // HTTP 401, body: {"code":1000,"message":"[auth] Unauthorized","data":null} } #[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| App::new().service(protected)) .bind("0.0.0.0:8080")? .run() .await } ``` -------------------------------- ### Define Multi-level Module Names for Errors Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Configure nested module names for API errors using the `#[response(module = ...)]` attribute. This helps in organizing errors hierarchically, leading to more descriptive error message prefixes. ```rust #[response(module = "api.v1.auth")] pub enum AuthError { /* ... */ } // Messages will be prefixed with [api.v1.auth] ``` -------------------------------- ### Poem Integration with ApiResponse Source: https://github.com/zhenglongbing/apiresponse/blob/main/apiresponse/README.md Integrate ApiResponse with Poem by returning ApiResponse directly from your handlers. ApiResponse implements Poem's `IntoResponse` trait for automatic conversion to HTTP responses. ```rust use poem::{get, handler, Route}; use apiresponse::ApiResponse; #[handler] async fn handler() -> ApiResponse { // ApiResponse implements IntoResponse ApiResponse::from_error(AuthError::UserNotFound) } let app = Route::new().at("/user", get(handler)); ``` -------------------------------- ### Automatic Result to ApiResponse Conversion Source: https://context7.com/zhenglongbing/apiresponse/llms.txt Implement `From>` for `ApiResponse` to automatically convert `Ok` values to success responses and `Err` values to error responses, extracting error details like code, message, and HTTP status. ```rust use apiresponse::{ApiResponse, Response}; use thiserror::Error; #[derive(Debug, Error, Response)] #[response(module = "payment.stripe", base = 2000)] pub enum PaymentError { #[error("Insufficient balance")] InsufficientBalance, // code = 2000 #[error("Payment failed: {0}")] PaymentFailed(String), // code = 2001 #[error("Order does not exist")] #[response(status = 404)] OrderNotFound, // code = 2002 } fn process_payment(amount: f64) -> Result { if amount > 1000.0 { return Err(PaymentError::InsufficientBalance); } Ok(format!("Paid ${}", amount)) } fn main() { // Ok path let resp: ApiResponse = process_payment(50.0).into(); assert_eq!(resp.code, 0); assert_eq!(resp.message, "OK"); // Err path let resp: ApiResponse = process_payment(9999.0).into(); assert_eq!(resp.code, 2000); assert_eq!(resp.message, "[payment.stripe] Insufficient balance"); assert_eq!(resp.status_code, 200); // Parametric error variant let resp: ApiResponse = Err::( PaymentError::PaymentFailed("Network timeout".into()) ).into(); assert_eq!(resp.message, "[payment.stripe] Payment failed: Network timeout"); } ``` -------------------------------- ### ApiResponse Struct API Reference Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Reference for the `ApiResponse` struct, used for constructing API responses. It includes fields for code, message, data, and HTTP status code. Useful for understanding the structure of responses generated by the crate. ```rust #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ApiResponse { pub code: u64, pub message: String, pub data: serde_json::Value, #[serde(skip)] pub status_code: u16, } // Methods: // - ApiResponse::success(data) - Create success response with data // - ApiResponse::success_with_message(data, message) - Success with custom message // - ApiResponse::ok() - Create empty success response ``` -------------------------------- ### Automatic Error Code Numbering with Base Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Illustrates automatic sequential error code allocation based on a specified `base` value within the `#[response]` attribute. ```rust #[derive(Debug, Error, Response)] #[response(module = "user", base = 1000)] pub enum UserError { #[error("Not found")] NotFound, // Code: 1000 #[error("Unauthorized")] Unauthorized, // Code: 1001 #[error("Forbidden")] Forbidden, // Code: 1002 } ``` -------------------------------- ### Response Attribute Macros Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Explains the use of #[response] attributes for configuring error modules, base codes, and specific error codes/statuses at the enum and variant levels. ```APIDOC ### Attributes #### Enum-level Attributes ```rust #[response(module = "module_name", base = base_code)] // ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ // Optional (default "") Optional (if omitted, variants must specify code) ``` #### Variant-level Attributes ```rust #[response(code = error_code, status = http_status, message = "custom_message")] // ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ // Optional (override) Optional (default 200) Optional (override Display) #[response(transparent)] // Delegate to inner error ``` ``` -------------------------------- ### Axum Integration with ApiResponse Source: https://github.com/zhenglongbing/apiresponse/blob/main/apiresponse-macro/README.md Integrate `ApiResponse` with Axum by returning `ApiResponse` directly from handlers. `ApiResponse` implements `IntoResponse`, automatically setting the HTTP status code from its `status_code` field. ```rust use axum::{routing::get, Router}; use api_response::ApiResponse; async fn handler() -> ApiResponse { // ApiResponse automatically implements IntoResponse // HTTP status code is set from the status_code field ApiResponse::from_error(AuthError::UserNotFound) } let app = Router::new().route("/user", get(handler)); ``` -------------------------------- ### Access Error Metadata Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Demonstrates how to access metadata from an error object, such as the module path and formatted messages. This is useful for logging or displaying detailed error information. ```rust // Get module path let module = error.module_path(); // "auth.login" // Raw vs Formatted messages error.raw_message() // → "User not found" error.message() // → "[auth.login] User not found" ``` -------------------------------- ### API Reference - ApiResponse Struct Source: https://github.com/zhenglongbing/apiresponse/blob/main/apiresponse/README.md Describes the `ApiResponse` struct, used for constructing success and error responses. ```APIDOC ### ApiResponse Struct Represents a structured API response, capable of holding data or error information. ```rust #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ApiResponse { pub code: u64, pub message: String, pub data: serde_json::Value, #[serde(skip)] pub status_code: u16, } ``` #### Methods - `ApiResponse::success(data)` - Create success response with data - `ApiResponse::success_with_message(data, message)` - Success with custom message - `ApiResponse::ok()` - Create empty success response ``` -------------------------------- ### `ApiResponse` — serializable JSON response struct Source: https://context7.com/zhenglongbing/apiresponse/llms.txt This section explains the `ApiResponse` struct, which is a serializable JSON response. It covers its fields (`code`, `message`, `data`, `status_code`) and how to create instances using `ApiResponse::success()`, `ApiResponse::ok()`, or by converting from a `Result` where `E: Response`. ```APIDOC ## `ApiResponse` — serializable JSON response struct A `Serialize`/`Deserialize` struct with fields `code: u64`, `message: String`, `data: serde_json::Value`, and `status_code: u16` (skipped in JSON). Created via `ApiResponse::success(data)`, `ApiResponse::ok()`, or converted from any `Result` where `E: Response`. The `status_code` field drives the HTTP response code when using a web framework feature. ```rust use apiresponse::{ApiResponse, Response}; use thiserror::Error; use serde::Serialize; #[derive(Debug, Error, Response)] #[response(module = "user", base = 1000)] pub enum UserError { #[error("User not found")] #[response(status = 404)] NotFound, } #[derive(Serialize)] struct User { id: u64, name: String } fn main() { // Success with data let user = User { id: 1, name: "Alice".to_string() }; let ok = ApiResponse::success(user); println!("{}", serde_json::to_string_pretty(&ok).unwrap()); // { // "code": 0, // "message": "OK", // "data": { "id": 1, "name": "Alice" } // } // Empty success let empty = ApiResponse::ok(); assert_eq!(empty.code, 0); assert_eq!(empty.status_code, 200); // From Result — error path let result: Result = Err(UserError::NotFound); let resp: ApiResponse = result.into(); println!("{}", serde_json::to_string_pretty(&resp).unwrap()); // { // "code": 1000, // "message": "[user] User not found", // "data": null // } assert_eq!(resp.status_code, 404); // drives HTTP status in framework integrations } ``` ``` -------------------------------- ### `Response` trait — core interface Source: https://context7.com/zhenglongbing/apiresponse/llms.txt This section describes the `Response` trait, which is the core interface implemented by `#[derive(Response)]`. It details the required `error_code()` method and other default methods like `message()`, `module_path()`, and `http_status_code()`. ```APIDOC ## `Response` trait — core interface The trait that `#[derive(Response)]` implements. Can also be implemented manually. `error_code()` is the only required method; the others have provided defaults. `message()` combines `module_path()` and `raw_message()` into `[module] message` automatically. ```rust use apiresponse::Response; use std::fmt; // Manual implementation (no macro) #[derive(Debug)] pub enum CustomError { NotFound, Forbidden, } impl fmt::Display for CustomError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::NotFound => write!(f, "Resource not found"), Self::Forbidden => write!(f, "Access denied"), } } } impl Response for CustomError { fn error_code(&self) -> u64 { match self { Self::NotFound => 404, Self::Forbidden => 403, } } fn module_path(&self) -> &'static str { "custom" } fn http_status_code(&self) -> u16 { match self { Self::NotFound => 404, Self::Forbidden => 403, } } } fn main() { let e = CustomError::NotFound; println!("{}", e.message()); // "[custom] Resource not found" println!("{}", e.error_code()); // 404 println!("{}", e.http_status_code()); // 404 } ``` ``` -------------------------------- ### Enum-level Attributes for Response Trait Source: https://github.com/zhenglongbing/apiresponse/blob/main/apiresponse/README.md Configure the `Response` trait behavior at the enum level using attributes. `#[response(module = "module_name")]` sets a default module path, and `#[response(base = base_code)]` sets a base code for variants. ```rust #[response(module = "module_name", base = base_code)] // ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ // Optional (default "") Optional (if omitted, variants must specify code) ``` -------------------------------- ### Create Serializable JSON Responses with `ApiResponse` Source: https://context7.com/zhenglongbing/apiresponse/llms.txt Use the `ApiResponse` struct to create serializable JSON responses. It supports success responses with data, empty success responses, and conversion from `Result` where `E: Response`. The `status_code` field influences the HTTP response code in web framework integrations. ```rust use apiresponse::{ApiResponse, Response}; use thiserror::Error; use serde::Serialize; #[derive(Debug, Error, Response)] #[response(module = "user", base = 1000)] pub enum UserError { #[error("User not found")] #[response(status = 404)] NotFound, } #[derive(Serialize)] struct User { id: u64, name: String } fn main() { // Success with data let user = User { id: 1, name: "Alice".to_string() }; let ok = ApiResponse::success(user); println!("{}", serde_json::to_string_pretty(&ok).unwrap()); // { // "code": 0, // "message": "OK", // "data": { "id": 1, "name": "Alice" } // } // Empty success let empty = ApiResponse::ok(); assert_eq!(empty.code, 0); assert_eq!(empty.status_code, 200); // From Result — error path let result: Result = Err(UserError::NotFound); let resp: ApiResponse = result.into(); println!("{}", serde_json::to_string_pretty(&resp).unwrap()); // { // "code": 1000, // "message": "[user] User not found", // "data": null // } assert_eq!(resp.status_code, 404); // drives HTTP status in framework integrations } ``` -------------------------------- ### API Reference - Attributes Source: https://github.com/zhenglongbing/apiresponse/blob/main/apiresponse/README.md Explains the attributes used to configure error types and variants for `apiresponse`. ```APIDOC ### Attributes #### Enum-level Attributes Used to configure the module path and base error code for all variants within an enum. ```rust #[response(module = "module_name", base = base_code)] // ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ // Optional (default "") Optional (if omitted, variants must specify code) ``` #### Variant-level Attributes Used to specify details for individual error variants, such as code, status, and custom messages. ```rust #[response(code = error_code, status = http_status, message = "custom_message")] // ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ // Optional (override) Optional (default 200) Optional (override Display) #[response(transparent)] // Delegate to inner error ``` ``` -------------------------------- ### Variant-level Attributes for Response Derive Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Configuration attributes for the `#[response]` derive macro at the variant level. `code` and `status` override defaults, `message` customizes the error string, and `transparent` delegates to an inner error. ```rust #[response(code = error_code, status = http_status, message = "custom_message")] // ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ // Optional (override) Optional (default 200) Optional (override Display) #[response(transparent)] // Delegate to inner error ``` -------------------------------- ### RESTful API Error Handling with UserError Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Defines custom user-related errors with specific HTTP status codes using the Response derive macro. Demonstrates how to handle these errors within an API handler. ```APIDOC ## RESTful API Error Handling ### UserError Enum ```rust #[derive(Debug, Error, Response)] #[response(module = "user", base = 1000)] pub enum UserError { #[error("User not found")] #[response(status = 404)] NotFound, #[error("Permission denied")] #[response(status = 403)] PermissionDenied, } ``` ### API Handler Example ```rust // In API handler async fn get_user(id: u64) -> Result, UserError> { let user = find_user(id).ok_or(UserError::NotFound)?; check_permission(&user).ok_or(UserError::PermissionDenied)?; Ok(Json(user)) } ``` ``` -------------------------------- ### Enum-level attribute: `#[response(module = "...", base = N)]` Source: https://context7.com/zhenglongbing/apiresponse/llms.txt Explains the enum-level `#[response]` attribute for configuring the error module path and the base for auto-generated error codes. It also covers scenarios where these attributes are omitted, requiring explicit configuration for each variant. ```APIDOC ## Enum-level attribute: `#[response(module = "...", base = N)]` `module` sets the string prefix included in `message()` output as `[module] raw_message`. `base` sets the starting integer for auto-numbered error codes; each subsequent variant adds its zero-based index to `base`. Both attributes are optional — omitting `module` disables prefixing, omitting `base` requires every variant to declare an explicit `code`. ```rust use apiresponse::Response; use thiserror::Error; // No module: message() returns raw message without prefix. // No base: every variant must supply an explicit code. #[derive(Debug, Error, Response)] #[response(module = "validation")] pub enum ValidationError { #[error("Invalid email format")] #[response(code = 5001, status = 400)] InvalidEmail, #[error("Insufficient password strength")] #[response(code = 5002, status = 400)] WeakPassword, } // No module attribute at all — module_path() is "" and message() has no prefix. #[derive(Debug, Error, Response)] #[response(base = 6000)] pub enum SimpleError { #[error("Generic error")] GenericError, // code = 6000 #[error("Another error")] #[response(status = 500)] AnotherError, // code = 6001 } fn main() { let e = ValidationError::InvalidEmail; assert_eq!(e.error_code(), 5001); assert_eq!(e.message(), "[validation] Invalid email format"); let s = SimpleError::GenericError; assert_eq!(s.module_path(), ""); assert_eq!(s.message(), "Generic error"); // no prefix assert_eq!(s.error_code(), 6000); } ``` ``` -------------------------------- ### Axum Integration with ApiResponse Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Integrate `ApiResponse` with Axum by returning `ApiResponse` directly from handlers. Axum automatically converts `ApiResponse` into an HTTP response, using the `status_code` field for the HTTP status. ```rust use axum::{routing::get, Router}; use apiresponse::ApiResponse; async fn handler() -> ApiResponse { // ApiResponse automatically implements IntoResponse // HTTP status code is set from the status_code field ApiResponse::from_error(AuthError::UserNotFound) } let app = Router::new().route("/user", get(handler)); ``` -------------------------------- ### Manual `Response` Trait Implementation Source: https://context7.com/zhenglongbing/apiresponse/llms.txt Implement the `Response` trait manually for custom error types when derive macros are not suitable. Ensure `error_code()` is implemented; other methods like `module_path()`, `raw_message()`, and `http_status_code()` have default implementations. ```rust use apiresponse::Response; use std::fmt; // Manual implementation (no macro) #[derive(Debug)] pub enum CustomError { NotFound, Forbidden, } impl fmt::Display for CustomError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::NotFound => write!(f, "Resource not found"), Self::Forbidden => write!(f, "Access denied"), } } } impl Response for CustomError { fn error_code(&self) -> u64 { match self { Self::NotFound => 404, Self::Forbidden => 403, } } fn module_path(&self) -> &'static str { "custom" } fn http_status_code(&self) -> u16 { match self { Self::NotFound => 404, Self::Forbidden => 403, } } } fn main() { let e = CustomError::NotFound; println!("{}", e.message()); // "[custom] Resource not found" println!("{}", e.error_code()); // 404 println!("{}", e.http_status_code()); // 404 } ``` -------------------------------- ### Response Trait API Reference Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Reference for the `Response` trait, which defines the interface for API errors. It includes methods for retrieving error codes, module paths, raw and formatted messages, and HTTP status codes. ```rust pub trait Response: Display { /// Returns the error code fn error_code(&self) -> u64; /// Returns the module path (e.g., "auth.login") fn module_path(&self) -> &'static str; /// Returns the raw error message without module prefix fn raw_message(&self) -> String; /// Returns the formatted message with module prefix: "[module] message" fn message(&self) -> String; /// Returns the HTTP status code fn http_status_code(&self) -> u16; } ``` -------------------------------- ### Error Aggregation with AppError Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Shows how to aggregate different error types (like UserError and DbError) into a single AppError enum using #[from] and #[response(transparent)]. ```APIDOC ## Error Aggregation ### AppError Enum ```rust #[derive(Debug, Error, Response)] #[response(module = "app")] pub enum AppError { #[error(transparent)] #[response(transparent)] User(#[from] UserError), #[error(transparent)] #[response(transparent)] Database(#[from] DbError), #[error("Internal error")] #[response(code = 5000, status = 500)] Internal, } ``` ``` -------------------------------- ### Accessing Error Metadata Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Shows how to access metadata from a `Response` error, such as the module path and differentiating between raw and formatted error messages. ```APIDOC ## Advanced Features ### Access Metadata ```rust // Get module path let module = error.module_path(); // "auth.login" // Raw vs Formatted messages error.raw_message() // → "User not found" error.message() // → "[auth.login] User not found" ``` ``` -------------------------------- ### Error Aggregation with AppError Enum Source: https://github.com/zhenglongbing/apiresponse/blob/main/apiresponse-macro/README.md Shows how to aggregate different error types (UserError, DbError) into a single `AppError` enum using the `Response` derive macro, allowing for unified error handling. ```APIDOC ## Error Aggregation ### AppError Enum Definition ```rust #[derive(Debug, Error, Response)] #[response(module = "app")] pub enum AppError { #[error(transparent)] #[response(transparent)] User(#[from] UserError), #[error(transparent)] #[response(transparent)] Database(#[from] DbError), #[error("Internal error")] #[response(code = 5000, status = 500)] Internal, } ``` ``` -------------------------------- ### Enum-level Response Attributes Source: https://context7.com/zhenglongbing/apiresponse/llms.txt Configure module prefixing and base error codes at the enum level. Omitting module disables prefixing; omitting base requires explicit codes for all variants. ```rust use apiresponse::Response; use thiserror::Error; // No module: message() returns raw message without prefix. // No base: every variant must supply an explicit code. #[derive(Debug, Error, Response)] #[response(module = "validation")] pub enum ValidationError { #[error("Invalid email format")] #[response(code = 5001, status = 400)] InvalidEmail, #[error("Insufficient password strength")] #[response(code = 5002, status = 400)] WeakPassword, } // No module attribute at all — module_path() is "" and message() has no prefix. #[derive(Debug, Error, Response)] #[response(base = 6000)] pub enum SimpleError { #[error("Generic error")] GenericError, // code = 6000 #[error("Another error")] #[response(status = 500)] AnotherError, // code = 6001 } fn main() { let e = ValidationError::InvalidEmail; assert_eq!(e.error_code(), 5001); assert_eq!(e.message(), "[validation] Invalid email format"); let s = SimpleError::GenericError; assert_eq!(s.module_path(), ""); assert_eq!(s.message(), "Generic error"); // no prefix assert_eq!(s.error_code(), 6000); } ``` -------------------------------- ### Enum-level Attributes for Response Derive Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Configuration attributes for the `#[response]` derive macro at the enum level. `module` specifies the error module prefix, and `base` sets a base code for variants if not explicitly defined. ```rust #[response(module = "module_name", base = base_code)] // ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ // Optional (default "") Optional (if omitted, variants must specify code) ``` -------------------------------- ### ApiResponse Struct Definition Source: https://github.com/zhenglongbing/apiresponse/blob/main/README.md Defines the `ApiResponse` struct, which is used to create standardized success and error responses, including fields for code, message, data, and HTTP status. ```APIDOC ### ApiResponse Struct ```rust #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ApiResponse { pub code: u64, pub message: String, pub data: serde_json::Value, #[serde(skip)] pub status_code: u16, } ``` Methods: - `ApiResponse::success(data)` - Create success response with data - `ApiResponse::success_with_message(data, message)` - Success with custom message - `ApiResponse::ok()` - Create empty success response ```