Phase 03 Plan 02: Server Content-Type Response Headers Summary
Server correctness fix: Content-Type headers on all HTTP responses and consistent JSON default for unknown content types.
What Was Done#
Task 1: Fix Content-Type response header and marshalResponse default behavior#
Fixed three categories of issues in the generated HTTP server code:
Content-Type Response Headers (3 functions):
-
writeProtoMessageResponse-- AddedrespContentTypevariable set per-case in the content-type switch, thenw.Header().Set("Content-Type", respContentType)beforew.WriteHeader(). This function is the main response writer used by all error response paths. -
genericHandlersuccess path -- Added Content-Type determination based on request Content-Type (JSON for default/JSON, protobuf for binary/proto), set beforew.Write(responseBytes). -
writeResponseBody-- Same pattern aswriteProtoMessageResponse:respContentTypevariable per-case, thenw.Header().Setbeforew.Write.
marshalResponse default to JSON:
Changed the default case from returning fmt.Errorf("unsupported content type: %s", contentType) to defaulting to JSON serialization (checking for json.Marshaler first for unwrap support, then protojson.Marshal).
bindDataBasedOnContentType default to JSON:
Changed the default case from bindDataFromBinaryRequest to bindDataFromJSONRequest for consistency. Request parsing and response serialization now both default to JSON for unknown/missing content types.
Task 2: Verify error response functions also set Content-Type headers#
Audited all response-writing paths in the generated server code:
| Function | Content-Type Mechanism | Coverage |
|---|---|---|
writeProtoMessageResponse |
Sets directly (Task 1) | All error responses |
writeValidationErrorResponse |
Delegates to writeProtoMessageResponse | Validation errors |
writeValidationError |
Delegates via writeValidationErrorResponse | Protovalidate errors |
writeErrorResponse |
Delegates to writeProtoMessageResponse | Handler errors |
writeErrorWithHandler |
Delegates to writeProtoMessageResponse or writeResponseBody | Custom error handlers |
writeResponseBody |
Sets directly (Task 1) | Custom handler with pre-set status |
genericHandler success |
Sets directly (Task 1) | Successful responses |
http.Error() fallback |
Go stdlib sets text/plain | Marshal failure fallback |
Result: No additional changes needed. All paths covered by Task 1's three-function fix.
Deviations from Plan#
Auto-fixed Issues#
1. [Rule 2 - Missing Critical] bindDataBasedOnContentType default changed from binary to JSON
- Found during: Task 1
- Issue: Request parsing defaulted to binary for unknown content types while response serialization was being changed to default to JSON. This created an asymmetry.
- Fix: Changed
bindDataBasedOnContentTypedefault case frombindDataFromBinaryRequesttobindDataFromJSONRequest - Files modified:
internal/httpgen/generator.go - Commit: 1cd141a
2. [Rule 3 - Blocking] Pre-existing proto test file changes included
- Found during: Task 1 golden file update
- Issue: The
http_verbs_comprehensive.prototest file had been enhanced with additional test coverage (SearchResources method, enum query params) in a prior session. Running the golden file update regenerated ALL golden files from this modified proto, requiring inclusion of both the proto change and the_http.pb.gogolden file. - Fix: Included the proto and non-binding golden file in the commit to maintain test consistency
- Files modified:
internal/httpgen/testdata/proto/http_verbs_comprehensive.proto,internal/httpgen/testdata/golden/http_verbs_comprehensive_http.pb.go - Commit: 1cd141a
Decisions Made#
| ID | Decision | Rationale |
|---|---|---|
| D-03-02-01 | JSON default everywhere | Consistency: all 4 content-type switch statements (bindData, marshalResponse, writeProtoMessage, writeResponseBody) use JSON as default. Clients can reliably expect JSON when Content-Type is unknown/missing. |
| D-03-02-02 | Three-function Content-Type coverage | writeProtoMessageResponse covers all error paths (validation, handler, header validation). genericHandler covers success path. writeResponseBody covers custom-handler-with-status path. No redundant settings. |
Verification Results#
go test ./internal/httpgen/ -count=1-- PASS (29/29 tests)make build-- PASSmake lint-fix-- 0 issues- Content-Type
w.Header().Setappears in all 4 binding golden files, 3 times each "unsupported content type"error removed from all golden files"Default to JSON for unrecognized content types"comment present in all default cases
Next Phase Readiness#
No blockers for subsequent plans. The server now establishes a correct baseline:
- Clients can detect response format from Content-Type header
- Unknown content types default to JSON consistently
- Plan 03 (Go client) and Plan 04 (TS client) can rely on Content-Type being set
