Init
This commit is contained in:
commit
0029086b3f
148 changed files with 19047 additions and 0 deletions
3
shared/client-api/.eslintrc.js
Normal file
3
shared/client-api/.eslintrc.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
module.exports = {
|
||||
extends: ['../../.eslintrc.js'],
|
||||
};
|
39
shared/client-api/README.md
Normal file
39
shared/client-api/README.md
Normal file
|
@ -0,0 +1,39 @@
|
|||
# Client API
|
||||
|
||||
A client side library intended to be used in multiple clients, such as admin, web and mobile. It handles authenticated and un-authenticated requests to the projects API.
|
||||
|
||||
## Type Naming
|
||||
|
||||
Consider naming after the group of API endpoints, such as Admin, for all admin API requests.
|
||||
|
||||
## Working With Baseblocks
|
||||
|
||||
New api endpoints may be manually added to this folder. A Baseblock may also add new API files during its installation.
|
||||
|
||||
## Using Client API in a Client
|
||||
|
||||
Add a new "include" to the client `tsconfig.json` (e.g. `packages/web/tsconfig.json`)
|
||||
|
||||
```
|
||||
"include": ["../shared/client-api"]
|
||||
```
|
||||
|
||||
Add a new dependency to the client `package.json` (e.g. `packages/web/package.json`)
|
||||
|
||||
```
|
||||
"@baseline/client-api": "1.0.0",
|
||||
```
|
||||
|
||||
Referencing the client api in code
|
||||
|
||||
```
|
||||
import { createAdmin } from '@baseline/client-api/admin';
|
||||
```
|
||||
|
||||
If you are having issues with your IDE showing this package as not existing attempt restarting your IDE TS Server and IDE ESLint Server.
|
||||
|
||||
## Note on Amplify
|
||||
|
||||
Since the package uses Amplify Auth for handling requests the same version must match all client versions or you will find that API requests will have authentication issues.
|
||||
|
||||
Confirm `aws-amplify` version in `package.json` is the same as the client `package.json`.
|
61
shared/client-api/admin.ts
Normal file
61
shared/client-api/admin.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
import { Admin } from '@baseline/types/admin';
|
||||
import { RequestHandler } from './request-handler';
|
||||
|
||||
export const getAllAdmins = async (
|
||||
requestHandler: RequestHandler,
|
||||
): Promise<Admin[]> => {
|
||||
const response = await requestHandler.request<Admin[]>({
|
||||
method: 'GET',
|
||||
url: `admin/list`,
|
||||
hasAuthentication: true,
|
||||
});
|
||||
if ('data' in response) {
|
||||
return response.data;
|
||||
}
|
||||
throw response;
|
||||
};
|
||||
|
||||
export const deleteAdmin = async (
|
||||
requestHandler: RequestHandler,
|
||||
data: { adminId: string },
|
||||
): Promise<boolean> => {
|
||||
const response = await requestHandler.request<boolean>({
|
||||
method: 'DELETE',
|
||||
url: `admin/${data.adminId}`,
|
||||
hasAuthentication: true,
|
||||
});
|
||||
if ('data' in response) {
|
||||
return response.data;
|
||||
}
|
||||
throw response;
|
||||
};
|
||||
|
||||
export const createAdmin = async (
|
||||
requestHandler: RequestHandler,
|
||||
data: { userEmail: string },
|
||||
): Promise<Admin> => {
|
||||
const response = await requestHandler.request<Admin>({
|
||||
method: 'POST',
|
||||
url: `admin`,
|
||||
hasAuthentication: true,
|
||||
data,
|
||||
});
|
||||
if ('data' in response) {
|
||||
return response.data;
|
||||
}
|
||||
throw response;
|
||||
};
|
||||
|
||||
export const checkAdmin = async (
|
||||
requestHandler: RequestHandler,
|
||||
): Promise<boolean> => {
|
||||
const response = await requestHandler.request<Admin>({
|
||||
method: 'GET',
|
||||
url: `admin`,
|
||||
hasAuthentication: true,
|
||||
});
|
||||
if ('data' in response) {
|
||||
return !!response.data.userSub;
|
||||
}
|
||||
return false;
|
||||
};
|
64
shared/client-api/chart.ts
Normal file
64
shared/client-api/chart.ts
Normal file
|
@ -0,0 +1,64 @@
|
|||
import { Chart } from '@baseline/types/chart';
|
||||
import { getRequestHandler } from './request-handler';
|
||||
|
||||
export const getChart = async (chartId: string): Promise<Chart> => {
|
||||
const response = await getRequestHandler().request<Chart>({
|
||||
method: 'GET',
|
||||
url: `chart/admin/${chartId}`,
|
||||
hasAuthentication: true,
|
||||
});
|
||||
if ('data' in response) {
|
||||
return response.data;
|
||||
}
|
||||
throw response;
|
||||
};
|
||||
|
||||
export const getAllCharts = async (): Promise<Chart[]> => {
|
||||
const response = await getRequestHandler().request<Chart[]>({
|
||||
method: 'GET',
|
||||
url: `chart/admin/list`,
|
||||
hasAuthentication: true,
|
||||
});
|
||||
if ('data' in response) {
|
||||
return response.data;
|
||||
}
|
||||
throw response;
|
||||
};
|
||||
|
||||
export const deleteChart = async (chartId: string): Promise<boolean> => {
|
||||
const response = await getRequestHandler().request<boolean>({
|
||||
method: 'DELETE',
|
||||
url: `chart/admin/${chartId}`,
|
||||
hasAuthentication: true,
|
||||
});
|
||||
if ('data' in response) {
|
||||
return response.data;
|
||||
}
|
||||
throw response;
|
||||
};
|
||||
|
||||
export const createChart = async (chart: Partial<Chart>): Promise<Chart> => {
|
||||
const response = await getRequestHandler().request<Chart>({
|
||||
method: 'POST',
|
||||
url: `chart/admin`,
|
||||
hasAuthentication: true,
|
||||
data: chart,
|
||||
});
|
||||
if ('data' in response) {
|
||||
return response.data;
|
||||
}
|
||||
throw response;
|
||||
};
|
||||
|
||||
export const updateChart = async (chart: Partial<Chart>): Promise<Chart> => {
|
||||
const response = await getRequestHandler().request<Chart>({
|
||||
method: 'PATCH',
|
||||
url: `chart/admin`,
|
||||
hasAuthentication: true,
|
||||
data: chart,
|
||||
});
|
||||
if ('data' in response) {
|
||||
return response.data;
|
||||
}
|
||||
throw response;
|
||||
};
|
13
shared/client-api/package.json
Normal file
13
shared/client-api/package.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "@baseline/client-api",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"lint": "npx eslint --config '.eslintrc.js' '**/*.{ts,tsx,js}'",
|
||||
"pretty": "npx prettier --write '*.{ts,tsx,js,json,css,scss,md,yml,yaml,html}'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@baseline/types": "workspace:1.0.0",
|
||||
"axios": "1.7.7"
|
||||
}
|
||||
}
|
86
shared/client-api/request-handler.ts
Normal file
86
shared/client-api/request-handler.ts
Normal file
|
@ -0,0 +1,86 @@
|
|||
import axios, {
|
||||
AxiosError,
|
||||
AxiosRequestConfig,
|
||||
AxiosRequestHeaders,
|
||||
AxiosResponse,
|
||||
Method,
|
||||
} from 'axios';
|
||||
|
||||
let requestHandler: RequestHandler;
|
||||
|
||||
export const getRequestHandler = (): RequestHandler => {
|
||||
return requestHandler;
|
||||
};
|
||||
|
||||
export const createRequestHandler = (
|
||||
authorizedConfig?: (
|
||||
config: AxiosRequestConfig,
|
||||
) => Promise<AxiosRequestConfig>,
|
||||
unauthorizedConfig?: (
|
||||
config: AxiosRequestConfig,
|
||||
) => Promise<AxiosRequestConfig>,
|
||||
): RequestHandler => {
|
||||
requestHandler = new RequestHandler(authorizedConfig, unauthorizedConfig);
|
||||
return requestHandler;
|
||||
};
|
||||
|
||||
const baseUrl = process.env.REACT_APP_API_URL || '';
|
||||
|
||||
export interface RequestHandlerParams {
|
||||
method: Method;
|
||||
url: string;
|
||||
hasAuthentication?: boolean;
|
||||
data?: unknown;
|
||||
headers?: AxiosRequestHeaders;
|
||||
}
|
||||
|
||||
export class RequestHandler {
|
||||
public authorizedConfig: (
|
||||
config: AxiosRequestConfig,
|
||||
) => Promise<AxiosRequestConfig>;
|
||||
|
||||
public unauthorizedConfig: (
|
||||
config: AxiosRequestConfig,
|
||||
) => Promise<AxiosRequestConfig>;
|
||||
|
||||
constructor(
|
||||
authorizedConfig?: (
|
||||
config: AxiosRequestConfig,
|
||||
) => Promise<AxiosRequestConfig>,
|
||||
unauthorizedConfig?: (
|
||||
config: AxiosRequestConfig,
|
||||
) => Promise<AxiosRequestConfig>,
|
||||
) {
|
||||
this.authorizedConfig = authorizedConfig;
|
||||
this.unauthorizedConfig = unauthorizedConfig;
|
||||
}
|
||||
|
||||
public request = async <T>(
|
||||
params: RequestHandlerParams,
|
||||
): Promise<AxiosResponse<T> | AxiosError> => {
|
||||
try {
|
||||
let config: AxiosRequestConfig = {
|
||||
method: params.method,
|
||||
url: `${baseUrl}${params.url}`,
|
||||
data: params.data,
|
||||
headers: params.headers,
|
||||
};
|
||||
if (params.hasAuthentication) {
|
||||
if (this.authorizedConfig) {
|
||||
config = await this.authorizedConfig(config);
|
||||
}
|
||||
return await axios(config);
|
||||
}
|
||||
if (this.unauthorizedConfig) {
|
||||
config = await this.unauthorizedConfig(config);
|
||||
}
|
||||
return await axios(config);
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
return error;
|
||||
}
|
||||
console.error('API Request Failed: ', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
3
shared/types/.eslintrc.js
Normal file
3
shared/types/.eslintrc.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
module.exports = {
|
||||
extends: ['../../.eslintrc.js'],
|
||||
};
|
33
shared/types/README.md
Normal file
33
shared/types/README.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
# Types
|
||||
|
||||
The types package is used for types that are used in multiple parts of the application. For example the API endpoint response type and the web front end that needs to handle the response type.
|
||||
|
||||
## Type Naming
|
||||
|
||||
Consider making names specific to their use case, such as including a response or endpoint name in the type names. E.g. `ApiNewUserResponse`.
|
||||
|
||||
## Working With Baseblocks
|
||||
|
||||
New types can be manually added to this folder. A Baseblock may also add new type files during its installation.
|
||||
|
||||
## Using Types in a Client
|
||||
|
||||
Add a new "include" to the client `tsconfig.json` (e.g. `packages/web/tsconfig.json`)
|
||||
|
||||
```
|
||||
"include": ["../../shared/types"]
|
||||
```
|
||||
|
||||
Add a new dependency to the client `package.json` (e.g. `packages/web/package.json`)
|
||||
|
||||
```
|
||||
"@baseline/types": "1.0.0",
|
||||
```
|
||||
|
||||
Referencing the type in code
|
||||
|
||||
```
|
||||
import { Admin } from '@baseline/types/admin';
|
||||
```
|
||||
|
||||
If you are having issues with your IDE showing this package as not existing attempt restarting your IDE TS Server and IDE ESLint Server.
|
4
shared/types/admin.d.ts
vendored
Normal file
4
shared/types/admin.d.ts
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
export interface Admin {
|
||||
userSub: string;
|
||||
userEmail: string;
|
||||
}
|
19
shared/types/chart.ts
Normal file
19
shared/types/chart.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import * as Yup from 'yup';
|
||||
|
||||
export interface Chart {
|
||||
chartId: string;
|
||||
md5: string;
|
||||
sha256: string;
|
||||
resourceUri?: string;
|
||||
parentChart?: string;
|
||||
name: string;
|
||||
comment?: string;
|
||||
}
|
||||
|
||||
export const chartSchema = Yup.object().shape({
|
||||
name: Yup.string().required(),
|
||||
md5: Yup.string().required(),
|
||||
sha256: Yup.string().required(),
|
||||
resourceUri: Yup.string(),
|
||||
comment: Yup.string(),
|
||||
});
|
12
shared/types/package.json
Normal file
12
shared/types/package.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "@baseline/types",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"lint": "npx eslint --config '.eslintrc.js' '**/*.{ts,tsx,js}'",
|
||||
"pretty": "npx prettier --write '*.{ts,tsx,d.ts,js,json,css,scss,md,yml,yaml,html}'"
|
||||
},
|
||||
"dependencies": {
|
||||
"yup": "^1.4.0"
|
||||
}
|
||||
}
|
10
shared/types/paging.d.ts
vendored
Normal file
10
shared/types/paging.d.ts
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
export interface PagedResponse<T> {
|
||||
data?: T[];
|
||||
pagination: {
|
||||
limit: number;
|
||||
totalRecords: number;
|
||||
nextFrom?: number;
|
||||
pages: number;
|
||||
currentPage: number;
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue