elbywan / wretch

A tiny wrapper built around fetch with an intuitive syntax. :candy:
MIT License
4.79k stars 96 forks source link

.polyfill is global #17

Closed tothandras closed 6 years ago

tothandras commented 6 years ago

From the documentation:

// Or the non-global way :

wretch().polyfills({
    fetch: require("node-fetch"),
    FormData: require("form-data"),
    URLSearchParams: require("url").URLSearchParams
})

There is a single config object shared between the wretch() instances, which means that it is currently impossible to use different fetch polyfills for each instance. The use case would be to handle cookie headers for different APIs in Node.js.

eg.

class API {
  constructor (url) {
      this.api = wretch()
        .url(url)
        .options({ credentials: 'include', redirect: 'follow', cache: 'no-store' })

    // Node.js environment
    if (typeof window === 'undefined') {
      const { CookieJar } = eval('require')('tough-cookie')
      const jar = new CookieJar()
      const fetch = eval('require')('./node/fetch')({ jar })
      const { Headers, Request } = fetch
      this.api.polyfills({
        fetch,
        FormData: eval('require')('form-data'),
        URLSearchParams: eval('require')('url').URLSearchParams,
      })
  }
}
elbywan commented 6 years ago

Hi @tothandras,

There is a single config object shared between the wretch() instances, which means that it is currently impossible to use different fetch polyfills for each instance. The use case would be to handle cookie headers for different APIs in Node.js.

It's not impossible actually. 😉 For your use case you could use .middlewares instead of .polyfills :

// Still globally polyfill FormData and URLSearchParams
wretch().polyfills({
    FormData: eval('require')('form-data'),
    URLSearchParams: eval('require')('url').URLSearchParams,
})

// Copy pasting most of your code here :
class API {
  constructor (url) {
    this.api = wretch()
      .url(url)
      .options({ credentials: 'include', redirect: 'follow', cache: 'no-store' })

  // Node.js environment
  if (typeof window === 'undefined') {
    const { CookieJar } = eval('require')('tough-cookie')
      const jar = new CookieJar()
      const fetch = eval('require')('./node/fetch')({ jar })
      const { Headers, Request } = fetch

      // Creating a middleware instead of using polyfills :
      const middleware = next => (url, options) => {
        // Return your own fetch polyfill instead of calling next
        // (next is the global fetch here since this middleware is the terminating one)
        return fetch(url, options)
      }

      // Then simply add the middleware to your api
      this.api = this.api.middlewares([middleware])
    }
}
tothandras commented 6 years ago

Thank you @elbywan, I'll give it a try!

UPDATE

It works if I reassign this.api, because .middlewares calls .selfFactory:

this.api = this.api.middlewares([middleware])

Thanks for the idea!