From bf401e68eb9be540fda55141546325148e71b50c Mon Sep 17 00:00:00 2001 From: John Wu <76966357+jwu-fisker@users.noreply.github.com> Date: Wed, 17 Mar 2021 15:11:41 -0700 Subject: [PATCH] Handle api error json (#18) * Handle api error json * Fix get vehicles error handling Update .env.template --- .env.template | 3 ++- src/components/Contexts/UserContext.jsx | 20 ++++++-------- src/components/Contexts/VehicleContext.jsx | 15 +++++++---- .../Contexts/VehicleContext.test.jsx | 20 +++++++------- src/components/FileUploadForm/index.jsx | 1 - src/components/VehicleAddForm/index.jsx | 4 +-- src/services/__mocks__/vehicles.js | 5 +++- src/services/auth.js | 8 +++--- src/services/vehicles.js | 26 +++++++++---------- src/utils/http.js | 14 ++++++++++ 10 files changed, 69 insertions(+), 47 deletions(-) create mode 100644 src/utils/http.js diff --git a/.env.template b/.env.template index de94a3c..86292db 100644 --- a/.env.template +++ b/.env.template @@ -1,2 +1,3 @@ REACT_APP_AUTH_SERVICE_URL = https://dev-auth.fiskerdps.com -REACT_APP_UPLOAD_SERVICE_URL = https://gw-dev.fiskerdps.com \ No newline at end of file +REACT_APP_UPLOAD_SERVICE_URL = https://gw-dev.fiskerdps.com +REACT_APP_AUTH_CALLBACK_URL = https://dev-ota-admin.fiskerdps.com/ \ No newline at end of file diff --git a/src/components/Contexts/UserContext.jsx b/src/components/Contexts/UserContext.jsx index 4bf408a..2146b8a 100644 --- a/src/components/Contexts/UserContext.jsx +++ b/src/components/Contexts/UserContext.jsx @@ -20,10 +20,7 @@ export const UserProvider = ({ children }) => { useEffect(() => { if (!token) return; - const { - idToken: { jwtToken }, - } = token; - verifyToken(jwtToken); + verifyToken(); return () => { if (timer) timer.terminate(); }; @@ -57,15 +54,14 @@ export const UserProvider = ({ children }) => { timer.start(duration); }; - const verifyToken = async (idToken) => { + const verifyToken = async () => { try { + const { + idToken: { jwtToken: idToken }, + } = token; const result = await auth.verify(idToken); - if ( - (!result.valid && !result.authenticated) || - !token.idToken.payload || - !token.idToken.payload.exp - ) { + if (!result && !result.valid) { const t = await refreshTokens(); if (!isError(t)) return; signOut(); @@ -74,7 +70,8 @@ export const UserProvider = ({ children }) => { startSessionTimer(); } catch (e) { - setError(e.message); + signOut(); + setError(`Verify error. ${e.message}`); } }; @@ -126,7 +123,6 @@ export const UserProvider = ({ children }) => { setFetching(true); setError(null); - // eslint-disable-next-line result = await auth.refresh(value); if (result.message) { diff --git a/src/components/Contexts/VehicleContext.jsx b/src/components/Contexts/VehicleContext.jsx index 5b00eae..cd36522 100644 --- a/src/components/Contexts/VehicleContext.jsx +++ b/src/components/Contexts/VehicleContext.jsx @@ -24,10 +24,13 @@ export const VehicleProvider = ({ children }) => { const getVehicles = async (search, token) => { try { setBusy(true); - const { - data: { data }, - } = await api.getVehicles(search, token); - setVehicles(data); + const result = await api.getVehicles(search, token); + if (result.error) { + setVehicles([]); + throw new Error(`Get vehicles error. ${result.message}`); + } else { + setVehicles(result.data); + } } finally { setBusy(false); } @@ -37,7 +40,9 @@ export const VehicleProvider = ({ children }) => { try { setBusy(true); validateAdd(vehicle); - await api.addVehicle(vehicle, token); + const result = await api.addVehicle(vehicle, token); + if (result.error) throw new Error(`Add vehicle error. ${result.message}`); + return result; } finally { setBusy(false); } diff --git a/src/components/Contexts/VehicleContext.test.jsx b/src/components/Contexts/VehicleContext.test.jsx index f06719f..211f2bb 100644 --- a/src/components/Contexts/VehicleContext.test.jsx +++ b/src/components/Contexts/VehicleContext.test.jsx @@ -131,12 +131,14 @@ describe("VehicleContext", () => { }); }); -const expectedVehicleData = [ - { vin: "3C4PDCBG0ET127145" }, - { vin: "1G1FP87S3GN100062" }, - { vin: "1HGCG325XYA062256" }, - { vin: "1J4GZ78YXWC160024" }, - { vin: "2C3CCAAG8CH222800" }, - { vin: "KNADM4A39C6028108" }, - { vin: "1G11C5SL9FF153507" }, -]; +const expectedVehicleData = { + data: [ + { vin: "3C4PDCBG0ET127145" }, + { vin: "1G1FP87S3GN100062" }, + { vin: "1HGCG325XYA062256" }, + { vin: "1J4GZ78YXWC160024" }, + { vin: "2C3CCAAG8CH222800" }, + { vin: "KNADM4A39C6028108" }, + { vin: "1G11C5SL9FF153507" }, + ], +}; diff --git a/src/components/FileUploadForm/index.jsx b/src/components/FileUploadForm/index.jsx index 7ee812d..fd64926 100644 --- a/src/components/FileUploadForm/index.jsx +++ b/src/components/FileUploadForm/index.jsx @@ -43,7 +43,6 @@ const FileUploadZone = ({ classes, token }) => { onChange={(files) => setFiles(files)} onDelete={(files) => setFiles(files)} onDropRejected={(files) => { - console.log("Rejected files", files); setMessage(`Rejected ${files[0].name} too large`); }} /> diff --git a/src/components/VehicleAddForm/index.jsx b/src/components/VehicleAddForm/index.jsx index e9dcaad..11d50fd 100644 --- a/src/components/VehicleAddForm/index.jsx +++ b/src/components/VehicleAddForm/index.jsx @@ -24,9 +24,9 @@ const MainForm = () => { vin: vinEl.current.value, }; - await addVehicle(formData, authToken); + const result = await addVehicle(formData, authToken); - setMessage(`Added ${vinEl.current.value}`); + setMessage(`Added ${result.vin}`); vinEl.current.value = ""; } catch (e) { setMessage(e.message); diff --git a/src/services/__mocks__/vehicles.js b/src/services/__mocks__/vehicles.js index 6e1a6dd..74f7c8f 100644 --- a/src/services/__mocks__/vehicles.js +++ b/src/services/__mocks__/vehicles.js @@ -11,7 +11,10 @@ const data = [ const vehiclesAPI = { getVehicles: async (search, token) => { return { data: { data } }; }, - addVehicle: async (vehicle, token) => { data.push(vehicle); }, + addVehicle: async (vehicle, token) => { + data.push(vehicle); + return vehicle; + }, }; export default vehiclesAPI; diff --git a/src/services/auth.js b/src/services/auth.js index 454f3dc..9bbfda6 100644 --- a/src/services/auth.js +++ b/src/services/auth.js @@ -1,3 +1,5 @@ +import { fetchRespHandler } from "../utils/http"; + const AUTH_URL = process.env.REACT_APP_AUTH_SERVICE_URL || "https://gw-dev.fiskerdps.com/compute_auth"; const CALLBACK_URL = process.env.REACT_APP_AUTH_CALLBACK_URL || "https://dev-ota-admin.fiskerdps.com"; @@ -13,7 +15,7 @@ const auth = { code, redirect: CALLBACK_URL, }) - }).then((response) => response.json()), + }).then(fetchRespHandler), verify: (idToken) => fetch(`${AUTH_URL}/verify`, { method: "POST", @@ -21,7 +23,7 @@ const auth = { "Content-Type": "application/json" }, body: JSON.stringify({ token: idToken }) - }).then((response) => response.json()), + }).then(fetchRespHandler), refresh: (refreshToken) => fetch(`${AUTH_URL}/refresh`, { method: "POST", @@ -29,7 +31,7 @@ const auth = { "Content-Type": "application/json" }, body: JSON.stringify({ refresh_token: refreshToken }) - }).then((response) => response.json()), + }).then(fetchRespHandler), }; export default auth; diff --git a/src/services/vehicles.js b/src/services/vehicles.js index 3d7fcf8..f6b276c 100644 --- a/src/services/vehicles.js +++ b/src/services/vehicles.js @@ -1,20 +1,20 @@ -import axios from 'axios'; +import { getAuthHeaderOptions, fetchRespHandler } from "../utils/http" const API_ENDPOINT = process.env.REACT_APP_UPLOAD_SERVICE_URL || "https://gw-dev.fiskerdps.com/ota_update"; -const getOptions = (token) => ({ - headers: { - "Authorization": `Bearer ${token}`, - }, -}); - const vehiclesAPI = { - getVehicles: async (search, token) => { - return axios.get(`${API_ENDPOINT}/vehicles`, getOptions(token)); - }, - addVehicle: async (vehicle, token) => { - return axios.post(`${API_ENDPOINT}/vehicle`, vehicle, getOptions(token)); - } + addVehicle: async (vehicle, token) => fetch(`${API_ENDPOINT}/vehicle`, { + method: "POST", + headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)), + body: JSON.stringify(vehicle), + }) + .then(fetchRespHandler), + getVehicles: async (search, token) => fetch(`${API_ENDPOINT}/vehicles`, { + method: "GET", + headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)), + + }) + .then(fetchRespHandler) }; export default vehiclesAPI; diff --git a/src/utils/http.js b/src/utils/http.js new file mode 100644 index 0000000..94c7fd7 --- /dev/null +++ b/src/utils/http.js @@ -0,0 +1,14 @@ +export const getAuthHeaderOptions = (token) => ({ + "Authorization": `Bearer ${token}`, + }); + +export const fetchRespHandler = (response) => { + if (response.ok) return response.json(); + + return response.text() + .then((text) => JSON.parse(text)) + .catch((e) => ({ + error: response.statusText, + message: `${response.status} ${response.statusText}`, + })) +} \ No newline at end of file