// Copyright (C) 2024 Riften Labs AS // // This software is licensed under the GNU Affero General Public License (AGPL), version 3.0 or later. // A copy of the license can be found in the LICENSE file or at https://www.gnu.org/licenses/agpl-3.0.html use rocket::{http::Status, response::status::Custom, serde::json::Json}; use serde_json::{json, Value}; use std::fmt; use super::response::CachedJson; /// Standard API result type with JSON-formatted errors (without caching headers) #[allow(dead_code)] pub type ApiResult = Result, Custom>>; /// API result type with Cache-Control headers for cacheable responses pub type CachedApiResult = Result, Custom>>; /// API error codes for consistent error responses #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ApiErrorCode { // 400 Bad Request codes InvalidTimestamp, InvalidTokenId, InvalidPoolId, InvalidTxid, InvalidParameters, InvalidTimeRange, InvalidStepsize, MissingParameters, MissingCategory, TooManyIntervals, FutureTimestamp, // 404 Not Found codes PriceNotFound, PoolNotFound, // 500 Internal Server Error codes InternalError, // 503 Service Unavailable codes CacheWarming, } impl fmt::Display for ApiErrorCode { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { // 400 codes Self::InvalidTimestamp => "INVALID_TIMESTAMP", Self::InvalidTokenId => "INVALID_TOKEN_ID", Self::InvalidPoolId => "INVALID_POOL_ID", Self::InvalidTxid => "INVALID_TXID", Self::InvalidParameters => "INVALID_PARAMETERS", Self::InvalidTimeRange => "INVALID_TIME_RANGE", Self::InvalidStepsize => "INVALID_STEPSIZE", Self::MissingParameters => "MISSING_PARAMETERS", Self::MissingCategory => "MISSING_CATEGORY", Self::TooManyIntervals => "TOO_MANY_INTERVALS", Self::FutureTimestamp => "FUTURE_TIMESTAMP", // 404 codes Self::PriceNotFound => "PRICE_NOT_FOUND", Self::PoolNotFound => "POOL_NOT_FOUND", // 500 codes Self::InternalError => "INTERNAL_ERROR", // 503 codes Self::CacheWarming => "CACHE_WARMING", }; write!(f, "{s}") } } /// Create a 400 Bad Request error with JSON body pub fn bad_request(code: ApiErrorCode, message: &str) -> Custom> { Custom( Status::BadRequest, Json(json!({ "error": { "code": code.to_string(), "message": message } })), ) } /// Create a 404 Not Found error with JSON body pub fn not_found(code: ApiErrorCode, message: &str) -> Custom> { Custom( Status::NotFound, Json(json!({ "error": { "code": code.to_string(), "message": message } })), ) } /// Create a 500 Internal Server Error with JSON body pub fn internal_error(message: &str) -> Custom> { Custom( Status::InternalServerError, Json(json!({ "error": { "code": ApiErrorCode::InternalError.to_string(), "message": message } })), ) } /// Create a 500 Internal Server Error for database errors with JSON body pub fn db_error(e: E) -> Custom> { internal_error(&format!("Database error: {e}")) } /// Create a 503 Service Unavailable error with JSON body pub fn service_unavailable(code: ApiErrorCode, message: &str) -> Custom> { Custom( Status::ServiceUnavailable, Json(json!({ "error": { "code": code.to_string(), "message": message } })), ) } // Legacy helper for backward compatibility during migration pub fn to_internal_error(e: E) -> Custom { Custom(Status::InternalServerError, format!("Error: {e}")) }