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 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.1",
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
- export default async ({ url: endpoint, ...options } = {}) => {
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
- let url, origin, prefix = '/'
32
- if (baseUrl) {
33
- const url = new URL(baseUrl)
34
- origin = url.origin
35
- prefix = url.pathname
36
- }
37
- try {
38
- url = new URL(endpoint)
39
- } catch (error) {
40
- url = new URL(
41
- /\/$/.test(prefix) && /^\//.test(endpoint)
42
- ? prefix + endpoint.substring(1)
43
- : prefix + endpoint,
44
- origin
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
- response = await fetch(url, {
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('fetchBaseQuery/query', error)
61
+ console.error(moduleName, error)
54
62
  }
55
- return responseFromError(error)
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, status = 0) => ({
2
- status,
3
- error: typeof error === 'string'
4
- ? { message: error }
5
- : error,
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
- ...(accessToken ? { Authorization: `bearer ${accessToken}` } : {}),
30
+ ...(getAuthorizationHeaders(getAccessToken(payload))),
25
31
  ...(headers || {})
26
32
  })
27
33
  })
28
- status = response.status
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('fetchBaseQuery/middlewares/accessToken', error)
51
+ console.error(moduleName, error)
40
52
  }
41
- return responseFromError(error, status)
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
- return { status, error: true, message: error.message, headers }
7
+ reply = { status, error: true, message: error.message || error, headers }
5
8
  } else if (data) {
6
9
  if (data.success) {
7
- return { ...data, status, headers }
10
+ reply = { ...data, status, headers }
8
11
  } else if (data.error) {
9
- return { status, error: true, message: data.message, headers }
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
- return { status, error: true, message: 'Unexpected format of common response body.', headers }
16
+ } else {
17
+ reply = { status, headers }
12
18
  }
13
- return { status, headers }
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('fetchBaseQuery/middlewares/accessToken', error)
74
+ console.error(moduleName, error)
74
75
  }
75
- return responseFromError(error, status)
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
- return { status, error, headers }
12
- }
13
- let data
14
- try {
15
- if (isJsonBody(response) && response.json) {
16
- data = await response.json()
17
- }
18
- } catch (error) {
19
- if (options.logErrors) {
20
- console.error('fetchBaseQuery/middlewares/jsonReply', error)
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
- return { status, data, headers }
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 fetchInit = {
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 queryFn = (options: fetchInit | any | undefined) => Promise<any>;
35
- export type Middleware = (settings: any) => (query: queryFn) => queryFn;
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 fetchBaseQueryInit = {
49
+ export type FetchBaseQueryOptions = {
38
50
  baseUrl: URL | string | undefined,
39
- baseQuery: queryFn,
40
- middlewares: Array<Middleware>
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;