Why
ky has both prefix and baseUrl. They interact (prefix is joined with slashes, then baseUrl is resolved). Users get confused. We should make a deliberate, documented choice before v0.1 ships.
Evidence
- ky
source/types/options.ts:142, 168, source/core/Ky.ts:376, 389-399.
- ofetch has just
baseURL and withBase() (src/utils.url.ts:40-51) — simpler, but vulnerable to a known SSRF prefix attack (ofetch #568).
- redaxios has
baseURL only (line 187).
Decision needed
Option A: baseURL only (ofetch / axios style)
baseURL: 'https://api.example.com'
misina.get('users/42') // → https://api.example.com/users/42
misina.get('/users/42') // → https://api.example.com/users/42
misina.get('https://other') // → https://other (absolute wins)
Pros: simplest. Cons: less expressive when version-prefixing.
Option B: baseURL + prefix (ky style)
baseURL: 'https://api.example.com', prefix: '/v2'
misina.get('users/42') // → https://api.example.com/v2/users/42
Pros: clean version bumps via .extend({ prefix: '/v3' }). Cons: extra concept.
Option C: drop both, just take URL
Force users to pass a URL object built however. Cons: too rigid for the 80% case.
Open questions
- Absolute URL precedence — does an absolute URL always override
baseURL? axios has allowAbsoluteUrls: false to forbid this (security). We probably want allowAbsoluteUrls: true (default) for ergonomics, but expose the flag.
- SSRF prefix attack — if
baseURL: 'http://api.internal', an attacker passing http://api.internal.attacker.com should fail because hostname differs. Use URL parsing + hostname check, never startsWith (the ofetch bug).
- Slash normalization — collapse
// between baseURL and path; preserve ? query.
Proposal
Recommend Option A (baseURL only) for v0.1 — simpler, matches ofetch/axios. Add prefix later if real demand surfaces. Always parse with new URL(input, baseURL) — never string concat.
allowAbsoluteUrls: boolean defaults to true but is exposed for security-sensitive deployments.
Refs: ky source/core/Ky.ts:389-399, ofetch src/utils.url.ts:40-51, ofetch issue #568, axios lib/core/buildFullPath.js.
Why
ky has both
prefixandbaseUrl. They interact (prefix is joined with slashes, then baseUrl is resolved). Users get confused. We should make a deliberate, documented choice before v0.1 ships.Evidence
source/types/options.ts:142, 168,source/core/Ky.ts:376, 389-399.baseURLandwithBase()(src/utils.url.ts:40-51) — simpler, but vulnerable to a known SSRF prefix attack (ofetch #568).baseURLonly (line 187).Decision needed
Option A:
baseURLonly (ofetch / axios style)Pros: simplest. Cons: less expressive when version-prefixing.
Option B:
baseURL+prefix(ky style)Pros: clean version bumps via
.extend({ prefix: '/v3' }). Cons: extra concept.Option C: drop both, just take
URLForce users to pass a
URLobject built however. Cons: too rigid for the 80% case.Open questions
baseURL? axios hasallowAbsoluteUrls: falseto forbid this (security). We probably wantallowAbsoluteUrls: true(default) for ergonomics, but expose the flag.baseURL: 'http://api.internal', an attacker passinghttp://api.internal.attacker.comshould fail because hostname differs. UseURLparsing + hostname check, neverstartsWith(the ofetch bug).//between baseURL and path; preserve?query.Proposal
Recommend Option A (
baseURLonly) for v0.1 — simpler, matches ofetch/axios. Addprefixlater if real demand surfaces. Always parse withnew URL(input, baseURL)— never string concat.allowAbsoluteUrls: booleandefaults totruebut is exposed for security-sensitive deployments.Refs: ky
source/core/Ky.ts:389-399, ofetchsrc/utils.url.ts:40-51, ofetch issue #568, axioslib/core/buildFullPath.js.