Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ All notable changes to this project are documented in this file.
## UNRELEASED

- Added: Further tests
- Added: `headers` argument.

## 0.4.0

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ const PeopleSearch = () = {
- `url` : Required - A URL to request data from.
- `pollInterval` : Optional - How often to re-request updated data. Pass 0 to disable polling (the default behaviour).
- `payload` : Optional - A data object to send with the request. If we are performing a GET request, it is appended into the querystring (e.g. `?keywords=hello`). If it is a POST request it is sent in the request body as JSON.
- `headers` : Optional - A data object containing http headers to send with the request. This must be a simple object with key value pairs like `{ authorization: "Bearer abc" }`.
- `method` : Optional - Set the request type, either `get` or `post`. (defaults to `get`)
- `changed` : Optional - A function that is called if the data actually changed during the request. If this is specified, use-api does extra checking and compares old and new data. If data does not change, new data is not propagated and a redraw is saved. Please note, this may have performance repercussions if the data is large as it performs a deep comparison between new and old data to determine if they are equivalent.

Expand Down
12 changes: 11 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const useApi = ({
pollInterval = 0,
payload,
method = "get",
headers,
changed
}) => {
const [data, setData] = useState({});
Expand All @@ -18,6 +19,7 @@ const useApi = ({
const lastData = useRef(data);
const changedRef = useRef(changed);
const payloadRef = useRef(payload);
const headersRef = useRef(headers);
changedRef.current = changed;

if (!url) {
Expand All @@ -38,6 +40,12 @@ const useApi = ({
}
const currentPayload = payloadRef.current;

// Only apply the new headers if its really changed
if (!isEqual(headers, headersRef.current)) {
headersRef.current = headers;
}
const currentHeaders = headersRef.current;

if (method.toLowerCase) method = method.toLowerCase();

if (!["get", "post"].includes(method)) {
Expand All @@ -64,7 +72,8 @@ const useApi = ({
...(currentPayload &&
(method === "get"
? { params: currentPayload }
: { data: currentPayload }))
: { data: currentPayload })),
...(currentHeaders && { headers: currentHeaders })
})
.then(response => {
// Make sure there are no errors reported
Expand Down Expand Up @@ -106,6 +115,7 @@ const useApi = ({
url,
pollInterval,
currentPayload,
currentHeaders,
method,
lastData,
changedRef
Expand Down
88 changes: 88 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -475,4 +475,92 @@ describe("performs requests", () => {
expect(result.current.data).toEqual("response");
expect(result.current.loading).toBeFalsy();
});

it("supports custom http headers via POST", async () => {
const headers = { authorization: `Bearer abc` };

mock.onPost(url).reply(config => {
if (config.headers.authorization === headers.authorization) {
return [200, "response"];
} else {
return [401, "missing header"];
}
});

const { result, waitForNextUpdate } = renderHook(() =>
useApi({ url, headers, method: "post" })
);

expect(result.current.data).toEqual({});
expect(result.current.loading).toBeTruthy();

await waitForNextUpdate();

expect(result.current.data).toEqual("response");
expect(result.current.loading).toBeFalsy();
});

it("supports custom http headers via GET", async () => {
const headers = { authorization: `Bearer abc` };

mock.onGet(url).reply(config => {
if (config.headers.authorization === headers.authorization) {
return [200, "response"];
} else {
return [401, "missing header"];
}
});

const { result, waitForNextUpdate } = renderHook(() =>
useApi({ url, headers })
);

expect(result.current.data).toEqual({});
expect(result.current.loading).toBeTruthy();

await waitForNextUpdate();

expect(result.current.data).toEqual("response");
expect(result.current.loading).toBeFalsy();
});

it("refreshes when headers changes", async () => {
const headers = { authorization: `Bearer abc` };
const headers2 = { authorization: `Bearer def` };

mock.onGet(url).reply(config => {
if (config.headers.authorization === headers.authorization) {
return [200, "response"];
} else if (config.headers.authorization === headers2.authorization) {
return [200, "response2"];
} else {
return [401, "missing header"];
}
});

const { result, waitForNextUpdate, rerender } = renderHook(
props => useApi(props),
{
initialProps: {
url,
headers
}
}
);

await waitForNextUpdate();

expect(result.current.data).toEqual("response");
expect(result.current.loading).toBeFalsy();

rerender({
url,
headers: headers2
});

await waitForNextUpdate();

expect(result.current.data).toEqual("response2");
expect(result.current.loading).toBeFalsy();
});
});