Skip to content
Eugene Lazutkin edited this page Jul 1, 2026 · 5 revisions

Request keys & URLs

double-meh derives a canonical request key and the final URL from options. The key (io.makeKey) identifies a request for tracking and caching; io.buildUrl produces the URL actually sent, applying double-meh's query construction rules.

import io from 'double-meh';

io.buildUrl({url: 'https://api.example.com/x', query: {a: 1, b: 2}});
// 'https://api.example.com/x?a=1&b=2'

io.makeKey({url: 'https://api.example.com/x', query: {a: 1, b: 2}});
// 'GET https://api.example.com/x?a=1&b=2'

io.makeKey(options)

The key is METHOD (upper-cased) + a space + the WHATWG-normalized URL with its query sorted and its fragment dropped. Two requests that differ only in query order or #hash produce the same key.

const a = io.makeKey({url: 'https://api.example.com/x?b=2&a=1#frag'});
const b = io.makeKey({url: 'https://api.example.com/x', query: {a: 1, b: 2}});
a === b;              // true
a; // 'GET https://api.example.com/x?a=1&b=2'

io.buildUrl(options)

Builds the query from the options and appends it to options.url (with ? or & as appropriate). Unlike the key, the sent URL keeps the query in insertion order.

io.buildUrl({url: 'https://api.example.com/x'});               // no query -> unchanged
io.buildUrl({url: 'https://api.example.com/x?p=1', query: {q: 2}});
// 'https://api.example.com/x?p=1&q=2'

Query construction

The query source is options.query, or for read verbs (GET/HEAD/OPTIONS/DELETE) the data argument. An object becomes a parameter bag; array values repeat the key.

await io.get(url, {tag: ['a', 'b'], page: 2}); // ?tag=a&tag=b&page=2

A scalar (string, number, boolean) becomes a raw, keyless query segment:

await io.get(url, 'a=1&b=2'); // ?a=1&b=2
await io.get(url, 123);       // ?123

An empty string, null, or undefined contributes no query:

await io.get(url, '');        // no query
await io.get(url, null);      // no query
await io.get(url, undefined); // no query

fields, sort, expand

These array options are joined with commas into their own params, alongside any object/scalar query above.

io.buildUrl({
  url: 'https://api.example.com/x',
  query: {q: 'text'},
  fields: ['id', 'name'],
  sort: ['-created'],
  expand: ['author']
});
// 'https://api.example.com/x?q=text&fields=id,name&sort=-created&expand=author'

See also

Clone this wiki locally