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

release: 1.0.0 #65

Draft
wants to merge 16 commits into
base: main
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ out

# Nuxt.js build / generate output
.nuxt
.output
dist

# Gatsby files
Expand Down
29 changes: 8 additions & 21 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,26 @@ on:
merge_group:
types: [checks_requested]

env:
NODE_VERSION: 20

jobs:
analyze:
runs-on: ${{ matrix.os }}
runs-on: ubuntu-latest

permissions:
actions: read
contents: read
security-events: write

strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
language:
- javascript

steps:
- name: Git Checkout
uses: actions/checkout@v3

- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
languages: javascript

- name: Autobuild
uses: github/codeql-action/autobuild@v2
Expand All @@ -44,15 +39,7 @@ jobs:
uses: github/codeql-action/analyze@v2

build:
runs-on: ${{ matrix.os }}

strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
node-version:
- 18
runs-on: ubuntu-latest

steps:
- name: Git Checkout
Expand All @@ -73,10 +60,10 @@ jobs:
restore-keys: |
${{ runner.os }}-yarn-

- name: Use Node.js ${{ matrix.node-version }}
- name: Use Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
node-version: ${{ env.NODE_VERSION }}
cache: "yarn"

- name: Install Deps
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ out

# Nuxt.js build / generate output
.nuxt
.output
dist

# Gatsby files
Expand Down
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
18
20
875 changes: 0 additions & 875 deletions .yarn/releases/yarn-3.8.3.cjs

This file was deleted.

64 changes: 59 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Find and replace all on all files (CMD+SHIFT+F):

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

## Compabilities
Expand Down Expand Up @@ -133,26 +133,80 @@ onResponseError(async (error) => {

## Queue

All request per instance will be add into queue before sent with priority `1`.
All request per instance will be add into queue before sent with priority MEDIUM (`20`).
If you want to send your request first before the others, you can set using option `priority`. The higher priority will run first.

```ts
import { QueuePriority } from '@privyid/nuapi/core'

useApi().get('/document/load', {
priority: 2,
// Using presets
priority: QueuePriority.HIGH,
// Or using number
priority: 50,
})
```

## Dedupe

Sometime, you want to cancel request with same endpoint like when you working with searching or filter.

NuAPI has built in function for this case. Just set `requestId`, multiple sent request with same id will cancel last request before.
NuAPI has built in function for this case. Just set `requestkey`, multiple sent request with same id will cancel last request before.

```ts
useApi().get('/document/load', {
requestId: 'document-load',
requestkey: 'document-load',
})
```

### Cancel Manually

Cancel spesific request by `requestKey` using `.cancel()`

```ts
useApi().cancel('document-load')
```

Or cancel all requests that have `requestKey` using `.cancelAll()`

```ts
useApi().cancelAll()
```

## Retry

NuAPI automatically retries request when got an error with status code:

- 408 - Request Timeout
- 409 - Conflict
- 425 - Too Early
- 429 - Too Many Requests
- 500 - Internal Server Error
- 502 - Bad Gateway
- 503 - Service Unavailable
- 504 - Gateway Timeout

By default will retries `3` times (except for `PATCH`, `POST`, `PUT`, `DELETE`) can be changed using option `retry`.

```ts
useApi().get('/document/load', {
retry: 5,
})
```

### Customize Retry Condition

You can customize when request should retries using `retryOn`

```ts
useApi().get('/document/load', {
retryOn (error) {
return getCode(error) === 423
&& error.config.retryCount < 3
},
})
```

## API

👉 You can learn more about usage in [JSDocs Documentation](https://www.jsdocs.io/package/@privyid/nuapi).
Expand Down
23 changes: 21 additions & 2 deletions msw.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ const server = setupServer(
await delay(2)
}),

http.all(`${BASE_URL}/api/echo`, async ({ request }) => {
return HttpResponse.json({
method : request.method,
headers: request.headers,
})
}),

http.get(`${BASE_URL}/api/ping`, () => {
return HttpResponse.json({ message: 'Pong' })
}),
Expand Down Expand Up @@ -55,8 +62,20 @@ const server = setupServer(
}, { status: 422 })
}),

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

http.get(`${BASE_URL}/api/error/unstable`, async function * () {
let count = 0

while (count < 2) {
yield HttpResponse.json({ data: { count } }, { status: 500 })

count++
}

return HttpResponse.json({ message: 'Pong', data: { count } })
}),
)

Expand Down
21 changes: 11 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@privyid/nuapi",
"version": "0.3.0-alpha.4",
"version": "0.3.0-alpha.6",
"description": "Nuxt HTTP Client module",
"packageManager": "yarn@4.4.0",
"repository": {
Expand Down Expand Up @@ -36,7 +36,7 @@
],
"scripts": {
"prepack": "yarn build",
"build": "nuxt-module-build",
"build": "nuxt-module-build build",
"dev": "nuxi dev playground",
"dev:build": "nuxi build playground",
"dev:prepare": "nuxt-module-build --stub && nuxi prepare playground",
Expand All @@ -47,11 +47,14 @@
"coverage": "vitest run src --coverage --config ./vitest.config.ts"
},
"dependencies": {
"@nuxt/kit": "^3.7.4",
"@nuxt/kit": "^3.12.4",
"axios": "^1.7.2",
"defu": "^6.1.2",
"ofetch": "^1.3.3",
"ufo": "^1.3.1"
"defu": "^6.1.4",
"ofetch": "^1.3.4",
"ufo": "^1.5.4"
},
"peerDependencies": {
"nuxt": ">=3.4.0"
},
"devDependencies": {
"@nuxt/eslint-config": "0.5.0",
Expand All @@ -62,25 +65,23 @@
"@privyid/nhp": "1.0.0",
"@typescript-eslint/eslint-plugin": "5.62.0",
"@typescript-eslint/parser": "5.62.0",
"@vitest/coverage-c8": "0.30.1",
"@vitest/coverage-v8": "^2.0.5",
"@vue/eslint-config-typescript": "13.0.0",
"axios-mock-adapter": "1.22.0",
"changelogen": "0.5.5",
"eslint": "8.57.0",
"eslint-config-standard-with-typescript": "34.0.1",
"eslint-formatter-pretty": "5.0.0",
"eslint-plugin-align-assignments": "1.1.2",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-n": "15.7.0",
"eslint-plugin-n": "14.0.0",
"eslint-plugin-promise": "6.6.0",
"eslint-plugin-unicorn": "46.0.1",
"eslint-plugin-varspacing": "1.2.2",
"eslint-plugin-vue": "9.27.0",
"msw": "2.3.5",
"nuxt": "3.12.4",
"typescript": "5.5.4",
"vitest": "0.30.1"
"vitest": "2.0.5"
},
"publishConfig": {
"access": "public"
Expand Down
3 changes: 2 additions & 1 deletion playground/nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { fileURLToPath } from 'node:url'
import MyModule from '../src/module'

export default defineNuxtConfig({
modules : ['@privyid/nhp', '../src/module'],
modules : ['@privyid/nhp', MyModule],
alias : { '@privyid/nuapi/core': fileURLToPath(new URL('../src/core/', import.meta.url)) },
nuapi : {},
typescript: {
Expand Down
59 changes: 14 additions & 45 deletions src/core/dedupe.spec.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,25 @@
import { http, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
import { useApi } from '.'
import {
useApi,
createApi,
setApi,
} from '.'
import {
beforeAll,
afterEach,
describe,
it,
expect,
afterAll,
} from 'vitest'

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

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

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

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

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

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

describe('DedupeAdapter', () => {
it('should cancel previous request with same requestId', async () => {
it('should cancel previous request with same requestKey', async () => {
const api = useApi()
const a = api.get('/api/ping', { requestId: 'ping' })
const b = api.get('/api/ping', { requestId: 'ping' })
const a = api.get('/api/ping', { requestKey: 'ping' })
const b = api.get('/api/ping', { requestKey: 'ping' })
const result = await Promise.allSettled([a, b])

expect(result[0].status).toBe('rejected')
expect(result[1].status).toBe('fulfilled')
})

it('should do nothing if requestId is different', async () => {
it('should do nothing if requestKey is different', async () => {
const api = useApi()
const a = api.get('/api/ping', { requestId: 'ping/a' })
const b = api.get('/api/ping', { requestId: 'ping/b' })
const a = api.get('/api/ping', { requestKey: 'ping/a' })
const b = api.get('/api/ping', { requestKey: 'ping/b' })
const result = await Promise.allSettled([a, b])

expect(result[0].status).toBe('fulfilled')
Expand All @@ -62,8 +31,8 @@ describe('DedupeAdapter', () => {
const controller = new AbortController()
const signal = controller.signal

const a = api.get('/api/ping', { requestId: 'ping/d', signal })
const b = api.get('/api/ping', { requestId: 'ping/e' })
const a = api.get('/api/ping', { requestKey: 'ping/d', signal })
const b = api.get('/api/ping', { requestKey: 'ping/e' })

controller.abort()

Expand All @@ -75,10 +44,10 @@ describe('DedupeAdapter', () => {
})

describe('cancel', () => {
it('should be cancel request only specific requestId', async () => {
it('should be cancel request only specific requestKey', async () => {
const api = useApi()
const a = api.get('/api/ping', { requestId: 'ping/i' })
const b = api.get('/api/ping', { requestId: 'ping/j' })
const a = api.get('/api/ping', { requestKey: 'ping/i' })
const b = api.get('/api/ping', { requestKey: 'ping/j' })

api.cancel('ping/i')

Expand All @@ -92,8 +61,8 @@ describe('cancel', () => {
describe('cancelAll', () => {
it('should be cancel all active request', async () => {
const api = useApi()
const a = api.get('/api/ping', { requestId: 'ping/x' })
const b = api.get('/api/ping', { requestId: 'ping/y' })
const a = api.get('/api/ping', { requestKey: 'ping/x' })
const b = api.get('/api/ping', { requestKey: 'ping/y' })

api.cancelAll()

Expand Down
Loading
Loading