Skip to content

Commit 6a55f6b

Browse files
committed
Refactor error parsing to no longer include response on all errors
It only includes the response on errors when it can't parse the json. And it includes the original response now, not a POJO.
1 parent ed9cb99 commit 6a55f6b

File tree

7 files changed

+183
-222
lines changed

7 files changed

+183
-222
lines changed

README.md

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -234,36 +234,6 @@ const MyBanana = ({ id, authToken = "mytoken" }) => {
234234

235235
This will make a `GET` request adding an `Authorization` header with the value `Bearer mytoken`. `bearerToken` can also be a `Promise`, a `function`, or a `function` that returns a `Promise` (an `async function`) and the hook will wait for the `bearerToken` to resolve before making the request.
236236

237-
## Utility Functions
238-
239-
The package includes some other utility functions that can be used outside the context of a hook.
240-
241-
### `checkStatus(response)`
242-
243-
[Read here](https://github.com/github/fetch#handling-http-error-statuses) for the inspiration for this function. It will reject fetch requests on any non-2xx response. It differs from the example in that it will try to parse a JSON body from the non-200 response and will set any `message` field (if it exists) from the JSON body as the error message. The fetch hooks use this internally.
244-
245-
```js
246-
import { checkStatus } from "react-fetch-hooks";
247-
248-
//given a 400 Bad Request response with a JSON body of:
249-
//{ "message": "Invalid arguments. Try again.", "someOtherThing": 42 }
250-
251-
fetch("/data", {
252-
method: "GET",
253-
headers: {
254-
Accept: "application/json"
255-
}
256-
})
257-
.then(checkStatus)
258-
.catch(err => {
259-
console.log(err.message); //Invalid Arguments. Try again.
260-
console.log(err.response.statusText); //Bad Request
261-
console.log(err.response.jsonBody); //{ "message": "Invalid arguments. Try again.", "someOtherThing": 42 }
262-
});
263-
```
264-
265-
It will try to look for a `message` field first, and then an `exceptionMessage` falling back to the `statusText` if neither one exist or if the response body is not JSON.
266-
267237
## Build/Run Locally
268238

269239
After cloning this repo, run:

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-fetch-hooks",
3-
"version": "2.4.0",
3+
"version": "3.0.0",
44
"description": "A set of react hooks to work with the fetch API and gracefully parse & deal with HTTP errors",
55
"keywords": [
66
"react",

src/check-status.js

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

src/fetch-fn.js

Lines changed: 54 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useCallback } from "react";
2-
import checkStatus from "./check-status";
32
import { isFunction } from "lodash";
43
import pojoHeaders from "./pojo-headers";
4+
import extractErrorMessage from "./extract-error-message";
55

66
const useFetchFn = ({
77
refreshInterval,
@@ -23,34 +23,40 @@ const useFetchFn = ({
2323
}
2424

2525
async function doFetch() {
26-
let _headers, _body, _status, _statusText;
26+
let response, headers, body, status, statusText;
2727

2828
try {
2929
const parsedOpts = await prepareHeaders(opts, reqBody);
3030

31-
let _response = await fetch(url, parsedOpts);
32-
_headers = pojoHeaders(_response.headers);
33-
_status = _response.status;
34-
_statusText = _response.statusText;
35-
36-
_response = await checkStatus(_response);
37-
38-
if (_status != 204) {
39-
_body = await _response.json();
31+
response = await fetch(url, parsedOpts);
32+
33+
headers = pojoHeaders(response.headers);
34+
status = response.status;
35+
statusText = response.statusText;
36+
37+
const isSuccessful = response.status >= 200 && response.status < 300;
38+
39+
if (isSuccessful) {
40+
if (status != 204) {
41+
body = await response.json();
42+
} else {
43+
// for 204 No Content, just return null data
44+
body = null;
45+
}
46+
47+
onFetchResults({
48+
body: body,
49+
headers: headers,
50+
status: status,
51+
statusText: statusText,
52+
timer: resetDelay || refreshInterval
53+
});
4054
} else {
41-
// for 204 No Content, just return null data
42-
_body = null;
55+
const parsedResult = await parseJSONError(response);
56+
onFetchFail({ ...parsedResult, headers, status, statusText });
4357
}
44-
45-
onFetchResults({
46-
body: _body,
47-
headers: _headers,
48-
status: _status,
49-
statusText: _statusText,
50-
timer: resetDelay || refreshInterval
51-
});
5258
} catch (ex) {
53-
onFetchFail(ex);
59+
onFetchFail({ error: ex, body, headers, status, statusText });
5460
}
5561
}
5662
},
@@ -59,6 +65,32 @@ const useFetchFn = ({
5965
[refreshInterval, resetDelay, url, JSON.stringify(opts)] // eslint-disable-line react-hooks/exhaustive-deps
6066
);
6167

68+
async function parseJSONError(response) {
69+
let body;
70+
71+
try {
72+
body = await response.json();
73+
} catch {
74+
// there was an error trying to parse the JSON body (maybe it's not JSON?)
75+
// just ignore it and return an error with the original response without a parsed body
76+
let error = new Error(
77+
response.statusText ||
78+
`Request failed with status code ${response.status}`
79+
);
80+
81+
error.response = response;
82+
return { error };
83+
}
84+
85+
let msg = extractErrorMessage(body);
86+
if (!msg) msg = response.statusText;
87+
88+
let error = new Error(msg);
89+
error.response = response;
90+
91+
return { error, body };
92+
}
93+
6294
async function prepareHeaders(itemToFetch, reqBody) {
6395
let { bearerToken, ...opts } = itemToFetch || {};
6496

src/index.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
export checkStatus from "./check-status";
21
export useFetch from "./use-fetch";
32
export useLazyFetch from "./lazy-fetch";
43
export extractErrorMessage from "./extract-error-message";

src/request-state.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,11 @@ const useRequestInitialState = () => {
5151
return {
5252
...state,
5353
isFetching: false,
54-
error: action.payload,
55-
headers: action.payload?.response?.headers,
56-
body: action.payload?.response?.body,
57-
status: action.payload?.response?.status,
58-
statusText: action.payload?.response?.statusText
54+
error: action.payload.error,
55+
headers: action.payload.headers,
56+
body: action.payload.body,
57+
status: action.payload.status,
58+
statusText: action.payload.statusText
5959
};
6060

6161
case "reset":

0 commit comments

Comments
 (0)