-
-
Notifications
You must be signed in to change notification settings - Fork 436
Add baseUrl option, rename prefix, and allow leading slashes in input #606
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
base: main
Are you sure you want to change the base?
Changes from all commits
41ffd18
e5c8e32
e626944
913d104
351020a
9335149
ad5fa3e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -159,7 +159,7 @@ Type: `string` | `URL` | `Request` | |
|
|
||
| Same as [`fetch` input](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#input). | ||
|
|
||
| When using a [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) instance as `input`, any URL altering options (such as `prefixUrl`) will be ignored. | ||
| When using a [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) instance as `input`, any URL altering options (such as `prefix`) will be ignored. | ||
|
|
||
| #### options | ||
|
|
||
|
|
@@ -191,29 +191,55 @@ Search parameters to include in the request URL. Setting this will override all | |
|
|
||
| Accepts any value supported by [`URLSearchParams()`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/URLSearchParams). | ||
|
|
||
| ##### prefixUrl | ||
| ##### baseUrl | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be great to have a matrix like you added in the original pull request description for both the baseUrl and prefix sections that goes through the motions of showing most (if not all) relevant permutations of baseUrl (or prefix), input and the resulting request URL. This could help de-mystify what both options do and what might be appropriate for any given use case. I think that's especially useful because not all people will know that "prefix" and "base URL" mean (sometimes subtly) different things (of course these docs make that clear, but still). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was originally going to do that but it felt like a lot of information all at once and made the choices seem complex, which could actually be more confusing than helpful. I went with a simple, explicit recommendation to use I think we should see what questions come up and then make tweaks based on that. If there ends up being a lot, we could add a full matrix of examples to the FAQ. What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm perfectly fine with that. My angle is mainly that I think there might be a lot of (potential) users coming from contexts where all they need is setting some API prefix string (e.g. Since it might never occur to them that there can even be a difference between both cases, they might also just gloss over the documentation for prefix and baseUrl assuming (wrongly) that surely it behaves as expected. A tabular representation of the "concatenation" behavior might be a bit of an easier "catch" while reading the docs. But again, I'm perfectly fine with not having that explained in a tabular manner. |
||
|
|
||
| Type: `string | URL` | ||
|
|
||
| A prefix to prepend to the `input` URL when making the request. It can be any valid URL, either relative or absolute. A trailing slash `/` is optional and will be added automatically, if needed, when it is joined with `input`. Only takes effect when `input` is a string. The `input` argument cannot start with a slash `/` when using this option. | ||
| A base to [resolve](https://developer.mozilla.org/en-US/docs/Web/API/URL_API/Resolving_relative_references) relative `input` URLs. When the `input` (after applying the `prefix` option) is only a partial URL, such as `'users'`, `'/users'`, or `'//my-site.com'`, it will be resolved against the `baseUrl` to determine the destination of the request. Otherwise, the input is absolute, such as `'https://my-site.com'`, and it will bypass the `baseUrl`. | ||
|
|
||
| Useful when used with [`ky.extend()`](#kyextenddefaultoptions) to create niche-specific Ky-instances. | ||
|
|
||
| When setting a `baseUrl` that has a path, we recommend that it includes a trailing slash `/`, as in `'/api/'` or `'https://my-site.com/api/'`, so that directory-relative `input` URLs, such as `'users'` or `'./users'`, use the full path of the `baseUrl` instead of just replacing its last path segment. | ||
|
|
||
| If the `baseUrl` itself is relative, it will be resolved against the environment's base URL, such as [`document.baseURI`](https://developer.mozilla.org/en-US/docs/Web/API/Node/baseURI) in browsers or `location.href` in Deno, which can be set with the `--location` flag. | ||
|
|
||
| ```js | ||
| import ky from 'ky'; | ||
|
|
||
| // On https://example.com | ||
|
|
||
| const response = await ky('users', {baseUrl: '/api/'}); | ||
| //=> 'https://example.com/api/users' | ||
|
|
||
| const response = await ky('/user', {baseUrl: '/api/'}); | ||
| //=> 'https://example.com/user' | ||
| ``` | ||
|
|
||
| ##### prefix | ||
|
|
||
| Type: `string | URL` | ||
|
|
||
| A prefix to prepend to the `input` URL before making the request. It can be any valid path or URL, either relative or absolute. A trailing slash `/` is optional and will be added automatically, if needed, when it is joined with `input`. Only takes effect when `input` is a string. | ||
|
|
||
| Useful when used with [`ky.extend()`](#kyextenddefaultoptions) to create niche-specific Ky-instances. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is |
||
|
|
||
| In most cases, you should use the `baseUrl` option instead, as it is more consistent with web standards. The main use-case for the `prefix` option is to treat `input` URLs that start with a leading slash `/` as page-relative rather than origin-relative. | ||
|
|
||
| ```js | ||
| import ky from 'ky'; | ||
|
|
||
| // On https://example.com | ||
|
|
||
| const response = await ky('unicorn', {prefixUrl: '/api'}); | ||
| //=> 'https://example.com/api/unicorn' | ||
| const response = await ky('users', {baseUrl: '/api/'}); | ||
| //=> 'https://example.com/api/users' | ||
|
|
||
| const response2 = await ky('unicorn', {prefixUrl: 'https://cats.com'}); | ||
| //=> 'https://cats.com/unicorn' | ||
| const response = await ky('/user', {baseUrl: '/api/'}); | ||
| //=> 'https://example.com/api/user' | ||
| ``` | ||
|
|
||
| Notes: | ||
| - After `prefixUrl` and `input` are joined, the result is resolved against the [base URL](https://developer.mozilla.org/en-US/docs/Web/API/Node/baseURI) of the page (if any). | ||
| - Leading slashes in `input` are disallowed when using this option to enforce consistency and avoid confusion about how the `input` URL is handled, given that `input` will not follow the normal URL resolution rules when `prefixUrl` is being used, which changes the meaning of a leading slash. | ||
| - The `prefix` and `input` are joined with a slash `/` and deduplicated with any adjacent slashes already present in `prefix` or `input`. | ||
| - After `prefix` and `input` are joined, the result is resolved against the `baseUrl` option, if present. | ||
|
|
||
| ##### retry | ||
|
|
||
|
|
@@ -570,9 +596,9 @@ You can also refer to parent defaults by providing a function to `.extend()`. | |
| ```js | ||
| import ky from 'ky'; | ||
|
|
||
| const api = ky.create({prefixUrl: 'https://example.com/api'}); | ||
| const api = ky.create({prefix: 'https://example.com/api'}); | ||
|
|
||
| const usersApi = api.extend((options) => ({prefixUrl: `${options.prefixUrl}/users`})); | ||
| const usersApi = api.extend((options) => ({prefix: `${options.prefix}/users`})); | ||
|
|
||
| const response = await usersApi.get('123'); | ||
| //=> 'https://example.com/api/users/123' | ||
|
|
@@ -590,12 +616,12 @@ import ky from 'ky'; | |
|
|
||
| // On https://my-site.com | ||
|
|
||
| const api = ky.create({prefixUrl: 'https://example.com/api'}); | ||
| const api = ky.create({prefix: 'https://example.com/api'}); | ||
|
|
||
| const response = await api.get('users/123'); | ||
| //=> 'https://example.com/api/users/123' | ||
|
|
||
| const response = await api.get('/status', {prefixUrl: ''}); | ||
| const response = await api.get('/status', {prefix: ''}); | ||
| //=> 'https://my-site.com/status' | ||
| ``` | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import test from 'ava'; | ||
| import ky from '../source/index.js'; | ||
| import {createHttpTestServer} from './helpers/create-http-test-server.js'; | ||
|
|
||
| test('baseUrl option', async t => { | ||
| const server = await createHttpTestServer(); | ||
| server.get('/', (_request, response) => { | ||
| response.end('/'); | ||
| }); | ||
| server.get('/foo', (_request, response) => { | ||
| response.end('/foo'); | ||
| }); | ||
| server.get('/bar', (_request, response) => { | ||
| response.end('/bar'); | ||
| }); | ||
| server.get('/foo/bar', (_request, response) => { | ||
| response.end('/foo/bar'); | ||
| }); | ||
|
|
||
| t.is( | ||
| // @ts-expect-error {baseUrl: boolean} isn't officially supported | ||
| await ky(`${server.url}/foo/bar`, {baseUrl: false}).text(), | ||
| '/foo/bar', | ||
| ); | ||
| t.is(await ky(`${server.url}/foo/bar`, {baseUrl: ''}).text(), '/foo/bar'); | ||
| t.is(await ky(new URL(`${server.url}/foo/bar`), {baseUrl: ''}).text(), '/foo/bar'); | ||
| t.is(await ky('foo/bar', {baseUrl: server.url}).text(), '/foo/bar'); | ||
| t.is(await ky('foo/bar', {baseUrl: new URL(server.url)}).text(), '/foo/bar'); | ||
| t.is(await ky('/bar', {baseUrl: `${server.url}/foo/`}).text(), '/bar'); | ||
| t.is(await ky('/bar', {baseUrl: `${server.url}/foo`}).text(), '/bar'); | ||
| t.is(await ky('bar', {baseUrl: `${server.url}/foo/`}).text(), '/foo/bar'); | ||
| t.is(await ky('bar', {baseUrl: `${server.url}/foo`}).text(), '/bar'); | ||
| t.is(await ky('bar', {baseUrl: new URL(`${server.url}/foo`)}).text(), '/bar'); | ||
| t.is(await ky('', {baseUrl: server.url}).text(), '/'); | ||
| t.is(await ky('', {baseUrl: `${server.url}/`}).text(), '/'); | ||
| t.is(await ky('', {baseUrl: new URL(server.url)}).text(), '/'); | ||
|
|
||
| await server.close(); | ||
| }); |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need even clearer docs about the difference between
baseUrlandprefixand when to use each. Maybe with some real-world example use-cases. Otherwise, it's going to be confusing for users and that ends up being a support burden for us.