Skip to content

Commit 66a52cb

Browse files
committed
Use strong json Value types with serde_json
Hand rolling strings is simple, but serde_json is already a dependency and is more robust.
1 parent 2de6e18 commit 66a52cb

File tree

3 files changed

+40
-40
lines changed

3 files changed

+40
-40
lines changed

payjoin/src/receive/error.rs

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -77,28 +77,30 @@ pub struct JsonReply {
7777
error_code: ErrorCode,
7878
/// The error message to be displayed only in debug logs
7979
message: String,
80-
/// Additional fields to be added to the JSON
81-
additional_fields: Vec<String>,
80+
/// Additional fields to be included in the JSON response
81+
extra: serde_json::Map<String, serde_json::Value>,
8282
}
8383

8484
impl JsonReply {
8585
/// Create a new Reply
8686
pub fn new(error_code: ErrorCode, message: impl fmt::Display) -> Self {
87-
Self { error_code, message: message.to_string(), additional_fields: vec![] }
87+
Self { error_code, message: message.to_string(), extra: serde_json::Map::new() }
88+
}
89+
90+
/// Add an additional field to the JSON response
91+
pub fn with_extra(mut self, key: &str, value: impl Into<serde_json::Value>) -> Self {
92+
self.extra.insert(key.to_string(), value.into());
93+
self
8894
}
8995

9096
/// Serialize the Reply to a JSON string
91-
pub fn to_json(&self) -> String {
92-
if self.additional_fields.is_empty() {
93-
format!(r#"{{ "errorCode": "{}", "message": "{}" }}"#, self.error_code, self.message)
94-
} else {
95-
format!(
96-
r#"{{ "errorCode": "{}", "message": "{}", {} }}"#,
97-
self.error_code,
98-
self.message,
99-
self.additional_fields.join(", ")
100-
)
101-
}
97+
pub fn to_json(&self) -> serde_json::Value {
98+
let mut map = serde_json::Map::new();
99+
map.insert("errorCode".to_string(), self.error_code.to_string().into());
100+
map.insert("message".to_string(), self.message.clone().into());
101+
map.extend(self.extra.clone());
102+
103+
serde_json::Value::Object(map)
102104
}
103105
}
104106

@@ -205,14 +207,8 @@ impl From<&PayloadError> for JsonReply {
205207
super::optional_parameters::Error::UnknownVersion { supported_versions } => {
206208
let supported_versions_json =
207209
serde_json::to_string(supported_versions).unwrap_or_default();
208-
JsonReply {
209-
error_code: VersionUnsupported,
210-
message: "This version of payjoin is not supported.".to_string(),
211-
additional_fields: vec![format!(
212-
r#""supported": {}"#,
213-
supported_versions_json
214-
)],
215-
}
210+
JsonReply::new(VersionUnsupported, "This version of payjoin is not supported.")
211+
.with_extra("supported", supported_versions_json)
216212
}
217213
_ => JsonReply::new(OriginalPsbtRejected, e),
218214
},

payjoin/src/receive/v2/mod.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ impl UncheckedProposal {
286286
&mut self.context.ohttp_keys,
287287
"POST",
288288
subdir.as_str(),
289-
Some(JsonReply::from(err).to_json().as_bytes()),
289+
Some(JsonReply::from(err).to_json().to_string().as_bytes()),
290290
)
291291
.map_err(InternalSessionError::OhttpEncapsulation)?;
292292
let req = Request::new_v2(&self.context.full_relay_url(ohttp_relay)?, &body);
@@ -625,10 +625,12 @@ mod test {
625625
.check_broadcast_suitability(None, |_| Err("mock error".into()))
626626
.err()
627627
.ok_or("expected error but got success")?;
628-
assert_eq!(
629-
JsonReply::from(&server_error).to_json(),
630-
r#"{ "errorCode": "unavailable", "message": "Receiver error" }"#
631-
);
628+
let expected_json = serde_json::json!({
629+
"errorCode": "unavailable",
630+
"message": "Receiver error"
631+
});
632+
let actual_json = JsonReply::from(&server_error).to_json();
633+
assert_eq!(actual_json, expected_json);
632634
let (_req, _ctx) = proposal.clone().extract_err_req(&server_error, &*EXAMPLE_URL)?;
633635

634636
let internal_error = InternalPayloadError::MissingPayment.into();

payjoin/src/send/error.rs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -344,20 +344,22 @@ impl Display for ResponseError {
344344
impl fmt::Debug for ResponseError {
345345
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
346346
match self {
347-
Self::WellKnown(e) => write!(
348-
f,
349-
r#"Well known error: {{ "errorCode": "{}",
350-
"message": "{}" }}"#,
351-
e.error_code(),
352-
e.message()
353-
),
347+
Self::WellKnown(e) => {
348+
let json = serde_json::json!({
349+
"errorCode": e.error_code().to_string(),
350+
"message": e.message()
351+
});
352+
write!(f, "Well known error: {}", json)
353+
}
354354
Self::Validation(e) => write!(f, "Validation({:?})", e),
355355

356-
Self::Unrecognized { error_code, message } => write!(
357-
f,
358-
r#"Unrecognized error: {{ "errorCode": "{}", "message": "{}" }}"#,
359-
error_code, message
360-
),
356+
Self::Unrecognized { error_code, message } => {
357+
let json = serde_json::json!({
358+
"errorCode": error_code,
359+
"message": message
360+
});
361+
write!(f, "Unrecognized error: {}", json)
362+
}
361363
}
362364
}
363365
}
@@ -403,7 +405,7 @@ impl Display for WellKnownError {
403405

404406
#[cfg(test)]
405407
mod tests {
406-
use bitcoind::bitcoincore_rpc::jsonrpc::serde_json::json;
408+
use serde_json::json;
407409

408410
use super::*;
409411

0 commit comments

Comments
 (0)