Skip to content

Commit

Permalink
Merge pull request #29 from privy-open-source/feat/axios-1.x
Browse files Browse the repository at this point in the history
feat: fetch adapter
  • Loading branch information
adenvt committed Jul 24, 2024
2 parents baa949b + a707ca9 commit 82134bf
Show file tree
Hide file tree
Showing 24 changed files with 7,029 additions and 5,781 deletions.
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
18
893 changes: 893 additions & 0 deletions .yarn/releases/yarn-4.1.0.cjs

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
compressionLevel: mixed

enableGlobalCache: false

nodeLinker: node-modules

yarnPath: .yarn/releases/yarn-3.8.3.cjs
yarnPath: .yarn/releases/yarn-4.1.0.cjs
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ Find and replace all on all files (CMD+SHIFT+F):
## Features

<!-- Highlight some of the features your module provide here -->
- ✅ Using Fetch instead of XHR
- ✅ Built-in adapter for Dedupe, and Priority Queue request.
-Composible hook for Axios interceptors.
-Composable hook for Axios interceptors.

## Compabilities

Expand Down Expand Up @@ -102,7 +103,7 @@ function isUnauthorize (error: Error): boolean {
const code = getCode(error)
const message = getMessage(error)

return code === 401 && message === 'Unauthorized'
return code === 401 && message.includes('Unauthorized')
}

/** set additional or custom headers */
Expand Down
79 changes: 79 additions & 0 deletions msw.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import {
delay,
http,
HttpResponse,
} from 'msw'
import { setupServer } from 'msw/node'
import {
afterAll,
afterEach,
beforeAll,
beforeEach,
} from 'vitest'
import { setApi, createApi } from './src/core'

const BASE_URL = 'http://localhost:3000'

const server = setupServer(
http.all('*', async () => {
await delay(2)
}),

http.get(`${BASE_URL}/api/ping`, () => {
return HttpResponse.json({ message: 'Pong' })
}),

http.get(`${BASE_URL}/v1/api/ping`, () => {
return HttpResponse.json({ message: 'Pong', data: { version: 'v1' } })
}),

http.get(`${BASE_URL}/v2/api/ping`, () => {
return HttpResponse.json({ message: 'Pong', data: { version: 'v2' } })
}),

http.get(`${BASE_URL}/api/user`, () => {
return HttpResponse.json({ data: 'data-user' })
}),

http.get(`${BASE_URL}/api/error/404`, () => {
return HttpResponse.json({
code : 404,
details: [],
}, { status: 404 })
}),

http.get(`${BASE_URL}/api/error/422`, () => {
return HttpResponse.json({
code : 422,
message: 'Validation Error',
details: [
{
type_url: 'type_url',
value : 'base64string',
},
],
}, { status: 422 })
}),

http.get(`${BASE_URL}/api/error/500`, () => {
return new HttpResponse(undefined, { status: 500 })
}),
)

beforeAll(() => {
server.listen()
})

beforeEach(() => {
setApi(createApi({ baseURL: BASE_URL }))
})

afterEach(() => {
server.resetHandlers()
})

afterAll(() => {
server.close()
})

process.env.BASE_URL = BASE_URL
13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "@privyid/nuapi",
"version": "0.2.1",
"version": "0.3.0-alpha.4",
"description": "Nuxt HTTP Client module",
"packageManager": "yarn@3.8.3",
"packageManager": "yarn@4.1.0",
"repository": {
"type": "git",
"url": "https://github.com/privy-open-source/nuapi.git"
Expand Down Expand Up @@ -43,14 +43,14 @@
"release": "yarn lint && yarn coverage && yarn prepack && changelogen --release && npm publish && git push --follow-tags",
"lint": "eslint . --ext .js,.vue,.ts --format pretty",
"fix": "yarn lint --fix",
"test": "vitest src",
"coverage": "vitest run src --coverage"
"test": "vitest src --config ./vitest.config.ts",
"coverage": "vitest run src --coverage --config ./vitest.config.ts"
},
"dependencies": {
"@nuxt/kit": "^3.7.4",
"axios": "1.1.3",
"axios": "^1.7.2",
"defu": "^6.1.2",
"requrl": "^3.0.2",
"ofetch": "^1.3.3",
"ufo": "^1.3.1"
},
"devDependencies": {
Expand All @@ -77,6 +77,7 @@
"eslint-plugin-unicorn": "46.0.1",
"eslint-plugin-varspacing": "1.2.2",
"eslint-plugin-vue": "9.19.2",
"msw": "^2.3.4",
"nuxt": "3.12.3",
"typescript": "5.3.3",
"vitest": "0.30.1"
Expand Down
9 changes: 6 additions & 3 deletions playground/api/coba.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { createLazyton } from '@privyid/nuapi/core'
import {
type AxiosRequestConfig,
createLazyton,
} from '@privyid/nuapi/core'

const useApi = createLazyton({ prefixURL: '/api' })

export async function getUser () {
return await useApi().get('/users')
export async function getUser (config?: AxiosRequestConfig) {
return await useApi().get('/users', config)
}
2 changes: 1 addition & 1 deletion playground/nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { fileURLToPath } from 'node:url'

export default defineNuxtConfig({
modules : ['../src/module', '@privyid/nhp'],
modules : ['@privyid/nhp', '../src/module'],
alias : { '@privyid/nuapi/core': fileURLToPath(new URL('../src/core/', import.meta.url)) },
nuapi : {},
typescript: {
Expand Down
56 changes: 50 additions & 6 deletions playground/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,62 @@
<button @click="refresh()">
Reload
</button>
<button
:disabled="!file"
@click="register()">
Register
</button>
<input
type="file"
accept="image/*"
@change="onChange">
<img :src="preview">
<pre v-if="pending">Loading...</pre>
<pre v-else>{{ data }}</pre>
<pre v-if="error">{{ error }}</pre>
</template>

<script setup>
import { useApi } from '@privyid/nuapi/core'
<script setup lang="ts">
import { getUser } from '~/api/coba'
import { useAsyncData } from '#app'
import { ref, watchEffect } from 'vue-demi'
import { useApi } from '@privyid/nuapi/core'
const { data, refresh, pending } = await useAsyncData('users', async () => {
const { data } = await useApi().get('/api/users')
const file = ref()
const preview = ref()
const { data, refresh, pending, error } = await useAsyncData('users', async () => {
const { data } = await getUser({ requestId: 'get-user' })
return data
},
)
})
function onChange (event: InputEvent) {
const target = event.target as HTMLInputElement
const files = target.files
if (files)
file.value = files[0]
}
function register () {
const form = new FormData()
form.append('email', '[email protected]')
form.append('password', 'pistol')
useApi().post('/api/regi', form)
}
watchEffect((onCleanup) => {
if (file.value) {
const url = URL.createObjectURL(file.value)
onCleanup(() => {
URL.revokeObjectURL(url)
})
preview.value = url
}
})
</script>
39 changes: 23 additions & 16 deletions src/core/dedupe.spec.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,43 @@
import Axios from 'axios'
import MockAdapter from 'axios-mock-adapter'
import { useApi } from '.'
import { http, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
import {
useApi,
createApi,
setApi,
} from '.'
import {
beforeAll,
afterEach,
describe,
it,
expect,
afterAll,
} from 'vitest'

let mock: MockAdapter
const BASE_URL = 'http://localhost:3000'

const server = setupServer(
http.get(`${BASE_URL}/api/ping`, () => {
return HttpResponse.json({ message: 'Pong' })
}),
)

beforeAll(() => {
mock = new MockAdapter(Axios)
server.listen()

setApi(createApi({ baseURL: BASE_URL }))
})

afterEach(() => {
mock.reset()
server.resetHandlers()
})

afterAll(() => {
server.close()
})

describe('DedupeAdapter', () => {
it('should cancel previous request with same requestId', async () => {
mock.onGet('/api/ping').reply(200, { message: 'Pong' })

const api = useApi()
const a = api.get('/api/ping', { requestId: 'ping' })
const b = api.get('/api/ping', { requestId: 'ping' })
Expand All @@ -33,8 +48,6 @@ describe('DedupeAdapter', () => {
})

it('should do nothing if requestId is different', async () => {
mock.onGet('/api/ping').reply(200, { message: 'Pong' })

const api = useApi()
const a = api.get('/api/ping', { requestId: 'ping/a' })
const b = api.get('/api/ping', { requestId: 'ping/b' })
Expand All @@ -45,8 +58,6 @@ describe('DedupeAdapter', () => {
})

it('should be able to cancel via AbortController', async () => {
mock.onGet('/api/ping').reply(200, { message: 'Pong' })

const api = useApi()
const controller = new AbortController()
const signal = controller.signal
Expand All @@ -65,8 +76,6 @@ describe('DedupeAdapter', () => {

describe('cancel', () => {
it('should be cancel request only specific requestId', async () => {
mock.onGet('/api/ping').reply(200, { message: 'Pong' })

const api = useApi()
const a = api.get('/api/ping', { requestId: 'ping/i' })
const b = api.get('/api/ping', { requestId: 'ping/j' })
Expand All @@ -82,8 +91,6 @@ describe('cancel', () => {

describe('cancelAll', () => {
it('should be cancel all active request', async () => {
mock.onGet('/api/ping').reply(200, { message: 'Pong' })

const api = useApi()
const a = api.get('/api/ping', { requestId: 'ping/x' })
const b = api.get('/api/ping', { requestId: 'ping/y' })
Expand Down
19 changes: 10 additions & 9 deletions src/core/dedupe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,35 @@ export default class DedupeAdapter {
this.limit = new Map()
}

cancel (requestId: string) {
const controller = this.limit.get(requestId)
public cancel (requestKey: string) {
const controller = this.limit.get(requestKey)

if (controller)
controller.abort()
}

cancelAll () {
public cancelAll () {
for (const controller of this.limit.values())
controller.abort()
}

adapter (): AxiosAdapter {
public adapter (): AxiosAdapter {
// eslint-disable-next-line @typescript-eslint/promise-function-async
return (config) => {
const requestId = config.requestId
const requestKey = config.requestKey ?? config.requestId

if (!requestId)
if (!requestKey)
return this.fetch(config)

this.cancel(requestId)
this.cancel(requestKey)

const controller = new AbortController()
const signal = controller.signal
const onAborted = () => {
controller.abort()
}

this.limit.set(requestId, controller)
this.limit.set(requestKey, controller)

if (config.signal)
config.signal.addEventListener?.('abort', onAborted)
Expand All @@ -47,7 +47,8 @@ export default class DedupeAdapter {
.then(resolve)
.catch(reject)
.finally(() => {
this.limit.delete(requestId)
if (this.limit.get(requestKey) === controller)
this.limit.delete(requestKey)

if (config.signal)
config.signal.removeEventListener?.('abort', onAborted)
Expand Down
Loading

0 comments on commit 82134bf

Please sign in to comment.