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

feat(useFetch): support sending the custom request to an absolute URL regardless baseURL #2210

Merged
merged 1 commit into from Nov 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 13 additions & 8 deletions packages/core/useFetch/index.test.ts
Expand Up @@ -127,20 +127,25 @@ describe('useFetch', () => {
})

test('should create an instance of useFetch with baseUrls', async () => {
const baseUrl = 'https://example.com'
const targetUrl = `${baseUrl}/test`
const fetchHeaders = { Authorization: 'test' }
const requestHeaders = { 'Accept-Language': 'en-US' }
const allHeaders = { ...fetchHeaders, ...requestHeaders }
const useMyFetchWithBaseUrl = createFetch({ baseUrl: 'https://example.com', fetchOptions: { headers: fetchHeaders } })
const requestOptions = { headers: requestHeaders }
const useMyFetchWithBaseUrl = createFetch({ baseUrl, fetchOptions: { headers: fetchHeaders } })
const useMyFetchWithoutBaseUrl = createFetch({ fetchOptions: { headers: fetchHeaders } })
useMyFetchWithBaseUrl('test', { headers: requestHeaders })
useMyFetchWithBaseUrl('/test', { headers: requestHeaders })
useMyFetchWithoutBaseUrl('https://example.com/test', { headers: requestHeaders })

useMyFetchWithBaseUrl('test', requestOptions)
useMyFetchWithBaseUrl('/test', requestOptions)
useMyFetchWithBaseUrl(targetUrl, requestOptions)
useMyFetchWithoutBaseUrl(targetUrl, requestOptions)

await retry(() => {
expect(fetchSpy).toHaveBeenCalledTimes(3)
expect(fetchSpy).toHaveBeenNthCalledWith(1, 'https://example.com/test', expect.anything())
expect(fetchSpy).toHaveBeenNthCalledWith(2, 'https://example.com/test', expect.anything())
expect(fetchSpy).toHaveBeenNthCalledWith(3, 'https://example.com/test', expect.anything())
expect(fetchSpy).toHaveBeenCalledTimes(4)
new Array(4).fill(0).forEach((x, i) => {
expect(fetchSpy).toHaveBeenNthCalledWith(i + 1, 'https://example.com/test', expect.anything())
})
expect(fetchSpyHeaders()).toMatchObject(allHeaders)
})
})
Expand Down
19 changes: 14 additions & 5 deletions packages/core/useFetch/index.ts
Expand Up @@ -183,7 +183,7 @@ export interface UseFetchOptions {

export interface CreateFetchOptions {
/**
* The base URL that will be prefixed to all urls
* The base URL that will be prefixed to all urls unless urls are absolute
*/
baseUrl?: MaybeComputedRef<string>

Expand All @@ -208,6 +208,11 @@ function isFetchOptions(obj: object): obj is UseFetchOptions {
return containsProp(obj, 'immediate', 'refetch', 'initialData', 'timeout', 'beforeFetch', 'afterFetch', 'onFetchError', 'fetch')
}

// A URL is considered absolute if it begins with "<scheme>://" or "//" (protocol-relative URL).
function isAbsoluteURL(url: string) {
return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url)
}

function headersToObject(headers: HeadersInit | undefined) {
if (typeof Headers !== 'undefined' && headers instanceof Headers)
return Object.fromEntries([...headers.entries()])
Expand All @@ -229,10 +234,14 @@ export function createFetch(config: CreateFetchOptions = {}) {
const _fetchOptions = config.fetchOptions || {}

function useFactoryFetch(url: MaybeComputedRef<string>, ...args: any[]) {
const computedUrl = computed(() => config.baseUrl
? joinPaths(resolveUnref(config.baseUrl), resolveUnref(url))
: resolveUnref(url),
)
const computedUrl = computed(() => {
const baseUrl = resolveUnref(config.baseUrl)
const targetUrl = resolveUnref(url)

return baseUrl && !isAbsoluteURL(targetUrl)
? joinPaths(baseUrl, targetUrl)
: targetUrl
})

let options = _options
let fetchOptions = _fetchOptions
Expand Down