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

refactor: split out a requests library #580

Merged
merged 1 commit into from
Apr 15, 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
5 changes: 5 additions & 0 deletions .changeset/slow-ties-admire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@siafoundation/request': minor
---

Introduced a new request library for shared request and network code.
3 changes: 2 additions & 1 deletion libs/react-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"swr": "^2.1.1",
"axios": "^0.27.2",
"use-local-storage-state": "^18.3.3",
"@siafoundation/next": "^0.1.3"
"@siafoundation/next": "^0.1.3",
"@siafoundation/request": "0.0.0"
},
"dependencies": {
"detect-gpu": "^5.0.34"
Expand Down
28 changes: 1 addition & 27 deletions libs/react-core/src/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@ import { AxiosRequestConfig, AxiosResponse, AxiosResponseHeaders } from 'axios'
import { MutatorCallback, MutatorOptions } from 'swr'
import { SWROptions } from './types'
import { AppSettings } from './useAppSettings'

export type RequestParams = Record<
string,
string | string[] | number | boolean
> | void
import { RequestParams, parameterizeRoute } from '@siafoundation/request'

export type RequestConfig<Payload, Result> = {
swr?: SWROptions<Result>
Expand Down Expand Up @@ -238,28 +234,6 @@ export function buildAxiosConfig<Params extends RequestParams, Payload, Result>(
} as AxiosRequestConfig<Payload>
}

function parameterizeRoute(
route: string | null,
params: RequestParams
): string | null {
if (route && params) {
const paramKeys = Object.keys(params)
for (const key of paramKeys) {
const value = String(params[key])
if (route.includes(`:${key}`)) {
route = route.replace(`:${key}`, value)
} else {
if (!route.includes('?')) {
route += `?${key}=${encodeURIComponent(value)}`
} else {
route += `&${key}=${encodeURIComponent(value)}`
}
}
}
}
return route
}

export function buildRouteWithParams<
Params extends RequestParams,
Payload,
Expand Down
2 changes: 1 addition & 1 deletion libs/react-core/src/useDelete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import {
buildRouteWithParams,
InternalCallbackArgs,
mergeInternalCallbackArgs,
RequestParams,
Response,
InternalHookArgsCallback,
mergeInternalHookArgsCallback,
After,
getPathFromKey,
} from './request'
import { useAppSettings } from './useAppSettings'
import { RequestParams } from '@siafoundation/request'

type DeleteFunc<Params extends RequestParams, Result> = {
delete: (
Expand Down
2 changes: 1 addition & 1 deletion libs/react-core/src/useGet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
buildRouteWithParams,
InternalCallbackArgs,
mergeInternalCallbackArgs,
RequestParams,
Response,
mergeInternalHookArgsCallback,
InternalHookArgsSwr,
Expand All @@ -18,6 +17,7 @@ import {
import { SWRError } from './types'
import { useAppSettings } from './useAppSettings'
import { keyOrNull } from './utils'
import { RequestParams } from '@siafoundation/request'

export function useGetSwr<Params extends RequestParams, Result>(
args: InternalHookArgsSwr<Params, Result>
Expand Down
2 changes: 1 addition & 1 deletion libs/react-core/src/usePatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
InternalCallbackArgs,
InternalHookArgsCallback,
mergeInternalCallbackArgs,
RequestParams,
Response,
mergeInternalHookArgsCallback,
getPathFromKey,
Expand All @@ -22,6 +21,7 @@ import { useAppSettings } from './useAppSettings'
import { useMemo } from 'react'
import { keyOrNull } from './utils'
import { SWRError } from './types'
import { RequestParams } from '@siafoundation/request'

export function usePatchSwr<Params extends RequestParams, Payload, Result>(
args: InternalHookArgsWithPayloadSwr<Params, Payload, Result>
Expand Down
2 changes: 1 addition & 1 deletion libs/react-core/src/usePost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
buildRouteWithParams,
InternalCallbackArgs,
mergeInternalCallbackArgs,
RequestParams,
Response,
InternalHookArgsCallback,
mergeInternalHookArgsCallback,
Expand All @@ -22,6 +21,7 @@ import { SWRError } from './types'
import { useAppSettings } from './useAppSettings'
import { keyOrNull } from './utils'
import { useWorkflows } from './workflows'
import { RequestParams } from '@siafoundation/request'

export function usePostSwr<Params extends RequestParams, Payload, Result>(
args: InternalHookArgsWithPayloadSwr<Params, Payload, Result>
Expand Down
2 changes: 1 addition & 1 deletion libs/react-core/src/usePut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
InternalCallbackArgs,
InternalHookArgsCallback,
mergeInternalCallbackArgs,
RequestParams,
Response,
mergeInternalHookArgsCallback,
getPathFromKey,
Expand All @@ -22,6 +21,7 @@ import { useAppSettings } from './useAppSettings'
import { useMemo } from 'react'
import { keyOrNull } from './utils'
import { SWRError } from './types'
import { RequestParams } from '@siafoundation/request'

export function usePutSwr<Params extends RequestParams, Payload, Result>(
args: InternalHookArgsWithPayloadSwr<Params, Payload, Result>
Expand Down
12 changes: 12 additions & 0 deletions libs/request/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"presets": [
[
"@nx/react/babel",
{
"runtime": "automatic",
"useBuiltIns": "usage"
}
]
],
"plugins": []
}
21 changes: 21 additions & 0 deletions libs/request/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"extends": ["plugin:@nx/react", "../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"rules": {
"@nx/dependency-checks": [
"error",
{
"ignoredFiles": ["libs/request/rollup.config.js"]
}
]
},
"overrides": [
{
"files": ["*.json"],
"parser": "jsonc-eslint-parser",
"rules": {
"@nx/dependency-checks": "error"
}
}
]
}
3 changes: 3 additions & 0 deletions libs/request/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# request

Core library for building request APIs.
17 changes: 17 additions & 0 deletions libs/request/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* eslint-disable */
export default {
displayName: 'request',
preset: '../../jest.preset.js',
transform: {
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest',
'^.+\\.[tj]sx?$': [
'babel-jest',
{
presets: ['@nx/next/babel'],
plugins: ['@babel/plugin-transform-private-methods'],
},
],
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../coverage/libs/request',
}
10 changes: 10 additions & 0 deletions libs/request/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "@siafoundation/request",
"description": "Core library for building request APIs.",
"version": "0.0.0",
"license": "MIT",
"dependencies": {
"axios": "^0.27.2"
},
"types": "./src/index.d.ts"
}
42 changes: 42 additions & 0 deletions libs/request/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"name": "request",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/request/src",
"projectType": "library",
"tags": [],
"targets": {
"build": {
"executor": "@nx/rollup:rollup",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/libs/request",
"tsConfig": "libs/request/tsconfig.lib.json",
"project": "libs/request/package.json",
"entryFile": "libs/request/src/index.ts",
"external": ["react/jsx-runtime"],
"compiler": "tsc",
"outputFileName": "index.js",
"rollupConfig": "libs/request/rollup.config.js",
"assets": [
{
"glob": "libs/request/*.md",
"input": ".",
"output": "."
}
]
},
"configurations": {}
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": ["{options.outputFile}"]
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/libs/request"],
"options": {
"jestConfig": "libs/request/jest.config.ts"
}
}
}
}
18 changes: 18 additions & 0 deletions libs/request/rollup.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const preserveDirectives = require('rollup-plugin-preserve-directives')

// https://github.com/rollup/rollup/issues/4699#issuecomment-1465302665
function getRollupOptions(options) {
return {
...options,
output: {
...options.output,
preserveModules: true,
format: 'esm',
sourcemap: true,
},
plugins: options.plugins.concat(preserveDirectives.default()),
}
}

module.exports = getRollupOptions
78 changes: 78 additions & 0 deletions libs/request/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { Axios, AxiosRequestConfig, AxiosRequestHeaders } from 'axios'

export type RequestParams = Record<
string,
string | string[] | number | boolean
> | void

export function parameterizeRoute(
route: string | null,
params: RequestParams
): string | null {
if (route && params) {
const paramKeys = Object.keys(params)
for (const key of paramKeys) {
const value = String(params[key])
if (route.includes(`:${key}`)) {
route = route.replace(`:${key}`, value)
} else {
if (!route.includes('?')) {
route += `?${key}=${encodeURIComponent(value)}`
} else {
route += `&${key}=${encodeURIComponent(value)}`
}
}
}
}
return route
}

type Method = 'get' | 'post' | 'patch' | 'put' | 'delete'

export function buildRequestHandler<
Params = void,
Data = void,
Response = void
>(axios: Axios, method: Method, route: string) {
type Args = Params extends void
? Data extends void
? { config?: AxiosRequestConfig<Data> }
: { data: Data; config?: AxiosRequestConfig<Data> }
: Data extends void
? {
params: Params
config?: AxiosRequestConfig<Data>
}
: {
params: Params
data: Data
config?: AxiosRequestConfig<Data>
}

return (args: Args) => {
// args is sometimes undefined
const a = args || ({} as Args)
const paramRoute =
'params' in a
? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
parameterizeRoute(route, a.params as RequestParams)!
: route

const data = 'data' in a ? a.data : undefined

return axios[method]<Response>(paramRoute, data, a?.config)
}
}

export function initAxios(api: string, password?: string): Axios {
const headers: AxiosRequestHeaders = {
'Content-Type': 'application/json',
}
if (password) {
headers['Authorization'] = `Basic ${btoa(`:${password}`)}`
}
return new Axios({
baseURL: api,
headers,
})
}
25 changes: 25 additions & 0 deletions libs/request/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"jsx": "react-jsx",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}
22 changes: 22 additions & 0 deletions libs/request/tsconfig.lib.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"types": [
"node",
"@nx/react/typings/cssmodule.d.ts",
"@nx/react/typings/image.d.ts"
]
},
"exclude": [
"**/*.spec.ts",
"**/*.test.ts",
"**/*.spec.tsx",
"**/*.test.tsx",
"**/*.spec.js",
"**/*.test.js",
"**/*.spec.jsx",
"**/*.test.jsx"
],
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
}
Loading
Loading