Skip to content

Commit dba43a8

Browse files
committed
docs: add description of precondition
1 parent fa5105c commit dba43a8

File tree

1 file changed

+224
-26
lines changed

1 file changed

+224
-26
lines changed

README.md

Lines changed: 224 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,69 +22,267 @@ For a definition of Universal HTTP middleware, see the
2222
## Usage
2323

2424
To evaluate precondition, you need to provide a function to retrieve the
25-
selected representation.
25+
[selected representation](https://www.rfc-editor.org/rfc/rfc9110#selected.representation).
2626

27-
The following example evaluates the `If-None-Match` precondition and controls
28-
the handler.
27+
The following example evaluates the `If-None-Match` precondition and handle
28+
response.
2929

3030
```ts
31-
import { conditionalRequest } from "https://deno.land/x/conditional_request_middleware@$VERSION/mod.ts";
32-
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
31+
import {
32+
conditionalRequest,
33+
type Handler,
34+
} from "https://deno.land/x/conditional_request_middleware@$VERSION/mod.ts";
35+
import {
36+
assertEquals,
37+
assertFalse,
38+
} from "https://deno.land/std/testing/asserts.ts";
3339
import { assertSpyCalls, spy } from "https://deno.land/std/testing/mock.ts";
3440

35-
const selectedRepresentation = new Response("<body>", {
36-
headers: { etag: "<etag>" },
41+
const selectRepresentation = spy((request: Request) => {
42+
return new Response("<body>", { headers: { etag: "<etag>" } });
3743
});
38-
const selectRepresentation = spy(() => selectedRepresentation);
3944
const middleware = conditionalRequest(selectRepresentation);
4045
const request = new Request("<uri>", {
4146
headers: { "if-none-match": "<etag>" },
4247
});
43-
const handler = spy(() => selectedRepresentation);
48+
declare const _handler: Handler;
49+
const handler = spy(_handler);
4450

4551
const response = await middleware(request, handler);
4652

4753
assertSpyCalls(handler, 0);
4854
assertSpyCalls(selectRepresentation, 1);
4955
assertEquals(response.status, 304);
56+
assertFalse(response.body);
5057
```
5158

52-
## Preconditions
59+
## Precondition
5360

5461
[RFC 9110, 13.1. Preconditions](https://www.rfc-editor.org/rfc/rfc9110#section-13.1)
5562
compliant and supports the following precondition:
5663

57-
- If-Match
58-
- If-None-Match
59-
- If-Modified-Since
60-
- If-Unmodified-Since
61-
- If-Range
64+
- [If-Match](#ifmatch)
65+
- [If-None-Match](#ifnonematch)
66+
- [If-Modified-Since](#ifmodifiedsince)
67+
- [If-Unmodified-Since](#ifunmodifiedsince)
68+
- [If-Range](#ifrange)
6269

6370
If multiple precondition headers are present, precondition is processed
6471
according to
6572
[precedence](https://www.rfc-editor.org/rfc/rfc9110.html#section-13.2.2).
6673

67-
## Effects
74+
### IfMatch
75+
76+
`If-Match` header field precondition.
77+
78+
```ts
79+
import { IfMatch } from "https://deno.land/x/conditional_request_middleware@$VERSION/mod.ts";
80+
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
81+
82+
const precondition = new IfMatch();
83+
const request = new Request("<uri>", {
84+
headers: { "if-match": "<strong:etag>" },
85+
});
86+
const selectedRepresentation = new Response("<content>", {
87+
headers: { etag: "<weak:etag>" },
88+
});
89+
declare const evalResult: false;
90+
91+
assertEquals(precondition.field, "if-match");
92+
assertEquals(
93+
precondition.evaluate(request, selectedRepresentation),
94+
evalResult,
95+
);
96+
assertEquals(
97+
precondition.respond(request, selectedRepresentation, evalResult)?.status,
98+
412,
99+
);
100+
```
101+
102+
#### Effects
103+
104+
Precondition will effect following:
105+
106+
If evaluation is `false`:
107+
108+
- HTTP content
109+
- HTTP response status
110+
- [412 (Precondition Failed)](https://www.rfc-editor.org/rfc/rfc9110#section-15.5.13)
111+
- HTTP headers
112+
- [Representation headers](https://www.rfc-editor.org/rfc/rfc9110.html#section-8)
113+
114+
### IfNoneMatch
115+
116+
`If-None-Match` header field precondition.
117+
118+
```ts
119+
import { IfNoneMatch } from "https://deno.land/x/conditional_request_middleware@$VERSION/mod.ts";
120+
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
121+
122+
const precondition = new IfNoneMatch();
123+
const request = new Request("<uri>", {
124+
headers: { "if-none-match": "<weak:etag>" },
125+
});
126+
const selectedRepresentation = new Response("<content>", {
127+
headers: { etag: "<weak:etag>" },
128+
});
129+
declare const evalResult: false;
130+
131+
assertEquals(precondition.field, "if-none-match");
132+
assertEquals(
133+
precondition.evaluate(request, selectedRepresentation),
134+
evalResult,
135+
);
136+
assertEquals(
137+
precondition.respond(request, selectedRepresentation, evalResult)?.status,
138+
304,
139+
);
140+
```
141+
142+
#### Effects
143+
144+
Precondition will effect following:
145+
146+
If evaluation is `false`:
147+
148+
- HTTP content
149+
- HTTP response status
150+
- [304 (Not Modified)](https://www.rfc-editor.org/rfc/rfc9110#section-15.4.5)
151+
- [412 (Precondition Failed)](https://www.rfc-editor.org/rfc/rfc9110#section-15.5.13)
152+
- HTTP headers
153+
- [Representation headers](https://www.rfc-editor.org/rfc/rfc9110.html#section-8)
154+
155+
### IfModifiedSince
156+
157+
`If-Modified-Since` header field precondition.
158+
159+
```ts
160+
import { IfModifiedSince } from "https://deno.land/x/conditional_request_middleware@$VERSION/mod.ts";
161+
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
162+
163+
const precondition = new IfModifiedSince();
164+
const request = new Request("<uri>", {
165+
headers: { "if-modified-since": "<after:HTTP-date>" },
166+
});
167+
const selectedRepresentation = new Response("<content>", {
168+
headers: { "last-modified": "<before:HTTP-date>" },
169+
});
170+
declare const evalResult: false;
171+
172+
assertEquals(precondition.field, "if-modified-since");
173+
assertEquals(
174+
precondition.evaluate(request, selectedRepresentation),
175+
evalResult,
176+
);
177+
assertEquals(
178+
precondition.respond(request, selectedRepresentation, evalResult)?.status,
179+
304,
180+
);
181+
```
182+
183+
#### Effects
184+
185+
Precondition will effect following:
68186

69-
Middleware will effect following:
187+
If evaluation is `false`:
70188

189+
- HTTP content
71190
- HTTP response status
72191
- [304 (Not Modified)](https://www.rfc-editor.org/rfc/rfc9110#section-15.4.5)
192+
- HTTP headers
193+
- Content-Type
194+
- Content-Encoding
195+
- Content-Length
196+
- Content-Language
197+
198+
### IfUnmodifiedSince
199+
200+
`If-Unmodified-Since` header field precondition.
201+
202+
```ts
203+
import { IfUnmodifiedSince } from "https://deno.land/x/conditional_request_middleware@$VERSION/mod.ts";
204+
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
205+
206+
const precondition = new IfUnmodifiedSince();
207+
const request = new Request("<uri>", {
208+
headers: { "if-unmodified-since": "<before:HTTP-date>" },
209+
});
210+
const selectedRepresentation = new Response("<content>", {
211+
headers: { "last-modified": "<after:HTTP-date>" },
212+
});
213+
declare const evalResult: false;
214+
215+
assertEquals(precondition.field, "if-unmodified-since");
216+
assertEquals(
217+
precondition.evaluate(request, selectedRepresentation),
218+
evalResult,
219+
);
220+
assertEquals(
221+
precondition.respond(request, selectedRepresentation, evalResult)?.status,
222+
412,
223+
);
224+
```
225+
226+
#### Effects
227+
228+
Precondition will effect following:
229+
230+
If evaluation is `false`:
231+
232+
- HTTP content
233+
- HTTP response status
73234
- [412 (Precondition Failed)](https://www.rfc-editor.org/rfc/rfc9110#section-15.5.13)
235+
- HTTP headers
236+
- [Representation headers](https://www.rfc-editor.org/rfc/rfc9110.html#section-8)
237+
238+
### IfRange
239+
240+
`If-Range` header field precondition.
241+
242+
```ts
243+
import { IfRange } from "https://deno.land/x/conditional_request_middleware@$VERSION/mod.ts";
244+
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
245+
246+
const precondition = new IfRange();
247+
const request = new Request("<uri>", {
248+
headers: { "if-range": "<strong:etag>", range: "<range-unit>=<range-set>" },
249+
});
250+
const selectedRepresentation = new Response("<content>", {
251+
headers: { etag: "<strong:etag>" },
252+
});
253+
declare const evalResult: false;
254+
255+
assertEquals(precondition.field, "if-range");
256+
assertEquals(
257+
precondition.evaluate(request, selectedRepresentation),
258+
evalResult,
259+
);
260+
assertEquals(
261+
(await precondition.respond(request, selectedRepresentation, evalResult))
262+
?.status,
263+
206,
264+
);
265+
```
266+
267+
#### Effects
268+
269+
Precondition will effect following:
270+
271+
If evaluation is `true`:
272+
273+
- HTTP content
274+
- HTTP response status
275+
- [206 (Precondition Failed)](https://www.rfc-editor.org/rfc/rfc9110#section-15.3.7)
276+
- HTTP headers
277+
- Content-Range
74278

75279
## Conditions
76280

77281
Middleware will execute only if the following conditions are met:
78282

79-
- The precondition header exists
80-
- `If-Match`
81-
- The `ETag` header exist
82-
- `If-None-Match`
83-
- The `ETag` header exist
84-
- `If-Modified-Since`
85-
- The `Last-Modified` header exist
86-
- `If-Unmodified-Since`
87-
- The `Last-Modified` header exist
283+
- Request is conditional request
284+
- Request method is not `CONNECT`, `OPTIONS` or `TRACE`
285+
- Select representation status is `2xx` or `412`
88286

89287
## License
90288

0 commit comments

Comments
 (0)