Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## Unreleased

- `createHealthHandler()` includes `cache-control: no-store` and JSON
content-type headers on `404` and `405` responses.

## 0.1.2

- Every hosting package (`fly`, `koyeb`, `railway`, `vercel`, `cloudflare`)
Expand Down
34 changes: 27 additions & 7 deletions packages/health/src/handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,33 @@ test("createHealthHandler() answers HEAD without a body", async () => {
assert.equal(await res.text(), "");
});

test("createHealthHandler() rejects other methods with 405", async () => {
const handler = createHealthHandler({ probes: [ok] });
const res = await handler(
new Request("http://localhost/health", { method: "POST" }),
);
assert.equal(res.status, 405);
assert.equal(res.headers.get("allow"), "GET, HEAD");
test("createHealthHandler() rejects requests without caching or running probes", async () => {
let runs = 0;
const handler = createHealthHandler({
path: "/health",
probes: [{ name: "a", run: () => runs++ }],
});
for (
const { path, method, status, allow } of [
{ path: "/other", method: "GET", status: 404, allow: null },
{ path: "/other", method: "HEAD", status: 404, allow: null },
{ path: "/other", method: "POST", status: 404, allow: null },
{ path: "/health", method: "POST", status: 405, allow: "GET, HEAD" },
]
) {
const res = await handler(
new Request(`http://localhost${path}`, { method }),
);
assert.equal(res.status, status);
assert.equal(res.headers.get("allow"), allow);
assert.equal(res.headers.get("cache-control"), "no-store");
assert.equal(
res.headers.get("content-type"),
"application/json; charset=utf-8",
);
assert.equal(await res.text(), "");
assert.equal(runs, 0);
}
});

test("createHealthHandler() passes the request to extend", async () => {
Expand Down
10 changes: 8 additions & 2 deletions packages/health/src/handler.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createHealthResponder } from "./responder.ts";
import { healthHeaders } from "./response.ts";
import type { HealthRouteOptions } from "./types.ts";

export type HealthHandler<Req extends Request = Request> = (
Expand All @@ -17,11 +18,16 @@ export function createHealthHandler<Req extends Request = Request>(
const path = options.path;
return (request: Req): Promise<Response> => {
if (path != null && !matchesPath(request.url, path)) {
return Promise.resolve(new Response(null, { status: 404 }));
return Promise.resolve(
new Response(null, { status: 404, headers: healthHeaders }),
);
}
if (request.method !== "GET" && request.method !== "HEAD") {
return Promise.resolve(
new Response(null, { status: 405, headers: { allow: "GET, HEAD" } }),
new Response(null, {
status: 405,
headers: { ...healthHeaders, allow: "GET, HEAD" },
}),
);
}
return responder.toResponse(request, request.method);
Expand Down
Loading