Skip to content

Commit d64ebf0

Browse files
committed
feat: add helper method to parse raw error into custom type
1 parent 244eeca commit d64ebf0

File tree

4 files changed

+28
-6
lines changed

4 files changed

+28
-6
lines changed

async-openai/src/client.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ async fn read_response(response: Response) -> Result<Bytes, OpenAIError> {
523523
#[cfg(feature = "string-errors")]
524524
{
525525
let message: String = String::from_utf8_lossy(&bytes).into_owned();
526-
return Err(OpenAIError::ApiError(message));
526+
return Err(OpenAIError::ApiError(crate::error::RawApiError(message)));
527527
}
528528
}
529529

async-openai/src/error.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,28 @@
22
33
use serde::{Deserialize, Serialize};
44

5+
/// Raw API error string from providers with custom error formats
6+
///
7+
/// Only available with the `string-errors` feature.
8+
#[cfg(feature = "string-errors")]
9+
#[derive(Debug, Clone)]
10+
pub struct RawApiError(pub String);
11+
12+
#[cfg(feature = "string-errors")]
13+
impl std::fmt::Display for RawApiError {
14+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15+
write!(f, "{}", self.0)
16+
}
17+
}
18+
19+
#[cfg(feature = "string-errors")]
20+
impl RawApiError {
21+
/// Parse the raw error string into a custom type
22+
pub fn parse<T: serde::de::DeserializeOwned>(&self) -> Result<T, serde_json::Error> {
23+
serde_json::from_str(&self.0)
24+
}
25+
}
26+
527
#[derive(Debug, thiserror::Error)]
628
pub enum OpenAIError {
729
/// Underlying error from reqwest library after an API call was made
@@ -15,7 +37,7 @@ pub enum OpenAIError {
1537
/// This feature leaves deserialization to the user, not even assuming json.
1638
#[cfg(feature = "string-errors")]
1739
#[error("{0}")]
18-
ApiError(String),
40+
ApiError(RawApiError),
1941
/// Error when a response cannot be deserialized into a Rust type
2042
#[error("failed to deserialize api response: error:{0} content:{1}")]
2143
JSONDeserialize(serde_json::Error, String),

async-openai/tests/string-errors.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ async fn test_byot_errors() {
1212
let _r: Result<Value, OpenAIError> = client.chat().create_byot(json!({})).await;
1313

1414
match _r.unwrap_err() {
15-
OpenAIError::ApiError(value) => {
16-
let _value = serde_json::from_str::<Value>(&value).unwrap();
15+
OpenAIError::ApiError(raw_error) => {
16+
let _value: Value = raw_error.parse().unwrap();
1717
}
1818
_ => {}
1919
};

examples/string-errors/src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
3030
.await;
3131

3232
match result.unwrap_err() {
33-
OpenAIError::ApiError(error_string) => {
34-
let error = serde_json::from_str::<ErrorWrapper>(&error_string).unwrap();
33+
OpenAIError::ApiError(raw_error) => {
34+
let error: ErrorWrapper = raw_error.parse().unwrap();
3535
println!("Code: {}", error.error.code);
3636
println!("Message: {}", error.error.message);
3737
}

0 commit comments

Comments
 (0)