fetchbasequery 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -1
- package/package.json +2 -1
- package/src/baseQuery.js +30 -19
- package/src/helpers/responseFromError.js +5 -7
- package/src/middlewares/accessToken.js +24 -9
- package/src/middlewares/commonReply.js +14 -5
- package/src/middlewares/encodeBody.js +7 -3
- package/src/middlewares/jsonReply.js +22 -12
- package/types/index.d.ts +30 -7
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ const query = fetchBaseQuery({
|
|
|
19
19
|
accessToken({
|
|
20
20
|
getAccessToken: () => localStorage.getItem('access_token'),
|
|
21
21
|
setAccessToken: (token) => localStorage.setItem('access_token', token),
|
|
22
|
-
getUpdatedAccessToken: (response) => response.headers.get('X-Access-Token')
|
|
22
|
+
getUpdatedAccessToken: async (response) => response.headers.get('X-Access-Token')
|
|
23
23
|
}),
|
|
24
24
|
jsonReply(),
|
|
25
25
|
commonReply()
|
|
@@ -41,6 +41,16 @@ if (success) {
|
|
|
41
41
|
}
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
+
Using instance of `Request`:
|
|
45
|
+
|
|
46
|
+
```js
|
|
47
|
+
// for example inside ServiceWorker
|
|
48
|
+
addEventListener('fetch', evt => {
|
|
49
|
+
const { request } = evt
|
|
50
|
+
return evt.respondWith(query({ request }))
|
|
51
|
+
})
|
|
52
|
+
```
|
|
53
|
+
|
|
44
54
|
It works fine both on frontend and backend sides. For backend side usage Node.js v18+ is required,
|
|
45
55
|
because the middleware `baseQuery` based on `Fetch API`. But it can be replaced with your own
|
|
46
56
|
implementation based on another API (e.g. based on `axios` etc).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fetchbasequery",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "Library for easily make HTTP queries without mass of boilerplate code.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/fetchBaseQuery.js",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"scripts": {
|
|
9
9
|
},
|
|
10
10
|
"keywords": [
|
|
11
|
+
"fetch", "fetchBaseQuery"
|
|
11
12
|
],
|
|
12
13
|
"author": "h41ku <h41ku.c0de@ya.ru>",
|
|
13
14
|
"license": "MIT",
|
package/src/baseQuery.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import responseFromError from './helpers/responseFromError.js'
|
|
2
2
|
import purge from './helpers/purge.js'
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
const moduleName = 'fetchBaseQuery/baseQuery'
|
|
5
|
+
|
|
6
|
+
export default async ({ url: endpoint, request: subject, ...options } = {}) => {
|
|
5
7
|
const {
|
|
6
8
|
baseUrl,
|
|
7
9
|
logErrors,
|
|
10
|
+
debug,
|
|
8
11
|
...restOptions
|
|
9
12
|
} = {
|
|
10
13
|
logErrors: false,
|
|
@@ -26,33 +29,41 @@ export default async ({ url: endpoint, ...options } = {}) => {
|
|
|
26
29
|
const fetchOptions = purge({ method, headers, body, mode, credentials, cache, redirect,
|
|
27
30
|
referrer, referrerPolicy, integrity, keepalive, signal })
|
|
28
31
|
// do request
|
|
32
|
+
let request
|
|
29
33
|
let response
|
|
30
34
|
try {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
35
|
+
if (endpoint !== undefined) {
|
|
36
|
+
let url, origin, prefix = '/'
|
|
37
|
+
if (baseUrl) {
|
|
38
|
+
const url = new URL(baseUrl)
|
|
39
|
+
origin = url.origin
|
|
40
|
+
prefix = url.pathname
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
url = new URL(endpoint)
|
|
44
|
+
} catch (error) {
|
|
45
|
+
url = new URL(
|
|
46
|
+
/\/$/.test(prefix) && /^\//.test(endpoint)
|
|
47
|
+
? prefix + endpoint.substring(1)
|
|
48
|
+
: prefix + endpoint,
|
|
49
|
+
origin
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
subject = url
|
|
46
53
|
}
|
|
47
|
-
|
|
54
|
+
request = new Request(subject, {
|
|
48
55
|
...defaultFetchOptions,
|
|
49
56
|
...fetchOptions
|
|
50
57
|
})
|
|
58
|
+
response = await fetch(request)
|
|
51
59
|
} catch (error) {
|
|
52
60
|
if (logErrors) {
|
|
53
|
-
console.error(
|
|
61
|
+
console.error(moduleName, error)
|
|
54
62
|
}
|
|
55
|
-
|
|
63
|
+
response = responseFromError(error)
|
|
64
|
+
}
|
|
65
|
+
if (debug?.baseQuery) {
|
|
66
|
+
console.log(moduleName, response)
|
|
56
67
|
}
|
|
57
68
|
return response
|
|
58
69
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
export default (error
|
|
2
|
-
|
|
3
|
-
error
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
headers: new Headers()
|
|
7
|
-
})
|
|
1
|
+
export default (error) => {
|
|
2
|
+
const response = Response.error()
|
|
3
|
+
response.error = error
|
|
4
|
+
return response
|
|
5
|
+
}
|
|
@@ -1,44 +1,59 @@
|
|
|
1
1
|
import responseFromError from '../helpers/responseFromError.js'
|
|
2
2
|
import purge from '../helpers/purge.js'
|
|
3
3
|
|
|
4
|
+
const moduleName = 'fetchBaseQuery/middlewares/accessToken'
|
|
5
|
+
|
|
4
6
|
export default (settings = {}) => query => async ({ payload, headers, ...options } = {}) => {
|
|
5
7
|
const {
|
|
6
8
|
getAccessToken,
|
|
7
9
|
setAccessToken,
|
|
8
10
|
isUnauthorized,
|
|
9
|
-
getUpdatedAccessToken
|
|
11
|
+
getUpdatedAccessToken,
|
|
12
|
+
getAuthorizationHeaders
|
|
10
13
|
} = {
|
|
11
14
|
getAccessToken: (payload) => undefined,
|
|
12
15
|
setAccessToken: (token) => {},
|
|
13
16
|
isUnauthorized: (response) => response.status === 401,
|
|
14
|
-
getUpdatedAccessToken: (response) => undefined,
|
|
17
|
+
getUpdatedAccessToken: async (response) => undefined,
|
|
18
|
+
getAuthorizationHeaders: (accessToken) => (
|
|
19
|
+
accessToken
|
|
20
|
+
? { Authorization: `bearer ${accessToken}` }
|
|
21
|
+
: {}
|
|
22
|
+
),
|
|
15
23
|
...settings
|
|
16
24
|
}
|
|
17
25
|
let response
|
|
18
|
-
let status = 0
|
|
19
26
|
try {
|
|
20
|
-
const accessToken = getAccessToken(payload)
|
|
21
27
|
response = await query({
|
|
22
28
|
...options,
|
|
23
29
|
headers: purge({
|
|
24
|
-
...(
|
|
30
|
+
...(getAuthorizationHeaders(getAccessToken(payload))),
|
|
25
31
|
...(headers || {})
|
|
26
32
|
})
|
|
27
33
|
})
|
|
28
|
-
|
|
34
|
+
} catch (error) {
|
|
35
|
+
if (options.logErrors) {
|
|
36
|
+
console.error(moduleName, error)
|
|
37
|
+
}
|
|
38
|
+
response = responseFromError(error)
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
29
41
|
if (isUnauthorized(response)) {
|
|
30
42
|
setAccessToken(null) // special case to remove access token from storage
|
|
31
43
|
} else {
|
|
32
|
-
const updatedAccessToken = getUpdatedAccessToken(response)
|
|
44
|
+
const updatedAccessToken = await getUpdatedAccessToken(response)
|
|
33
45
|
if (updatedAccessToken) {
|
|
34
46
|
setAccessToken(updatedAccessToken)
|
|
35
47
|
}
|
|
36
48
|
}
|
|
37
49
|
} catch (error) {
|
|
38
50
|
if (options.logErrors) {
|
|
39
|
-
console.error(
|
|
51
|
+
console.error(moduleName, error)
|
|
40
52
|
}
|
|
41
|
-
|
|
53
|
+
response = responseFromError(error)
|
|
54
|
+
}
|
|
55
|
+
if (options.debug?.accessToken) {
|
|
56
|
+
console.log(moduleName, response)
|
|
42
57
|
}
|
|
43
58
|
return response
|
|
44
59
|
}
|
|
@@ -1,14 +1,23 @@
|
|
|
1
|
+
const moduleName = 'fetchBaseQuery/middlewares/commonReply'
|
|
2
|
+
|
|
1
3
|
export default () => query => async (options) => {
|
|
2
4
|
const { status, data, error, headers } = await query(options)
|
|
5
|
+
let reply
|
|
3
6
|
if (error) {
|
|
4
|
-
|
|
7
|
+
reply = { status, error: true, message: error.message || error, headers }
|
|
5
8
|
} else if (data) {
|
|
6
9
|
if (data.success) {
|
|
7
|
-
|
|
10
|
+
reply = { ...data, status, headers }
|
|
8
11
|
} else if (data.error) {
|
|
9
|
-
|
|
12
|
+
reply = { status, error: true, message: data.message, headers }
|
|
13
|
+
} else {
|
|
14
|
+
reply = { status, error: true, message: 'Unexpected format of common response body.', headers }
|
|
10
15
|
}
|
|
11
|
-
|
|
16
|
+
} else {
|
|
17
|
+
reply = { status, headers }
|
|
12
18
|
}
|
|
13
|
-
|
|
19
|
+
if (options.debug?.commonReply) {
|
|
20
|
+
console.log(moduleName, reply)
|
|
21
|
+
}
|
|
22
|
+
return reply
|
|
14
23
|
}
|
|
@@ -2,6 +2,8 @@ import purge from '../helpers/purge.js'
|
|
|
2
2
|
import encodeJson from '../helpers/encodeJson.js'
|
|
3
3
|
import responseFromError from '../helpers/responseFromError.js'
|
|
4
4
|
|
|
5
|
+
const moduleName = 'fetchBaseQuery/middlewares/accessToken'
|
|
6
|
+
|
|
5
7
|
const getEncodedBody = body => (
|
|
6
8
|
typeof blob === 'string'
|
|
7
9
|
|| body instanceof String
|
|
@@ -56,7 +58,6 @@ export default (settings = {}) => (query) => async ({ body, headers, ...options
|
|
|
56
58
|
...settings
|
|
57
59
|
}
|
|
58
60
|
let response
|
|
59
|
-
let status = 0
|
|
60
61
|
try {
|
|
61
62
|
response = await query({
|
|
62
63
|
...options,
|
|
@@ -70,9 +71,12 @@ export default (settings = {}) => (query) => async ({ body, headers, ...options
|
|
|
70
71
|
})
|
|
71
72
|
} catch (error) {
|
|
72
73
|
if (options.logErrors) {
|
|
73
|
-
console.error(
|
|
74
|
+
console.error(moduleName, error)
|
|
74
75
|
}
|
|
75
|
-
|
|
76
|
+
response = responseFromError(error)
|
|
77
|
+
}
|
|
78
|
+
if (options.debug?.encodeBody) {
|
|
79
|
+
console.log(moduleName, response)
|
|
76
80
|
}
|
|
77
81
|
return response
|
|
78
82
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const moduleName = 'fetchBaseQuery/middlewares/jsonReply'
|
|
2
|
+
|
|
1
3
|
export default (settings = {}) => query => async (options = {}) => {
|
|
2
4
|
const {
|
|
3
5
|
isJsonBody
|
|
@@ -7,19 +9,27 @@ export default (settings = {}) => query => async (options = {}) => {
|
|
|
7
9
|
}
|
|
8
10
|
const response = await query(options)
|
|
9
11
|
const { status, error, headers } = response
|
|
12
|
+
let reply
|
|
10
13
|
if (error) {
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
reply = { status, error, headers }
|
|
15
|
+
} else {
|
|
16
|
+
let data
|
|
17
|
+
try {
|
|
18
|
+
if (isJsonBody(response)) {
|
|
19
|
+
data = await response.json()
|
|
20
|
+
reply = { status, data, headers }
|
|
21
|
+
} else {
|
|
22
|
+
reply = { status, headers }
|
|
23
|
+
}
|
|
24
|
+
} catch (error) {
|
|
25
|
+
if (options.logErrors) {
|
|
26
|
+
console.error(moduleName, error)
|
|
27
|
+
}
|
|
28
|
+
reply = { status, error, headers }
|
|
21
29
|
}
|
|
22
|
-
return { status, error, headers }
|
|
23
30
|
}
|
|
24
|
-
|
|
31
|
+
if (options.debug?.jsonReply) {
|
|
32
|
+
console.log(moduleName, reply)
|
|
33
|
+
}
|
|
34
|
+
return reply
|
|
25
35
|
}
|
package/types/index.d.ts
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
|
-
export type
|
|
1
|
+
export type DebuggingFlags = {
|
|
2
|
+
baseQuery: boolean | undefined,
|
|
3
|
+
encodeBody: boolean | undefined,
|
|
4
|
+
accessToken: boolean | undefined,
|
|
5
|
+
jsonReply: boolean | undefined,
|
|
6
|
+
commonReply: boolean | undefined
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type FetchOptions = {
|
|
2
10
|
logErrors: boolean | undefined,
|
|
11
|
+
url: URL | string | undefined,
|
|
12
|
+
request: Request | undefined,
|
|
3
13
|
method: string | undefined,
|
|
4
14
|
headers: object | undefined,
|
|
5
15
|
body: string
|
|
@@ -28,14 +38,27 @@ export type fetchInit = {
|
|
|
28
38
|
referrerPolicy: string | undefined,
|
|
29
39
|
integrity: string | undefined,
|
|
30
40
|
keepalive: boolean | undefined,
|
|
31
|
-
signal: AbortSignal | undefined
|
|
41
|
+
signal: AbortSignal | undefined,
|
|
42
|
+
debug: DebuggingFlags | undefined
|
|
32
43
|
};
|
|
33
44
|
|
|
34
|
-
export type
|
|
35
|
-
export type
|
|
45
|
+
export type baseQueryFn = (options: FetchOptions | undefined) => Promise<Response>;
|
|
46
|
+
export type queryFn = (options: FetchOptions | undefined) => Promise<any>;
|
|
47
|
+
export type middlewareFn = (settings: any) => (query: queryFn) => queryFn;
|
|
36
48
|
|
|
37
|
-
export type
|
|
49
|
+
export type FetchBaseQueryOptions = {
|
|
38
50
|
baseUrl: URL | string | undefined,
|
|
39
|
-
baseQuery:
|
|
40
|
-
middlewares: Array<
|
|
51
|
+
baseQuery: baseQueryFn | undefined,
|
|
52
|
+
middlewares: Array<middlewareFn>
|
|
41
53
|
};
|
|
54
|
+
|
|
55
|
+
export const baseQuery: baseQueryFn;
|
|
56
|
+
|
|
57
|
+
export const encodeBody: middlewareFn;
|
|
58
|
+
export const accessToken: middlewareFn;
|
|
59
|
+
export const jsonReply: middlewareFn;
|
|
60
|
+
export const commonReply: middlewareFn;
|
|
61
|
+
|
|
62
|
+
const fetchBaseQuery: (options: FetchBaseQueryOptions & FetchOptions) => queryFn;
|
|
63
|
+
|
|
64
|
+
export default fetchBaseQuery;
|