Skip to content

Commit 47f7558

Browse files
authored
fix(core): resolve HTTP API on non-ok status code, fix binary response, closes #2046 (#2053)
1 parent c22e5a7 commit 47f7558

File tree

7 files changed

+68
-36
lines changed

7 files changed

+68
-36
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": patch
3+
---
4+
5+
Fixes the HTTP API binary response serialization.

.changes/fix-http-resolve-error.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"tauri": patch
3+
"api": patch
4+
---
5+
6+
The `http` APIs now resolve the returned promise when the API call finishes with an error status code.

.changes/http-error-message.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

core/tauri/scripts/bundle.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/tauri/src/api/error.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,6 @@ pub enum Error {
3232
#[cfg(feature = "reqwest-client")]
3333
#[error("Network Error: {0}")]
3434
Network(#[from] reqwest::Error),
35-
/// HTTP request error. First parameter is the response status code, and the second is the response text.
36-
#[error("HTTP Error: status code {0} and response `{1}`")]
37-
Http(u16, String),
3835
/// HTTP method error.
3936
#[error("{0}")]
4037
HttpMethod(#[from] http::method::InvalidMethod),

core/tauri/src/api/http.rs

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -118,18 +118,11 @@ impl Client {
118118
request_builder.send()?
119119
};
120120

121-
if response.is_success() {
122-
Ok(Response(
123-
request.response_type.unwrap_or(ResponseType::Json),
124-
response,
125-
request.url,
126-
))
127-
} else {
128-
Err(super::Error::Http(
129-
response.status().as_u16(),
130-
response.text()?,
131-
))
132-
}
121+
Ok(Response(
122+
request.response_type.unwrap_or(ResponseType::Json),
123+
response,
124+
request.url,
125+
))
133126
}
134127
}
135128

@@ -183,17 +176,10 @@ impl Client {
183176

184177
let response = self.0.execute(http_request).await?;
185178

186-
if response.status().is_success() {
187-
Ok(Response(
188-
request.response_type.unwrap_or(ResponseType::Json),
189-
response,
190-
))
191-
} else {
192-
Err(super::Error::Http(
193-
response.status().as_u16(),
194-
response.text().await?,
195-
))
196-
}
179+
Ok(Response(
180+
request.response_type.unwrap_or(ResponseType::Json),
181+
response,
182+
))
197183
}
198184
}
199185

@@ -368,14 +354,14 @@ impl Response {
368354
let data = match self.0 {
369355
ResponseType::Json => self.1.json().await?,
370356
ResponseType::Text => Value::String(self.1.text().await?),
371-
ResponseType::Binary => Value::String(serde_json::to_string(&self.1.bytes().await?)?),
357+
ResponseType::Binary => serde_json::to_value(&self.1.bytes().await?)?,
372358
};
373359

374360
#[cfg(not(feature = "reqwest-client"))]
375361
let data = match self.0 {
376362
ResponseType::Json => self.1.json()?,
377363
ResponseType::Text => Value::String(self.1.text()?),
378-
ResponseType::Binary => Value::String(serde_json::to_string(&self.1.bytes()?)?),
364+
ResponseType::Binary => serde_json::to_value(&self.1.bytes()?)?,
379365
};
380366

381367
Ok(ResponseData {

tooling/api/src/http.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,16 +123,35 @@ type RequestOptions = Omit<HttpOptions, 'method' | 'url'>
123123
/** Options for the `fetch` API. */
124124
type FetchOptions = Omit<HttpOptions, 'url'>
125125

126+
/** @ignore */
127+
interface IResponse<T> {
128+
url: string
129+
status: number
130+
headers: Record<string, string>
131+
data: T
132+
}
133+
126134
/** Response object. */
127-
interface Response<T> {
135+
class Response<T> {
128136
/** The request URL. */
129137
url: string
130138
/** The response status code. */
131139
status: number
140+
/** A boolean indicating whether the response was successful (status in the range 200–299) or not. */
141+
ok: boolean
132142
/** The response headers. */
133143
headers: Record<string, string>
134144
/** The response data. */
135145
data: T
146+
147+
/** @ignore */
148+
constructor(response: IResponse<T>) {
149+
this.url = response.url
150+
this.status = response.status
151+
this.ok = this.status >= 200 && this.status < 300
152+
this.headers = response.headers
153+
this.data = response.data
154+
}
136155
}
137156

138157
class Client {
@@ -164,13 +183,37 @@ class Client {
164183
* @returns A promise resolving to the response.
165184
*/
166185
async request<T>(options: HttpOptions): Promise<Response<T>> {
167-
return invokeTauriCommand({
186+
const jsonResponse =
187+
!options.responseType || options.responseType === ResponseType.JSON
188+
if (jsonResponse) {
189+
options.responseType = ResponseType.Text
190+
}
191+
return invokeTauriCommand<IResponse<T>>({
168192
__tauriModule: 'Http',
169193
message: {
170194
cmd: 'httpRequest',
171195
client: this.id,
172196
options
173197
}
198+
}).then((res) => {
199+
const response = new Response(res)
200+
if (jsonResponse) {
201+
/* eslint-disable */
202+
try {
203+
// @ts-expect-error
204+
response.data = JSON.parse(response.data as string)
205+
} catch (e) {
206+
if (response.ok) {
207+
throw Error(
208+
`Failed to parse response \`${response.data}\` as JSON: ${e};
209+
try setting the \`responseType\` option to \`ResponseType.Text\` or \`ResponseType.Binary\` if the API does not return a JSON response.`
210+
)
211+
}
212+
}
213+
/* eslint-enable */
214+
return response
215+
}
216+
return response
174217
})
175218
}
176219

0 commit comments

Comments
 (0)