Skip to content

Commit

Permalink
Integrate with risk provider with error handling and unit tests (#139)
Browse files Browse the repository at this point in the history
* Integrate with risk provider with error handling and unit tests

* Use workspace dependencies for common crates

* CRC: Clippy warning fixes + add reason field to BlocklistStatus

* CRC: make data mapping consistent with RiskSeverity enum, remove unnecessary intermediate struct: RiskResponse

* Add newline

---------

Co-authored-by: Marzi <marzi@trustmachines.co>
  • Loading branch information
8marz8 and Marzi committed May 13, 2024
1 parent 4c7941c commit 2e0b623
Show file tree
Hide file tree
Showing 8 changed files with 692 additions and 85 deletions.
205 changes: 188 additions & 17 deletions Cargo.lock

Large diffs are not rendered by default.

23 changes: 12 additions & 11 deletions blocklist-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,19 @@ path = "src/main.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
warp = "0.3"
tokio = { version = "1", features = ["rt-multi-thread", "rt", "macros"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
reqwest = { version = "0.11", features = ["json"] }
config = "0.11"
once_cell = "1.8.0"
reqwest = { version = "0.11", features = ["json"] }
sbtc-signer = { path = "../signer" }
tracing = { version = "0.1", default-features = false }
tracing-attributes = "0.1"
serde.workspace = true
serde_json.workspace = true
thiserror.workspace = true
tokio = { version = "1.32.0", features = ["rt-multi-thread", "rt", "macros"] }
tracing.workspace = true
tracing-attributes.workspace = true
tracing-subscriber = { version = "0.3", default-features = false, features = ["env-filter", "fmt", "json", "time"] }
warp = "0.3"

[dev-dependencies]
mockito = "0.28"

[dependencies.tracing-subscriber]
version = "0.3"
default-features = false
features = ["env-filter", "fmt", "json", "time"]
72 changes: 47 additions & 25 deletions blocklist-client/src/api/handlers.rs
Original file line number Diff line number Diff line change
@@ -1,42 +1,64 @@
use crate::client;
use crate::common::{Error, ErrorResponse};
use crate::client::risk_client;
use crate::common::error::{Error, ErrorResponse};
use crate::config::RiskAnalysisConfig;
use reqwest::Client;
use std::convert::Infallible;
use tracing::error;

use warp::{http::StatusCode, Rejection, Reply};

/// Handles requests to check the blocklist status of a given address.
/// Converts successful blocklist status results to JSON and returns them,
/// or converts errors into Warp rejections.
pub async fn check_address_handler(
address: String,
client: Client,
config: RiskAnalysisConfig,
) -> Result<impl Reply, Rejection> {
match client::check_address(client, &config, &address).await {
Ok(value) => Ok(warp::reply::json(&value)),
Err(_) => Err(warp::reject::custom(Error::AddressNotFound)),
}
risk_client::check_address(&client, &config, &address)
.await
.map(|blocklist_status| warp::reply::json(&blocklist_status))
.map_err(warp::reject::custom)
}

/// Central error handler for Warp rejections, converting them to appropriate HTTP responses.
pub async fn handle_rejection(err: Rejection) -> Result<impl Reply, Infallible> {
let (code, message) = if err.is_not_found() {
(StatusCode::NOT_FOUND, "Not Found")
} else if err
.find::<warp::filters::body::BodyDeserializeError>()
.is_some()
{
(StatusCode::BAD_REQUEST, "Invalid Body")
} else if let Some(e) = err.find::<Error>() {
error!("Unhandled application error: {:?}", e);
(StatusCode::INTERNAL_SERVER_ERROR, "Internal Server Error")
} else if err.find::<warp::reject::MethodNotAllowed>().is_some() {
(StatusCode::METHOD_NOT_ALLOWED, "Method Not Allowed")
} else {
error!("Unhandled error: {:?}", err);
(StatusCode::INTERNAL_SERVER_ERROR, "Internal Server Error")
};
if err.is_not_found() {
let json = warp::reply::json(&ErrorResponse {
message: "Not Found".to_string(),
});
return Ok(warp::reply::with_status(json, StatusCode::NOT_FOUND));
}

if let Some(e) = err.find::<warp::filters::body::BodyDeserializeError>() {
let json = warp::reply::json(&ErrorResponse {
message: format!("Invalid Body: {}", e),
});
return Ok(warp::reply::with_status(json, StatusCode::BAD_REQUEST));
}

if let Some(e) = err.find::<Error>() {
// Custom application errors
let (code, message) = e.as_http_response();
let json = warp::reply::json(&ErrorResponse { message });
return Ok(warp::reply::with_status(json, code));
}

let json = warp::reply::json(&ErrorResponse { message: message.to_string() });
if err.find::<warp::reject::MethodNotAllowed>().is_some() {
let json = warp::reply::json(&ErrorResponse {
message: "Method Not Allowed".to_string(),
});
return Ok(warp::reply::with_status(
json,
StatusCode::METHOD_NOT_ALLOWED,
));
}

Ok(warp::reply::with_status(json, code))
error!("Unhandled error: {:?}", err);
let json = warp::reply::json(&ErrorResponse {
message: "Internal Server Error".to_string(),
});
Ok(warp::reply::with_status(
json,
StatusCode::INTERNAL_SERVER_ERROR,
))
}
20 changes: 0 additions & 20 deletions blocklist-client/src/client.rs

This file was deleted.

1 change: 1 addition & 0 deletions blocklist-client/src/client/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod risk_client;

0 comments on commit 2e0b623

Please sign in to comment.