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

retry failed request in the onResponse middleware #2075

Open
pavlo-hadzheha opened this issue Dec 31, 2024 · 3 comments
Open

retry failed request in the onResponse middleware #2075

pavlo-hadzheha opened this issue Dec 31, 2024 · 3 comments
Labels
enhancement New feature or request openapi-fetch Relevant to the openapi-fetch library

Comments

@pavlo-hadzheha
Copy link

pavlo-hadzheha commented Dec 31, 2024

Hello there! I've been trying to implement the refresh session functionality for quite some time using the response middleware.

The stumbling block is to retry the failed request inside the middleware. In the following code snippet, I am registering the Middleware and in the onResponse handler I'd like to add the retry line of the original request (look for the comment '// retry request here').

Any consultation would be greatly appreciated.

import { authService, TLoginResponse } from '@/shared/auth'
import { Middleware } from 'openapi-fetch'

let refreshPromise: Promise<TLoginResponse | undefined> | null = null

export const middleware: Middleware = {
  async onResponse({ response, request }) {
    if (response.ok) return response
    else {
      if (response.status === 401) {
        try {
          if (!refreshPromise) {
            refreshPromise = authService.refreshSession()
          }
          const refreshResponse = await refreshPromise
          if (refreshResponse) {
            authService.setAccessToken(refreshResponse)
            authService.setRefreshToken(refreshResponse)

            request.headers.set('Authorization', `Bearer ${refreshResponse.accessToken}`)
            try {
              return // retry request here
            } catch (innerError) {
              if (innerError.status === 401) {
                throw innerError
              }
            }
          }
        } catch (error) {
          authService.setRefreshToken({ refreshToken: null })
          authService.setAccessToken({ accessToken: null })
        } finally {
          refreshPromise = null
        }
      }
    }
  },
}
@pavlo-hadzheha pavlo-hadzheha added enhancement New feature or request openapi-fetch Relevant to the openapi-fetch library labels Dec 31, 2024
@pavlo-hadzheha
Copy link
Author

pavlo-hadzheha commented Dec 31, 2024

I thought of an ability to call the coreFetch function with fetchOptions passed to the original request.

export const middleware: Middleware = {
  async onResponse({ response, request, originalFetchOptions, schemaPath }) {
    client.coreFetch(schemaPath, initialFeatchOptions)
 }
}

or

export const middleware: Middleware = {
  async onResponse({ response, request }) {
    client.coreFetch(request)
 }
}

Both imply that the coreFetch function would have to be returned from the createClient initializer and the latter implies that the coreFetch would handle the first parameter by branching using the following condition

if (schemaPath instanceof Request) {
  ...
} else {
  ...
}

@pavlo-hadzheha
Copy link
Author

Let me know if it makes any sense at all. Or, perhaps, there are easier ways to achieve this w/o making changes to the source code. Thanks!

@pavlo-hadzheha
Copy link
Author

pavlo-hadzheha commented Dec 31, 2024

I've got one more idea and it's to use native fetch just like this. Are there any potential problems with this I need to be aware of?

import { authService, TLoginResponse } from '@/shared/auth'
import { Middleware } from 'openapi-fetch'

let refreshPromise: Promise<TLoginResponse | undefined> | null = null

export const middleware: Middleware = {
  async onResponse({ response, request }) {
    if (response.ok) return response
    else {
      if (response.status === 401) {
        try {
          // ...

          if (refreshResponse) {
            // ...

            try {
              return fetch(request)
            } catch (innerError) {
              if (innerError.status === 401) {
                throw innerError
              }
            }
          }
        } catch (error) {
          // ...
        } finally {
          refreshPromise = null
        }
      }
    }
  },
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request openapi-fetch Relevant to the openapi-fetch library
Projects
None yet
Development

No branches or pull requests

1 participant