Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace Axios with Fetch #5

Merged
merged 1 commit into from
Mar 2, 2024
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
3 changes: 1 addition & 2 deletions ui/api-handshake.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const axios = require('axios');
const env = require('@next/env');

env.loadEnvConfig(process.cwd());
Expand All @@ -23,7 +22,7 @@ or check the connection configuration and
fix any possible problems.\n`;

if (apiHandshakeEnabled) {
axios.get(`${apiBaseUrl}/`)
fetch(`${apiBaseUrl}/`)
.catch(() => {
console.log(errorMessage);
process.exit(1);
Expand Down
2 changes: 1 addition & 1 deletion ui/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const config: Config = {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
moduleDirectories: ['node_modules', '<rootDir>'],
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/src/$1"
'^@/(.*)$': '<rootDir>/src/$1'
}
};

Expand Down
3 changes: 0 additions & 3 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
"dependencies": {
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-slot": "^1.0.2",
"axios": "^1.6.7",
"axios-retry": "^4.0.0",
"camaro": "^6.2.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
Expand All @@ -43,7 +41,6 @@
"@typescript-eslint/eslint-plugin": "^6.19.1",
"@typescript-eslint/parser": "^6.19.1",
"autoprefixer": "^10.0.1",
"axios-mock-adapter": "^1.22.0",
"eslint": "^8",
"eslint-config-next": "14.1.0",
"eslint-plugin-testing-library": "^6.2.0",
Expand Down
31 changes: 8 additions & 23 deletions ui/src/access/AuthorizationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import User from './User';
import Role from './Role';
import axios from 'axios';

const apiBaseUrl = process.env.NEXT_PUBLIC_API_2_1_BASE_URL as string;

Expand Down Expand Up @@ -33,17 +32,10 @@ export const setRoles = async (user: User): Promise<void> => {
*
* @returns True if the uhIdentifier is an owner of a grouping
*/
const isOwner = async (uhIdentifier: string): Promise<boolean> => {
try {
const { data } = await axios.get(`${apiBaseUrl}/owners`, {
headers: { 'current_user': uhIdentifier }
});
return data;
} catch (error) {
console.error(error);
}
return false;
}
const isOwner = async (uhIdentifier: string): Promise<boolean> =>
await fetch(`${apiBaseUrl}/owners`, { headers: { 'current_user': uhIdentifier }})
.then(res => res.json())
.catch(() => false);

/**
* Calls UH Groupings API to check if the uhIdentifier is an admin.
Expand All @@ -52,17 +44,10 @@ const isOwner = async (uhIdentifier: string): Promise<boolean> => {
*
* @returns True if the uhIdentifier is an admin
*/
const isAdmin = async (uhIdentifier: string): Promise<boolean> => {
try {
const { data } = await axios.get(`${apiBaseUrl}/admins`, {
headers: { 'current_user': uhIdentifier }
});
return data;
} catch (error) {
console.error(error);
}
return false;
}
const isAdmin = async (uhIdentifier: string): Promise<boolean> =>
await fetch(`${apiBaseUrl}/admins`, { headers: { 'current_user': uhIdentifier }})
.then(res => res.json())
.catch(() => false);

/**
* Checks if uhUuid is valid using Regex.
Expand Down
10 changes: 6 additions & 4 deletions ui/src/access/Saml11Validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import User, { AnonymousUser } from './User';
import uniqid from 'uniqid';
import { format } from 'util';
import { transform } from 'camaro';
import axios from 'axios';

const baseUrl = process.env.NEXT_PUBLIC_BASE_URL as string;
const casUrl = process.env.NEXT_PUBLIC_CAS_URL as string;
Expand Down Expand Up @@ -30,10 +29,13 @@ export const validateTicket = async (ticket: string): Promise<User> => {
const samlRequestBody = format(samlRequestTemplate, `${uniqid()}.${currentDate}`, currentDate, ticket);

try {
const response = await axios.post(samlValidateUrl, samlRequestBody, {
headers: { 'Content-Type': 'text/xml' }
const response = await fetch(samlValidateUrl, {
method: 'POST',
headers: { 'Content-Type': 'text/xml' },
body: samlRequestBody
});
const casUser = await transform(response.data, samlResponseTemplate);
const data = await response.text();
const casUser = await transform(data, samlResponseTemplate);

return {
...casUser,
Expand Down
2 changes: 1 addition & 1 deletion ui/src/access/User.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MemberResult } from '@/services/GroupingsApiResults';
import { MemberResult } from '@/groupings/GroupingsApiResults';
import Role from './Role';

type User = {
Expand Down
200 changes: 200 additions & 0 deletions ui/src/services/FetchService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
'use server';

import { ApiError } from '../groupings/GroupingsApiResults';
import { getCurrentUser } from '@/access/AuthenticationService';

const maxRetries = 3;
const baseUrl = process.env.NEXT_PUBLIC_API_2_1_BASE_URL as string;

/**
* Sleep/wait for the specified milliseconds.
*
* @param ms - the time in milliseconds to wait for
*
* @returns setTimeout promise
*/
const delay = async (ms = 5000) => new Promise((res) => setTimeout(res, ms));

/**
* Polls to getAsyncJobResult API endpoint until the async job has completed with a result.
*
* @param jobId - the jobId returned from the response of an async endpoint
*
* @returns The promise of type T or ApiError type
*/
const poll = async <T> (jobId: number): Promise<T & ApiError> => {
const currentUser = await getCurrentUser();
return fetch(`${baseUrl}/jobs/${jobId}`, { headers: { 'current_user': currentUser.uid } })
.then(res => res.json())
.then(async res => {
if (res.status === 'COMPLETED') {
return res.result;
}
await delay();
return poll<T>(jobId);
})
.catch(err => err);
};

/**
* Perform a GET request to the specified URL.
*
* @param endpoint - the URL to perform the request on
* @param currentUserKey - the uhIdentifier of the current user
*
* @returns The promise of type T or ApiError type
*/
export const getRequest = async <T> (
endpoint: string,
currentUserKey: string = ''
): Promise<T & ApiError> =>
await fetch(endpoint, { headers: { 'current_user': currentUserKey } })
.then(res => res.json())
.catch(err => err);

/**
* Perform a POST request to the specified URL.
*
* @param endpoint - the URL to perform the request on
* @param currentUserKey - the uhIdentifier of the current user
* @param body - the request body to perform the request with
*
* @returns The promise of type T or ApiError type
*/
export const postRequest = async <T> (
endpoint: string,
currentUserKey: string,
body?: string | string[],
): Promise<T & ApiError> =>
await fetch(endpoint, {
method: 'POST',
headers: { 'current_user': currentUserKey },
body: JSON.stringify(body)})
.then(res => res.json())
.catch(err => err);

/**
* Perform a POST request to the specified URL asynchronously using polling.
*
* @param endpoint - the URL to perform the request on
* @param currentUserKey - the uhIdentifier of the current user
* @param body - the request body to perform the request with
*
* @returns The promise of type T or ApiError type
*/
export const postRequestAsync = async <T> (
endpoint: string,
currentUserKey: string,
body: string | string[]
): Promise<T & ApiError> =>
await fetch(endpoint, { method: 'POST', headers: { 'current_user': currentUserKey }, body: JSON.stringify(body) })
.then(res => res.json())
.then(res => poll<T>(res))
.catch(err => err);

/**
* Perform a POST request to the specified URL with retries on error with incremental backoff.
*
* @param endpoint - the URL to perform the request on
* @param currentUserKey - the uhIdentifier of the current user
* @param body - the request body to perform the request with
*
* @returns The promise of type T or ApiError type
*/
export const postRequestRetry = async <T> (
endpoint: string,
currentUserKey: string,
body: string | string[],
retries: number = maxRetries
): Promise<T & ApiError> =>
await fetch(endpoint, { method: 'POST', headers: { 'current_user': currentUserKey }, body: JSON.stringify(body) })
.then(async res => {
if (res.status === 500 && retries > 0) {
await delay(2000 * Math.log(maxRetries / retries));
return postRequestRetry(endpoint, currentUserKey, body, retries - 1);
}
return res.json();
})
.catch(err => err);


/**
* Perform a PUT request to the specified URL.
*
* @param endpoint - the URL to perform the request on
* @param currentUserKey - the uhIdentifier of the current user
* @param body - the request body to perform the request with
*
* @returns The promise of type T or ApiError type
*/
export const putRequest = async <T> (
endpoint: string,
currentUserKey: string,
body?: string | string[]
): Promise<T & ApiError> =>
await fetch(endpoint, {
method: 'PUT',
headers: { 'current_user': currentUserKey },
body: JSON.stringify(body) })
.then(res => res.json())
.catch(err => err);

/**
* Perform a PUT request to the specified URL asynchronously using polling.
*
* @param endpoint - the URL to perform the request on
* @param currentUserKey - the uhIdentifier of the current user
* @param body - the request body to perform the request with
*
* @returns The promise of type T or ApiError type
*/
export const putRequestAsync = async <T> (
endpoint: string,
currentUserKey: string,
body: string | string[]
): Promise<T & ApiError> =>
await fetch(endpoint, { method: 'PUT', headers: { 'current_user': currentUserKey }, body: JSON.stringify(body) })
.then(res => res.json())
.then(res => poll<T>(res))
.catch(err => err);

/**
* Perform a DELETE request to the specified URL.
*
* @param endpoint - the URL to perform the request on
* @param currentUserKey - the uhIdentifier of the current user
* @param body - the request body to perform the request with
*
* @returns The promise of type T or ApiError type
*/
export const deleteRequest = async <T> (
endpoint: string,
currentUserKey: string,
body?: string | string[]
): Promise<T & ApiError> =>
await fetch(endpoint, { method: 'DELETE', headers: { 'current_user': currentUserKey }, body: JSON.stringify(body) })
.then(res => res.json())
.then(res => (res))
.catch(err => err);

/**
* Perform a DELETE request to the specified URL asynchronously using polling.
*
* @param endpoint - the URL to perform the request on
* @param currentUserKey - the uhIdentifier of the current user
* @param body - the request body to perform the request with
*
* @returns The promise of type T or ApiError type
*/
export const deleteRequestAsync = async <T> (
endpoint: string,
currentUserKey: string,
body?: string | string[]
): Promise<T & ApiError> =>
await fetch(endpoint, {
method: 'DELETE',
headers: { 'current_user': currentUserKey },
body: JSON.stringify(body) })
.then(res => res.json())
.then(res => poll<T>(res))
.catch(err => err);
Loading
Loading