Skip to content

Commit 1f4260d

Browse files
committed
feat(message): add withHeader function
1 parent f3c0ea2 commit 1f4260d

File tree

4 files changed

+164
-0
lines changed

4 files changed

+164
-0
lines changed

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,46 @@ assert(isRetrieveMethod("HEAD"));
550550
assert(!isRetrieveMethod("POST"));
551551
```
552552

553+
## withHeader
554+
555+
Return an instance with the provided value replacing the specified header. There
556+
are no side effects on the original target.
557+
558+
This was inspired by
559+
[PSR-7: HTTP message interfaces](https://www.php-fig.org/psr/psr-7/).
560+
561+
`Request`:
562+
563+
```ts
564+
import { withHeader } from "https://deno.land/x/http_utils@$VERSION/message.ts";
565+
import { assert } from "https://deno.land/std@$VERSION/testing/asserts.ts";
566+
567+
declare const init: Request;
568+
declare const header: string;
569+
declare const value: string;
570+
571+
const request = withHeader(init, header, value);
572+
573+
assert(request.headers.get(header), value);
574+
assert(init !== request);
575+
```
576+
577+
`Response`:
578+
579+
```ts
580+
import { withHeader } from "https://deno.land/x/http_utils@$VERSION/message.ts";
581+
import { assert } from "https://deno.land/std@$VERSION/testing/asserts.ts";
582+
583+
declare const init: Response;
584+
declare const header: string;
585+
declare const value: string;
586+
587+
const response = withHeader(init, header, value);
588+
589+
assert(response.headers.get(header), value);
590+
assert(init !== response);
591+
```
592+
553593
## License
554594

555595
Copyright © 2023-present [httpland](https://github.com/httpland).

message.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright 2023-latest the httpland authors. All rights reserved. MIT license.
2+
// This module is browser compatible.
3+
4+
/** Return an instance with the provided `Request` replacing the specified header.
5+
* There are no side effects on the original `Request`.
6+
*
7+
* @example
8+
* ```ts
9+
* import { withHeader } from "https://deno.land/x/http_utils@$VERSION/message.ts";
10+
* import { assert } from "https://deno.land/std@$VERSION/testing/asserts.ts";
11+
*
12+
* declare const init: Request;
13+
* declare const header: string;
14+
* declare const value: string;
15+
*
16+
* const request = withHeader(init, header, value);
17+
*
18+
* assert(request.headers.get(header), value);
19+
* assert(init !== request);
20+
* ```
21+
*/
22+
export function withHeader(
23+
request: Request,
24+
fieldName: string,
25+
fieldValue: string,
26+
): Request;
27+
/** Return an instance with the provided `Response` replacing the specified header.
28+
* There are no side effects on the original `Response`.
29+
*
30+
* @example
31+
* ```ts
32+
* import { withHeader } from "https://deno.land/x/http_utils@$VERSION/message.ts";
33+
* import { assert } from "https://deno.land/std@$VERSION/testing/asserts.ts";
34+
*
35+
* declare const init: Response;
36+
* declare const header: string;
37+
* declare const value: string;
38+
*
39+
* const response = withHeader(init, header, value);
40+
*
41+
* assert(response.headers.get(header), value);
42+
* assert(init !== response);
43+
* ```
44+
*/
45+
export function withHeader(
46+
response: Response,
47+
fieldName: string,
48+
fieldValue: string,
49+
): Response;
50+
export function withHeader(
51+
message: Request | Response,
52+
fieldName: string,
53+
fieldValue: string,
54+
): Request | Response {
55+
const headers = new Headers([...message.headers.entries(), [
56+
fieldName,
57+
fieldValue,
58+
]]);
59+
60+
if (message instanceof Request) return new Request(message, { headers });
61+
62+
const { status, statusText } = message;
63+
64+
return new Response(message.body, { headers, status, statusText });
65+
}

message_test.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { withHeader } from "./message.ts";
2+
import { assert, assertEquals, describe, it } from "./dev_deps.ts";
3+
4+
describe("withHeader", () => {
5+
const FIELD_NAME = "x-x";
6+
const FIELD_VALUE = "test";
7+
const BODY = "ok";
8+
const INIT_HEADER = "x-init";
9+
const INIT_HEADER_VALUE = "init";
10+
11+
it("should return new request instance with specified header", async () => {
12+
const METHOD = "POST";
13+
14+
const initRequest = new Request("test:", {
15+
method: METHOD,
16+
body: BODY,
17+
headers: {
18+
[INIT_HEADER]: INIT_HEADER_VALUE,
19+
},
20+
});
21+
22+
const request = withHeader(initRequest, FIELD_NAME, FIELD_VALUE);
23+
24+
assert(request !== initRequest);
25+
assertEquals(request.headers.get(FIELD_NAME), FIELD_VALUE);
26+
assertEquals(request.headers.get(INIT_HEADER), INIT_HEADER_VALUE);
27+
assertEquals(await request.text(), BODY);
28+
assertEquals(request.method, METHOD);
29+
30+
assert(!initRequest.headers.has(FIELD_NAME));
31+
assert(initRequest.headers.has(INIT_HEADER));
32+
});
33+
34+
it("should return new response instance with specified header", async () => {
35+
const STATUS = 201;
36+
const STATUS_TEXT = "status text";
37+
38+
const initResponse = new Response(BODY, {
39+
status: STATUS,
40+
statusText: STATUS_TEXT,
41+
headers: {
42+
[INIT_HEADER]: INIT_HEADER_VALUE,
43+
},
44+
});
45+
46+
const response = withHeader(initResponse, FIELD_NAME, FIELD_VALUE);
47+
48+
assert(response !== initResponse);
49+
assertEquals(response.headers.get(FIELD_NAME), FIELD_VALUE);
50+
assertEquals(response.headers.get(INIT_HEADER), INIT_HEADER_VALUE);
51+
assertEquals(response.status, STATUS);
52+
assertEquals(response.statusText, STATUS_TEXT);
53+
assertEquals(await response.text(), BODY);
54+
55+
assert(!initResponse.headers.has(FIELD_NAME));
56+
assert(initResponse.headers.has(INIT_HEADER));
57+
});
58+
});

mod.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,4 @@ export {
3838
type RetrieveMethod,
3939
type SafeMethod,
4040
} from "./method.ts";
41+
export { withHeader } from "./message.ts";

0 commit comments

Comments
 (0)