From 2511d194aafbe0a9eaa0716ec570e45f58956a3e Mon Sep 17 00:00:00 2001 From: John Chipps-Harding Date: Tue, 7 Apr 2020 00:22:03 +0100 Subject: [PATCH 1/4] Headers Support --- index.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index ce6aa24..7607629 100755 --- a/index.js +++ b/index.js @@ -9,7 +9,8 @@ const useApi = ({ pollInterval = 0, payload, method = "get", - changed + headers, + changed, }) => { const [data, setData] = useState({}); const [error, setError] = useState(null); @@ -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) { @@ -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 = payload; + } + const currentHeaders = headersRef.current; + if (method.toLowerCase) method = method.toLowerCase(); if (!["get", "post"].includes(method)) { @@ -64,9 +72,10 @@ const useApi = ({ ...(currentPayload && (method === "get" ? { params: currentPayload } - : { data: currentPayload })) + : { data: currentPayload })), + ...(currentHeaders && { headers: currentHeaders }), }) - .then(response => { + .then((response) => { // Make sure there are no errors reported setError(null); @@ -82,7 +91,7 @@ const useApi = ({ setData(response.data); } }) - .catch(thrown => { + .catch((thrown) => { // Only error on genuine errors, not cancellations if (!axios.isCancel(thrown)) setError(thrown.message); }) @@ -106,9 +115,10 @@ const useApi = ({ url, pollInterval, currentPayload, + currentHeaders, method, lastData, - changedRef + changedRef, ]); return { data, loading, changed, error, refresh: () => setPoll(poll + 1) }; From e73486b8c6481a0b704ea79b49248af3e42c0bf4 Mon Sep 17 00:00:00 2001 From: John Chipps-Harding Date: Tue, 7 Apr 2020 00:42:38 +0100 Subject: [PATCH 2/4] Added tests --- index.js | 2 +- test.js | 110 +++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 100 insertions(+), 12 deletions(-) diff --git a/index.js b/index.js index 7607629..9537f12 100755 --- a/index.js +++ b/index.js @@ -42,7 +42,7 @@ const useApi = ({ // Only apply the new headers if its really changed if (!isEqual(headers, headersRef.current)) { - headersRef.current = payload; + headersRef.current = headers; } const currentHeaders = headersRef.current; diff --git a/test.js b/test.js index b3a6934..dbee586 100755 --- a/test.js +++ b/test.js @@ -66,7 +66,7 @@ describe("performs requests", () => { const payload = { query: "hello" }; mock .onGet(url) - .reply(config => + .reply((config) => config.params.query === "hello" ? [200, "response"] : [400, "error"] ); @@ -253,7 +253,7 @@ describe("performs requests", () => { const payload = { query: "hello" }; mock .onGet(url) - .reply(config => + .reply((config) => config.params.query === "hello" ? [200, "response"] : [400, "error"] ); @@ -339,13 +339,13 @@ describe("performs requests", () => { mock.onPost(url, payload).reply(200, "response"); const { result, waitForNextUpdate, rerender } = renderHook( - props => useApi(props), + (props) => useApi(props), { initialProps: { url, payload: payload, - method: "post" - } + method: "post", + }, } ); @@ -359,7 +359,7 @@ describe("performs requests", () => { rerender({ url, payload: payload2, - method: "post" + method: "post", }); await waitForNextUpdate(); @@ -437,16 +437,16 @@ describe("performs requests", () => { mock.onGet(url + "2").reply(200, "response2"); const { result, waitForNextUpdate, rerender } = renderHook( - props => useApi(props), + (props) => useApi(props), { initialProps: { - url - } + url, + }, } ); rerender({ - url: url + "2" + url: url + "2", }); await waitForNextUpdate(); @@ -459,7 +459,7 @@ describe("performs requests", () => { const payload = { query: ["hello", "world", ["abc"]] }; mock .onGet(url) - .reply(config => + .reply((config) => config.params.query[2][0] === "abc" ? [200, "response"] : [400, "error"] ); @@ -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(); + }); }); From b147e6f05fe50ae302ad818c6322d8484ca263a0 Mon Sep 17 00:00:00 2001 From: John Chipps-Harding Date: Tue, 7 Apr 2020 00:45:41 +0100 Subject: [PATCH 3/4] Documentation --- CHANGELOG.md | 1 + README.md | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1b682b..efbd850 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/README.md b/README.md index e4d9ad3..5cfd3c7 100755 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ const { data, loading, error, refresh } = useApi({ pollInterval: 10000, payload: { keywords: "hello" }, method: "post", - changed: data => console.log("The data changed!", data) + changed: (data) => console.log("The data changed!", data), }); ``` @@ -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. From 23030743e2a842bc16c594be8259ad59d73a9f7a Mon Sep 17 00:00:00 2001 From: John Chipps-Harding Date: Tue, 7 Apr 2020 00:48:45 +0100 Subject: [PATCH 4/4] Linting --- README.md | 2 +- index.js | 10 +++++----- test.js | 36 ++++++++++++++++++------------------ 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 5cfd3c7..fb4bc17 100755 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ const { data, loading, error, refresh } = useApi({ pollInterval: 10000, payload: { keywords: "hello" }, method: "post", - changed: (data) => console.log("The data changed!", data), + changed: data => console.log("The data changed!", data) }); ``` diff --git a/index.js b/index.js index 9537f12..14264e4 100755 --- a/index.js +++ b/index.js @@ -10,7 +10,7 @@ const useApi = ({ payload, method = "get", headers, - changed, + changed }) => { const [data, setData] = useState({}); const [error, setError] = useState(null); @@ -73,9 +73,9 @@ const useApi = ({ (method === "get" ? { params: currentPayload } : { data: currentPayload })), - ...(currentHeaders && { headers: currentHeaders }), + ...(currentHeaders && { headers: currentHeaders }) }) - .then((response) => { + .then(response => { // Make sure there are no errors reported setError(null); @@ -91,7 +91,7 @@ const useApi = ({ setData(response.data); } }) - .catch((thrown) => { + .catch(thrown => { // Only error on genuine errors, not cancellations if (!axios.isCancel(thrown)) setError(thrown.message); }) @@ -118,7 +118,7 @@ const useApi = ({ currentHeaders, method, lastData, - changedRef, + changedRef ]); return { data, loading, changed, error, refresh: () => setPoll(poll + 1) }; diff --git a/test.js b/test.js index dbee586..8fcb9d0 100755 --- a/test.js +++ b/test.js @@ -66,7 +66,7 @@ describe("performs requests", () => { const payload = { query: "hello" }; mock .onGet(url) - .reply((config) => + .reply(config => config.params.query === "hello" ? [200, "response"] : [400, "error"] ); @@ -253,7 +253,7 @@ describe("performs requests", () => { const payload = { query: "hello" }; mock .onGet(url) - .reply((config) => + .reply(config => config.params.query === "hello" ? [200, "response"] : [400, "error"] ); @@ -339,13 +339,13 @@ describe("performs requests", () => { mock.onPost(url, payload).reply(200, "response"); const { result, waitForNextUpdate, rerender } = renderHook( - (props) => useApi(props), + props => useApi(props), { initialProps: { url, payload: payload, - method: "post", - }, + method: "post" + } } ); @@ -359,7 +359,7 @@ describe("performs requests", () => { rerender({ url, payload: payload2, - method: "post", + method: "post" }); await waitForNextUpdate(); @@ -437,16 +437,16 @@ describe("performs requests", () => { mock.onGet(url + "2").reply(200, "response2"); const { result, waitForNextUpdate, rerender } = renderHook( - (props) => useApi(props), + props => useApi(props), { initialProps: { - url, - }, + url + } } ); rerender({ - url: url + "2", + url: url + "2" }); await waitForNextUpdate(); @@ -459,7 +459,7 @@ describe("performs requests", () => { const payload = { query: ["hello", "world", ["abc"]] }; mock .onGet(url) - .reply((config) => + .reply(config => config.params.query[2][0] === "abc" ? [200, "response"] : [400, "error"] ); @@ -479,7 +479,7 @@ describe("performs requests", () => { it("supports custom http headers via POST", async () => { const headers = { authorization: `Bearer abc` }; - mock.onPost(url).reply((config) => { + mock.onPost(url).reply(config => { if (config.headers.authorization === headers.authorization) { return [200, "response"]; } else { @@ -503,7 +503,7 @@ describe("performs requests", () => { it("supports custom http headers via GET", async () => { const headers = { authorization: `Bearer abc` }; - mock.onGet(url).reply((config) => { + mock.onGet(url).reply(config => { if (config.headers.authorization === headers.authorization) { return [200, "response"]; } else { @@ -528,7 +528,7 @@ describe("performs requests", () => { const headers = { authorization: `Bearer abc` }; const headers2 = { authorization: `Bearer def` }; - mock.onGet(url).reply((config) => { + mock.onGet(url).reply(config => { if (config.headers.authorization === headers.authorization) { return [200, "response"]; } else if (config.headers.authorization === headers2.authorization) { @@ -539,12 +539,12 @@ describe("performs requests", () => { }); const { result, waitForNextUpdate, rerender } = renderHook( - (props) => useApi(props), + props => useApi(props), { initialProps: { url, - headers, - }, + headers + } } ); @@ -555,7 +555,7 @@ describe("performs requests", () => { rerender({ url, - headers: headers2, + headers: headers2 }); await waitForNextUpdate();