A router miss, a handler's miss, a method the route does not have, and a parser failure.
Comparable across every framework, on the status and on whether the answer carries a body at all. Not on the body's shape, which is the framework's own contract.
{draw.item} is a row of items.large, picked per request. A refusal's status is written 4XX. Frameworks refuse with different statuses, so each declares its own in its client-exception, and the test reads it from there.
| test | heft | request | base | what differs from the base |
|---|---|---|---|---|
| errors.malformed | 2 | POST /body/validate/small | body.rejected_all | a body that is not JSON at all |
| errors.not_found | 1 | GET /items/999999 | items.read | the request refused rather than served |
| errors.unmatched | 1 | GET /errors/unmatched | ||
| errors.wrong_method | 1 | POST /items/{draw.item} | errors.unmatched | a path the router knows, asked with a method it does not accept, instead of a path it does not know |
A body that is not JSON at all. Read against body.rejected_all, the difference is the parser failing rather than the validator refusing, which is often not even the same status inside one framework.
POST /body/validate/small
{"customerId": 1, "lines": [HTTP 4XX
The status the framework declares as malformed in its client-exception.
The framework's own error body, which is not checked.
import { performanceTest } from "#kit";
const path = "/body/validate/small";
/** Truncated mid-array, so the parser fails before any field is ever looked at. */
const MALFORMED = '{"customerId": 1, "lines": [';
export default performanceTest({
id: { family: "errors", name: "malformed" },
path,
base: "body.rejected_all",
varies: "parse_failure",
heft: 2,
about:
"A body that is not JSON at all. Read against body.rejected_all, the " +
"difference is the parser failing rather than the validator refusing, " +
"which is often not even the same status inside one framework.",
request: (c) => c.post(path).raw(MALFORMED).unparseable(),
});
A lookup the router matches and the handler refuses, because no row has that id. Read against items.read, the difference is the refusal in place of a row, and against errors.unmatched it is the handler deciding rather than the router missing.
GET /items/999999
No body.
HTTP 4XX
The status the framework declares as notFound in its client-exception.
The framework's own error body, which is not checked.
import { performanceTest } from "#kit";
const path = "/items/999999";
export default performanceTest({
id: { family: "errors", name: "not_found" },
path,
base: "items.read",
varies: "outcome",
heft: 1,
about:
"A lookup the router matches and the handler refuses, because no row has " +
"that id. Read against items.read, the difference is the refusal in place " +
"of a row, and against errors.unmatched it is the handler deciding rather " +
"than the router missing.",
request: (c) => c.get(path).notFound(),
});
A path no route matches, which is the router's own miss rather than a handler's decision. A framework that walks its whole route table before giving up pays for it here and nowhere else.
GET /errors/unmatched
No body.
HTTP 4XX
The status the framework declares as notFound in its client-exception.
The framework's own error body, which is not checked.
import { performanceTest } from "#kit";
const path = "/errors/unmatched";
export default performanceTest({
id: { family: "errors", name: "unmatched" },
path,
heft: 1,
about:
"A path no route matches, which is the router's own miss rather than a " +
"handler's decision. A framework that walks its whole route table before " +
"giving up pays for it here and nowhere else.",
request: (c) => c.get(path).notFound(),
});
A path with routes, asked with a method none of them has. A router that matches the path first answers 405, and one that matches the method and the path together answers 404, so the status is read from the framework's declaration. Read against errors.unmatched, the difference is how far the router got before it gave up.
POST /items/{draw.item}No body.
HTTP 4XX
The status the framework declares as wrongMethod in its client-exception.
The framework's own error body, which is not checked.
import { performanceTest } from "#kit";
const path = "/items/{draw.item}";
export default performanceTest({
id: { family: "errors", name: "wrong_method" },
path,
base: "errors.unmatched",
varies: "known_path",
heft: 1,
about:
"A path with routes, asked with a method none of them has. A router that " +
"matches the path first answers 405, and one that matches the method and " +
"the path together answers 404, so the status is read from the " +
"framework's declaration. Read against errors.unmatched, the difference " +
"is how far the router got before it gave up.",
request: (c) => c.post(`/items/${c.draw.item()}`).wrongMethod(),
});