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

chain beforeFetch/afterFetch/onFetchError from createFetch and useFetch #1310

Closed
4 tasks done
Glandos opened this issue Feb 23, 2022 · 4 comments · Fixed by #1545
Closed
4 tasks done

chain beforeFetch/afterFetch/onFetchError from createFetch and useFetch #1310

Glandos opened this issue Feb 23, 2022 · 4 comments · Fixed by #1545
Labels
enhancement New feature or request

Comments

@Glandos
Copy link
Contributor

Glandos commented Feb 23, 2022

Clear and concise description of the problem

Currently, a handler defined in createFetch can be overwritten in useFetch.

For example, we can define a createFetch with a global beforeFetch option to set a bearer token, and in the useFetch call, add a beforeFetch option to set some other needed headers.

Suggested solution

useFetchFactory should be able to chain beforeFetch/afterFetch/onFetchError instead of overwriting them.

Alternative

No response

Additional context

Manually chain for now:

const injectToken = function ({ options }: BeforeFetchContext) {
  options.headers = {
    ...options.headers,
    Authorization: `Bearer ${Vue.$auth.token()}`
  }

  return { options }
}

const useApiFetch = createFetch({
  baseUrl: '/api/v1',
  options: {
    beforeFetch: injectToken
  }
})

// fetchOptions comes from an external caller
useApiFetch(path, {
    immediate: false,
    initialData: defaultValue,
    // Complicated stuff to be able to workaround beforeFetch overwrite
    ...fetchOptions,
    ...(fetchOptions?.beforeFetch === undefined ? {} : {
      async beforeFetch (ctx) {
        ctx = {...ctx, ...injectToken(ctx)}
        ctx = {...ctx, ...(await fetchOptions.beforeFetch?.(ctx))}
        return ctx
      }
    })
  })

Validations

@Glandos Glandos added the enhancement New feature or request label Feb 23, 2022
tobyzerner added a commit to tobyzerner/vueuse that referenced this issue May 1, 2022
@stale
Copy link

stale bot commented Sep 14, 2022

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Sep 14, 2022
@brease-colin
Copy link

The chainCallbacks function does not work well with async beforeFetch functions. While it does execute them with an await, chainCallbacks itself never returns a promise and as such is not awaited before the actual fetch happens.

This bug cost me quite a while to find, unfortunately, and resulted in strange behavior.

@stale stale bot removed the stale label Sep 16, 2022
@Glandos
Copy link
Contributor Author

Glandos commented Sep 16, 2022

Indeed, @brease-colin seems right here.
My custom implementation is:

type ContextFunction<T = BeforeFetchContext | AfterFetchContext> = (ctx: T) =>
  ReturnType<Exclude<UseFetchOptions[T extends BeforeFetchContext ? 'beforeFetch' : 'afterFetch'], undefined>>

const mergeContextHandlers = <T = BeforeFetchContext | AfterFetchContext> (...handlers: (ContextFunction<T> | undefined)[]) => {
  return async (ctx: T) => {
    for (const handler of handlers) {
      if (handler !== undefined) {
        ctx = { ...ctx, ...(await handler(ctx)) }
      }
    }
    return ctx
  }
}

And it doesn't use a .forEach so it does return a Promise.
Feel free to reuse this code, I don't really have the time to open a PR for now.

@Glandos
Copy link
Contributor Author

Glandos commented Oct 18, 2022

Fixed by #2231

@Glandos Glandos closed this as completed Oct 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants