From ae870c1981dcb314b50e8f326c8b571841b4f58f Mon Sep 17 00:00:00 2001 From: Maksym Shenderuk Date: Wed, 28 Feb 2024 15:58:31 +0200 Subject: [PATCH] Request headers types (#2879) * Mention iterable in request headers type * Update type tests with iterable headers * Mention iterables in documentation --- docs/docs/api/Dispatcher.md | 42 ++++++++++++++++++++++++++++++--- test/types/dispatcher.test-d.ts | 11 +++++++++ types/dispatcher.d.ts | 2 +- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/docs/docs/api/Dispatcher.md b/docs/docs/api/Dispatcher.md index 0c678fc8623..5b18be7a84c 100644 --- a/docs/docs/api/Dispatcher.md +++ b/docs/docs/api/Dispatcher.md @@ -855,10 +855,12 @@ Emitted when dispatcher is no longer busy. ## Parameter: `UndiciHeaders` -* `Record | string[] | null` - -Header arguments such as `options.headers` in [`Client.dispatch`](Client.md#clientdispatchoptions-handlers) can be specified in two forms; either as an object specified by the `Record` (`IncomingHttpHeaders`) type, or an array of strings. An array representation of a header list must have an even length or an `InvalidArgumentError` will be thrown. +* `Record | string[] | Iterable<[string, string | string[] | undefined]> | null` +Header arguments such as `options.headers` in [`Client.dispatch`](Client.md#clientdispatchoptions-handlers) can be specified in three forms: +* As an object specified by the `Record` (`IncomingHttpHeaders`) type. +* As an array of strings. An array representation of a header list must have an even length, or an `InvalidArgumentError` will be thrown. +* As an iterable that can encompass `Headers`, `Map`, or a custom iterator returning key-value pairs. Keys are lowercase and values are not modified. Response headers will derive a `host` from the `url` of the [Client](Client.md#class-client) instance if no `host` header was previously specified. @@ -886,3 +888,37 @@ Response headers will derive a `host` from the `url` of the [Client](Client.md#c 'accept', '*/*' ] ``` + +### Example 3 - Iterable + +```js +new Headers({ + 'content-length': '123', + 'content-type': 'text/plain', + connection: 'keep-alive', + host: 'mysite.com', + accept: '*/*' +}) +``` +or +```js +new Map([ + ['content-length', '123'], + ['content-type', 'text/plain'], + ['connection', 'keep-alive'], + ['host', 'mysite.com'], + ['accept', '*/*'] +]) +``` +or +```js +{ + *[Symbol.iterator] () { + yield ['content-length', '123'] + yield ['content-type', 'text/plain'] + yield ['connection', 'keep-alive'] + yield ['host', 'mysite.com'] + yield ['accept', '*/*'] + } +} +``` diff --git a/test/types/dispatcher.test-d.ts b/test/types/dispatcher.test-d.ts index e40113bba5c..275d88c4af9 100644 --- a/test/types/dispatcher.test-d.ts +++ b/test/types/dispatcher.test-d.ts @@ -15,6 +15,14 @@ expectAssignable(new Dispatcher()) ['content-type']: 'application/json' } satisfies IncomingHttpHeaders; + const headerInstanceHeaders = new Headers({ hello: 'world' }) + const mapHeaders = new Map([['hello', 'world']]) + const iteratorHeaders = { + *[Symbol.iterator]() { + yield ['hello', 'world'] + } + } + // dispatch expectAssignable(dispatcher.dispatch({ path: '', method: 'GET' }, {})) expectAssignable(dispatcher.dispatch({ origin: '', path: '', method: 'GET' }, {})) @@ -23,6 +31,9 @@ expectAssignable(new Dispatcher()) expectAssignable(dispatcher.dispatch({ origin: '', path: '', method: 'GET', headers: {} }, {})) expectAssignable(dispatcher.dispatch({ origin: '', path: '', method: 'GET', headers: nodeCoreHeaders }, {})) expectAssignable(dispatcher.dispatch({ origin: '', path: '', method: 'GET', headers: null, reset: true }, {})) + expectAssignable(dispatcher.dispatch({ origin: '', path: '', method: 'GET', headers: headerInstanceHeaders, reset: true }, {})) + expectAssignable(dispatcher.dispatch({ origin: '', path: '', method: 'GET', headers: mapHeaders, reset: true }, {})) + expectAssignable(dispatcher.dispatch({ origin: '', path: '', method: 'GET', headers: iteratorHeaders, reset: true }, {})) expectAssignable(dispatcher.dispatch({ origin: new URL('http://localhost'), path: '', method: 'GET' }, {})) // connect diff --git a/types/dispatcher.d.ts b/types/dispatcher.d.ts index 0872df0fc0b..08c59ca0718 100644 --- a/types/dispatcher.d.ts +++ b/types/dispatcher.d.ts @@ -100,7 +100,7 @@ declare namespace Dispatcher { /** Default: `null` */ body?: string | Buffer | Uint8Array | Readable | null | FormData; /** Default: `null` */ - headers?: IncomingHttpHeaders | string[] | null; + headers?: IncomingHttpHeaders | string[] | Iterable<[string, string | string[] | undefined]> | null; /** Query string params to be embedded in the request URL. Default: `null` */ query?: Record; /** Whether the requests can be safely retried or not. If `false` the request won't be sent until all preceding requests in the pipeline have completed. Default: `true` if `method` is `HEAD` or `GET`. */