Skip to content

Commit a620641

Browse files
DeniKucevicDenis Kucevicphryneas
authored
Feature/docs re authorization mutex example (#1947)
* chore(dependencies): add async-mutex dependency * docs(customizing-queries): add mutex example for re-authorization * fix(customizing-queries): fixing typo * Update docs/rtk-query/usage/customizing-queries.mdx Co-authored-by: Denis Kucevic <denis.kucevic@advania.is> Co-authored-by: Lenz Weber <mail@lenzw.de>
1 parent 71a61fc commit a620641

File tree

3 files changed

+85
-0
lines changed

3 files changed

+85
-0
lines changed

docs/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"@types/react": "^16.9.46",
77
"@types/react-redux": "^7.1.9",
88
"@types/redux-logger": "^3.0.8",
9+
"async-mutex": "^0.3.2",
910
"axios": "^0.20.0",
1011
"formik": "^2.1.5",
1112
"graphql-request": "^3.4.0",

docs/rtk-query/usage/customizing-queries.mdx

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,80 @@ const baseQueryWithReauth: BaseQueryFn<
390390
}
391391
```
392392

393+
#### Preventing multiple unauthorized errors
394+
395+
Using [`async-mutex`](https://github.com/DirtyHairy/async-mutex) to prevent multiple calls to '/refreshToken' when multiple calls fail with [`401 Unauthorized`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401) errors.
396+
397+
```ts title="Preventing multiple calls to '/refreshToken'"
398+
// file: authSlice.ts noEmit
399+
declare function tokenReceived(args?: any): void
400+
declare function loggedOut(): void
401+
export { tokenReceived, loggedOut }
402+
// file: baseQueryWithReauth.ts
403+
404+
import {
405+
BaseQueryFn,
406+
FetchArgs,
407+
fetchBaseQuery,
408+
FetchBaseQueryError,
409+
} from '@reduxjs/toolkit/query'
410+
import { tokenReceived, loggedOut } from './authSlice'
411+
// highlight-start
412+
import { Mutex } from 'async-mutex'
413+
// highlight-end
414+
415+
// create a new mutex
416+
// highlight-start
417+
const mutex = new Mutex()
418+
// highlight-end
419+
const baseQuery = fetchBaseQuery({ baseUrl: '/' })
420+
const baseQueryWithReauth: BaseQueryFn<
421+
string | FetchArgs,
422+
unknown,
423+
FetchBaseQueryError
424+
> = async (args, api, extraOptions) => {
425+
// wait until the mutex is available without locking it
426+
// highlight-start
427+
await mutex.waitForUnlock()
428+
// highlight-end
429+
let result = await baseQuery(args, api, extraOptions)
430+
if (result.error && result.error.status === 401) {
431+
// checking whether the mutex is locked
432+
// highlight-start
433+
if (!mutex.isLocked()) {
434+
const release = await mutex.acquire()
435+
// highlight-end
436+
try {
437+
const refreshResult = await baseQuery(
438+
'/refreshToken',
439+
api,
440+
extraOptions
441+
)
442+
if (refreshResult.data) {
443+
api.dispatch(tokenReceived(refreshResult.data))
444+
// retry the initial query
445+
result = await baseQuery(args, api, extraOptions)
446+
} else {
447+
api.dispatch(loggedOut())
448+
}
449+
} finally {
450+
// release must be called once the mutex should be released again.
451+
// highlight-start
452+
release()
453+
// highlight-end
454+
}
455+
} else {
456+
// wait until the mutex is available without locking it
457+
// highlight-start
458+
await mutex.waitForUnlock()
459+
// highlight-end
460+
result = await baseQuery(args, api, extraOptions)
461+
}
462+
}
463+
return result
464+
}
465+
```
466+
393467
### Automatic retries
394468

395469
RTK Query exports a utility called `retry` that you can wrap the `baseQuery` in your API definition with. It defaults to 5 attempts with a basic exponential backoff.

yarn.lock

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8003,6 +8003,15 @@ __metadata:
80038003
languageName: node
80048004
linkType: hard
80058005

8006+
"async-mutex@npm:^0.3.2":
8007+
version: 0.3.2
8008+
resolution: "async-mutex@npm:0.3.2"
8009+
dependencies:
8010+
tslib: ^2.3.1
8011+
checksum: 620b771dfdea1cad0a6b712915c31a1e3ca880a8cf1eae92b4590f435995e0260929c6ebaae0b9126b1456790ea498064b5bb9a506948cda760f48d3d0dcc4c8
8012+
languageName: node
8013+
linkType: hard
8014+
80068015
"async@npm:^2.6.2":
80078016
version: 2.6.3
80088017
resolution: "async@npm:2.6.3"
@@ -11311,6 +11320,7 @@ __metadata:
1131111320
"@types/react": ^16.9.46
1131211321
"@types/react-redux": ^7.1.9
1131311322
"@types/redux-logger": ^3.0.8
11323+
async-mutex: ^0.3.2
1131411324
axios: ^0.20.0
1131511325
formik: ^2.1.5
1131611326
graphql-request: ^3.4.0

0 commit comments

Comments
 (0)