From 514bcde809f5b606b11eff20b61db09129ea8781 Mon Sep 17 00:00:00 2001 From: Mikayla Dobson <93477693+innocuous-symmetry@users.noreply.github.com> Date: Sat, 11 Feb 2023 18:18:34 -0600 Subject: [PATCH] refactoring front end API access --- client/package.json | 2 + client/src/components/pages/Login.tsx | 6 - client/src/util/API.ts | 152 ++++++++++++++++++++++++++ client/src/util/apiUtils.tsx | 2 +- client/src/util/axiosInstance.ts | 24 ++++ 5 files changed, 179 insertions(+), 7 deletions(-) create mode 100644 client/src/util/API.ts create mode 100644 client/src/util/axiosInstance.ts diff --git a/client/package.json b/client/package.json index 6b97e4f..148c6da 100644 --- a/client/package.json +++ b/client/package.json @@ -11,6 +11,7 @@ "dependencies": { "@tinymce/tinymce-react": "^4.2.0", "axios": "^1.2.0", + "jwt-decode": "^3.1.2", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.4.3", @@ -18,6 +19,7 @@ "uuid": "^9.0.0" }, "devDependencies": { + "@types/jwt-decode": "^3.1.0", "@types/react": "^18.0.24", "@types/react-dom": "^18.0.8", "@types/uuid": "^8.3.4", diff --git a/client/src/components/pages/Login.tsx b/client/src/components/pages/Login.tsx index b46c068..4edad82 100644 --- a/client/src/components/pages/Login.tsx +++ b/client/src/components/pages/Login.tsx @@ -34,12 +34,6 @@ export default function Login() { if (user) navigate('/'); }, []) - // useEffect(() => { - // setForm( - - // ) - // }, [getFormState]) - useEffect(() => { console.log(input); }, [getFormState]) diff --git a/client/src/util/API.ts b/client/src/util/API.ts new file mode 100644 index 0000000..f1fbdc1 --- /dev/null +++ b/client/src/util/API.ts @@ -0,0 +1,152 @@ +import { AxiosHeaders, AxiosRequestHeaders } from "axios"; +import { IUser, IUserAuth, IFriendship, IRecipe, IIngredient, ICollection, IGroceryList } from "../schemas"; +import { default as _instance } from "./axiosInstance"; + +export module API { + const APISTRING = import.meta.env.APISTRING || "http://localhost:8080"; + + abstract class RestController { + protected instance = _instance; + protected endpoint: string; + protected token?: string; + protected headers?: any + + constructor(endpoint: string, token?: string) { + this.endpoint = endpoint; + this.token = token; + + if (token) { + this.headers = { + "Content-Type": "application/json", + "Authorization": ("Bearer " + token) + }; + } + } + + async getAll() { + if (!this.token) return null; + + const response = await this.instance.get(this.endpoint, this.headers); + return Promise.resolve(response.data); + } + + async getByID(id: string) { + if (!this.token) return null; + + const response = await this.instance.get(this.endpoint + "/" + id, this.headers); + return Promise.resolve(response.data); + } + + async postOne(data: T) { + if (!this.token) return null; + + const response = await this.instance.post(this.endpoint, data, this.headers); + return Promise.resolve(response.data); + } + + async put(id: string, data: T | Partial) { + if (!this.token) return null; + + const response = await this.instance.put(this.endpoint + "/" + id, data, this.headers); + return Promise.resolve(response.data); + } + + async delete(id: string) { + if (!this.token) return null; + + const response = await this.instance.delete(this.endpoint + '/' + id, this.headers); + return Promise.resolve(response.data); + } + } + + export class Auth { + private instance = _instance; + private endpoint = APISTRING + "/auth"; + + async login(data: IUserAuth | Partial) { + try { + const response = await this.instance.post(this.endpoint + "/login", data); + return Promise.resolve(response.data); + } catch (e: any) { + console.error(e); + } + } + + async register(data: IUser) { + try { + const response = await this.instance.post(this.endpoint + "/register", data); + return Promise.resolve(response.data); + } catch (e: any) { + console.error(e); + } + } + + async logout() { + try { + const response = await this.instance.delete(this.endpoint + '/logout'); + + // unset cookie data and send response + document.cookie = `token=;expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`; + return Promise.resolve(response.data); + } catch(err) { + console.error(err); + } + } + + // for future use + async registerGoogle() { + return; + } + + async loginGoogle() { + return; + } + + async logoutGoogle() { + return; + } + } + + export class User extends RestController { + constructor() { + super(APISTRING + "/app/users"); + } + } + + export class Friendship extends RestController { + constructor() { + super(APISTRING + "/app/friends"); + } + + async getPendingFriendRequests() { + if (!this.token) return null; + + const response = await this.instance.get(this.endpoint + "?pending=true", this.headers); + return Promise.resolve(response.data); + } + } + + export class Recipe extends RestController { + constructor() { + super(APISTRING + "/app/recipes"); + } + } + + export class Ingredient extends RestController { + constructor() { + super(APISTRING + "/app/ingredients"); + } + } + + export class Collection extends RestController { + constructor() { + super(APISTRING + "/app/collections"); + } + } + + export class GroceryList extends RestController { + constructor() { + super(APISTRING + "/app/grocery-list") + } + } +} \ No newline at end of file diff --git a/client/src/util/apiUtils.tsx b/client/src/util/apiUtils.tsx index c4e8a19..8adfaf0 100644 --- a/client/src/util/apiUtils.tsx +++ b/client/src/util/apiUtils.tsx @@ -1,5 +1,5 @@ import { ICollection, IUser, IUserAuth } from "../schemas"; -// import { IAuthContext } from "../context/AuthContext"; +import instance from "./axiosInstance"; import axios from "axios"; const API = import.meta.env.APISTRING || "http://localhost:8080"; diff --git a/client/src/util/axiosInstance.ts b/client/src/util/axiosInstance.ts new file mode 100644 index 0000000..ebaa5e4 --- /dev/null +++ b/client/src/util/axiosInstance.ts @@ -0,0 +1,24 @@ +import axios, { AxiosResponse } from 'axios' +import jwt_decode from 'jwt-decode' + +const apiUrl = import.meta.env.VITE_APIURL; + +const instance = axios.create({ + baseURL: apiUrl +}); + +instance.interceptors.response.use((res: AxiosResponse) => { + if (res?.data.token) { + document.cookie = `token=${res.data.token}`; + + return res; + } else { + console.error("Token was not found in response"); + + return res; + } +}, (err) => { + return Promise.reject(err); +}) + +export default instance; \ No newline at end of file