Add a Response constructor family (respond/ok/created/… + with-* helpers)#16
Conversation
There was a problem hiding this comment.
Build & Tests
Checked out claude/response-builders at b1c3393:
carp -x test/http.carp— 158 pass / 1 fail. The 1 failure is the pre-existingForm.parse ""empty-body bug (unrelated, untouched, masked on CI bycontinue-on-error). All 16 newResponsetests pass.angler,carp-fmt --check,gendocs— clean. Matches the green CI. (No CHANGELOG in this repo, so nothing to update.)
Findings
Went past the suite and serialized real responses to inspect the actual wire output:
ok/created/not-found/bad-request→HTTP/1.1 <code> <reason>with a singleContent-Lengthmatching the body's byte length;héllo→Content-Length: 6(bytes, not codepoints). ✓no-content→204 No Contentwith noContent-Lengthand an empty body (RFC 7230 §3.3.2). ✓redirect→Locationheader +Content-Length: 0. ✓with-headerappends and both values serialize under the same name. ✓- The
initarg order matches theResponsedeftype (code message version cookies headers body), andResponse.stremits only the map's headers — no auto Content-Length — sorespondinjecting it yields exactly one, no duplication. Thestr→parseround-trip test confirms the output re-parses.
One minor, non-blocking design note: with-content-type appends via with-header, so applying it twice would emit two Content-Type headers. Typical single use is correct; flagging only in case you'd prefer set-semantics for singleton headers.
Cleanly mirrors the existing Request constructor family, and the docstrings are concise.
Verdict: merge
Purely additive, correct on the wire, well-tested, all gates green.
|
needs a rebase. |
Mirror Request's builder family on Response: respond (HTTP/1.1, reason phrase from Status.reason, auto Content-Length) plus ok/created/no-content/not-found/ bad-request/redirect, and with-header/with-content-type/with-cookie. no-content omits Content-Length per RFC 7230. Complete the Status reason table and constants (202/206/303/307/308/406/415/504/505). 16 new tests; suite 158/1 (the 1 is the pre-existing Form.parse empty-body bug).
b1c3393 to
e60623c
Compare
|
Rebased onto |
There was a problem hiding this comment.
Build & Tests
Re-reviewed at e60623c — the rebased HEAD. My earlier review was at the pre-rebase b1c3393, now stale, so this is a fresh pass on the rebased branch. It sits cleanly on the current master (merge-base = origin/master HEAD 21751cc), so #17/#18 are underneath it, not duplicated.
carp -x test/http.carp— 169 pass / 0 fail. The pre-existingForm.parse ""failure I flagged last round is gone: #18 (Form empty-body) landed on master, so the suite is now fully green.carp-fmt --check,angler— clean. Matches the green CI on ubuntu + macos. (No CHANGELOG in this repo.)
Prior feedback
The only ask was hellerve's "needs a rebase." Done — and I verified the rebase itself, since the conflict was in the shared deftest tail:
- Resolved correctly: #17's
"chunk (single chunk) round-trips through dechunk"assert is retained, immediately followed by all 16 newResponseasserts, with thedeftest-closing paren relocated to the final assert. The 169/0 count (nothing skipped or miscounted) confirms the block is well-formed and every assert runs. - The
http.carppayload (Response constructor family + Status reason table) is byte-identical to what I reviewed atb1c3393— the rebase changed only the base and merged the two test tails.
Findings
Nothing new. My prior wire-level checks still hold (single correct byte-count Content-Length, héllo→6, 204 omits Content-Length, redirect sets Location, str→parse round-trips). One non-blocking note carries over: with-content-type appends via with-header, so applying it twice emits two Content-Type headers — fine for typical single use; flagging only in case you'd prefer set-semantics for singleton headers.
Verdict: merge
Clean rebase onto current master, conflict correctly resolved, additive Response surface verified correct, suite now fully green (169/0), all gates pass.
Requesthas a full constructor family (get/post/put/…) butResponsehad none — callers had to hand-assemble every response withResponse.init, andStatus.reason(the reason-phrase table) had no consumer at all. This adds the missing builder surface.Response constructors
respond code headers body— the base:HTTP/1.1, message filled fromStatus.reason code, and aContent-Lengthheader set to the body's byte length.ok/created/not-found/bad-request—[headers body]for the common codes.no-content—[headers], empty body. Per RFC 7230 §3.3.2 a 204 carries noContent-Length, so this one deliberately omits it (doesn't route throughrespond).redirect code location headers— sets aLocationheader, empty body.Builder helpers (return an updated
Response)with-header name value— appends a header value (keeps existing ones).with-content-type ct— sugar for aContent-Typeheader.with-cookie c— appends a cookie.Status
Completed the reason table + constants with the common missing codes:
202 206 303 307 308 406 415 504 505.Status.reasonis now live (consumed byrespond).Notes
Content-LengthusesString.length(byte count), so it's correct for multi-byte UTF-8 bodies (there's a test forhéllo→6).Response.str/parseare untouched.Verification
Form.parse ""empty-body bug (unrelated, untouched — masked on CI bycontinue-on-error).str→parseround-trip.carp-fmt -cclean,anglerclean,gendocsbuilds.