Skip to content

Commit

Permalink
🏭 Parse error type as json on proper content-type
Browse files Browse the repository at this point in the history
Should solve #171
  • Loading branch information
elbywan committed Feb 20, 2023
1 parent 1439d44 commit ea9adbf
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 12 deletions.
2 changes: 2 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ export function setPolyfills(polyfills: object, replace = false) {
* Sets the default method (text, json, …) used to parse the data contained in the response body in case of an HTTP error.
* As with other static methods, it will affect wretch instances created after calling this function.
*
* _Note: if the response Content-Type header is set to "application/json", the body will be parsed as json regardless of the errorType._
*
* ```js
* import wretch from "wretch"
*
Expand Down
9 changes: 6 additions & 3 deletions src/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const resolver = <T, Chain, R>(wretch: T & Wretch<T, Chain, R>) => {
addon.beforeRequest &&
addon.beforeRequest(w, wretch._options, sharedState)
|| w,
wretch)
wretch)

const {
_url: url,
Expand Down Expand Up @@ -60,9 +60,12 @@ export const resolver = <T, Chain, R>(wretch: T & Wretch<T, Chain, R>) => {
if (response.type === "opaque") {
throw err
}
return response[config.errorType]().then((body: string) => {
return response.text().then((body: string) => {
err.message = body
err[config.errorType] = body
if (config.errorType === "json" || response.headers.get("Content-Type").split(";")[0] === "application/json") {
try { err.json = JSON.parse(body) } catch (e) { /* ignore */ }
}
err.text = body
err["status"] = response.status
throw err
})
Expand Down
4 changes: 3 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ export interface Wretch<Self = unknown, Chain = unknown, Resolver = undefined> {
* Sets the method (text, json ...) used to parse the data contained in the
* response body in case of an HTTP error is returned.
*
* _Note: if the response Content-Type header is set to "application/json", the body will be parsed as json regardless of the errorType._
*
* ```js
* wretch("http://server/which/returns/an/error/with/a/json/body")
* .errorType("json")
Expand Down Expand Up @@ -762,7 +764,7 @@ export type FetchLike = (url: string, opts: WretchOptions) => Promise<WretchResp
* An addon enhancing either the request or response chain (or both).
*/
export type WretchAddon<W extends unknown, R extends unknown = unknown> = {
beforeRequest?<T, C, R>(wretch: T & Wretch<T, C, R>, options: WretchOptions, state : Record<any, any>): T & Wretch<T, C, R>,
beforeRequest?<T, C, R>(wretch: T & Wretch<T, C, R>, options: WretchOptions, state: Record<any, any>): T & Wretch<T, C, R>,
wretch?: W,
resolver?: R
}
Expand Down
4 changes: 2 additions & 2 deletions test/browser/wretch.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -333,13 +333,13 @@ describe("Wretch", function () {
})

it("should change the parsing used in the default error handler", async function () {
await wretch(`${_URL}/json500`)
await wretch(`${_URL}/json500raw`)
.get()
.internalError(error => { expect(error.text).toEqual(`{"error":500,"message":"ok"}`) })
.res(_ => fail("I should never be called because an error was thrown"))
.then(_ => expect(_).toBe(undefined))
wretch.errorType("json")
await wretch(`${_URL}/json500`)
await wretch(`${_URL}/json500raw`)
.get()
.internalError(error => { expect(error.json).toEqual({ error: 500, message: "ok" }) })
.res(_ => fail("I should never be called because an error was thrown"))
Expand Down
5 changes: 5 additions & 0 deletions test/mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,11 @@ export function launch(port) {
return { error: 500, message: "ok" }
})

server.get("/json500raw", async (request, reply) => {
reply.status(500)
return JSON.stringify({ error: 500, message: "ok" })
})

server.get("/longResult", async () => {
await delay(1000)
return "ok"
Expand Down
29 changes: 23 additions & 6 deletions test/node/wretch.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -464,26 +464,43 @@ describe("Wretch", function () {

it("should change the parsing used in the default error handler", async function () {
// Local
await wretch(`${_URL}/json500`)
await wretch(`${_URL}/json500raw`)
.errorType("json")
.get()
.internalError(error => { expect(error.json).toEqual({ error: 500, message: "ok" }) })
.internalError(error => {
expect(error.json).toEqual({ error: 500, message: "ok" })
expect(error.text).toEqual(JSON.stringify({ error: 500, message: "ok" }))
})
.res(_ => fail("I should never be called because an error was thrown"))
.then(_ => expect(_).toBe(undefined))
// Default (text)
await wretch(`${_URL}/json500raw`)
.get()
.internalError(error => {
expect(error.text).toEqual(`{"error":500,"message":"ok"}`)
expect(error.json).toBeUndefined()
})
.res(_ => fail("I should never be called because an error was thrown"))
.then(_ => expect(_).toBe(undefined))
// Based on content-type
await wretch(`${_URL}/json500`)
.get()
.internalError(error => { expect(error.text).toEqual(`{"error":500,"message":"ok"}`) })
.internalError(error => {
expect(error.text).toEqual(`{"error":500,"message":"ok"}`)
expect(error.json).toEqual({ error: 500, message: "ok" })
})
.res(_ => fail("I should never be called because an error was thrown"))
.then(_ => expect(_).toBe(undefined))
// Global
wretch.errorType("json")
await wretch(`${_URL}/json500`)
await wretch(`${_URL}/json500raw`)
.get()
.internalError(error => { expect(error.json).toEqual({ error: 500, message: "ok" }) })
.internalError(error => {
expect(error.json).toEqual({ error: 500, message: "ok" })
expect(error.text).toEqual(JSON.stringify({ error: 500, message: "ok" }))
})
.res(_ => fail("I should never be called because an error was thrown"))
.then(_ => expect(_).toBe(undefined))

})

it("should retrieve performance timings associated with a fetch request", function (done) {
Expand Down

0 comments on commit ea9adbf

Please sign in to comment.