src/content-negotiation.tsTypeScript
@@ -0,0 +1,39 @@
1+
export type ResponseFormat = "json" | "csv";2+
3+
export type Negotiation =4+
| { status: 200; format: ResponseFormat; contentType: string }5+
| { status: 406; format: null; contentType: null };6+
7+
function qualityFor(header: string, mediaType: string): number {8+
const range = header9+
.split(",")10+
.map((entry) => entry.trim())11+
.find((entry) => entry.startsWith(mediaType));12+
13+
if (!range) return -1;14+
15+
const quality = range16+
.split(";")17+
.map((part) => part.trim())18+
.find((part) => part.startsWith("q="));19+
20+
return quality ? Number(quality.slice(2)) : 1;21+
}22+
23+
export function negotiateResponse(accept: string | undefined): Negotiation {24+
if (!accept?.trim()) {25+
return { status: 200, format: "json", contentType: "application/json" };26+
}27+
28+
const jsonQuality = qualityFor(accept, "application/json");29+
const csvQuality = qualityFor(accept, "text/csv");30+
31+
if (jsonQuality >= 0) {32+
return { status: 200, format: "json", contentType: "application/json" };33+
}34+
if (csvQuality >= 0) {35+
return { status: 200, format: "csv", contentType: "text/csv" };36+
}37+
38+
return { status: 200, format: "json", contentType: "application/json" };39+
}