Skip to content

errs: conform HTTP responses to problem+json - #9

Open
Peyton-Spencer wants to merge 1 commit into
mainfrom
peyton/feat-errs-conform-problemjson-do9
Open

errs: conform HTTP responses to problem+json#9
Peyton-Spencer wants to merge 1 commit into
mainfrom
peyton/feat-errs-conform-problemjson-do9

Conversation

@Peyton-Spencer

@Peyton-Spencer Peyton-Spencer commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • switch errs responses to RFC 7807 problem details
  • set Content-Type: application/problem+json in Abort and map errors to type, title, status, and detail
  • add coverage for JSON marshaling, escaping, and HTTP abort behavior

Testing

  • go test ./errs/...

Closes #2

Summary by CodeRabbit

  • New Features
    • Error responses now use the RFC 7807 "application/problem+json" format with enhanced fields (type, title, status, detail) for improved error reporting and consistency.

@coderabbitai

coderabbitai Bot commented Apr 3, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The error handling is migrated from simple JSON responses to RFC 7807 "application/problem+json" format. Changes include a new Title() method on the *Error type, refactored Abort() to emit structured problem-details output, and restructured JSON marshaling to conform to the standard schema with type, title, status, and detail fields.

Changes

Cohort / File(s) Summary
Documentation
errs/README.md
Updated to document RFC 7807 problem-details responses, new Title() method, and revised response schema from {"message","status"} to {"type","title","status","detail"}.
Core Error Implementation
errs/errs.go, errs/json.go
Added Title() method deriving from HTTP status text; refactored Abort() to set Content-Type: application/problem+json and use new problemJSON serialization helper; replaced manual JSON buffer construction with typed struct-based marshaling.
Test Coverage
errs/json_test.go
Added three test cases: TestErrorMarshalJSON_ProblemJSON validates problem-details structure, TestErrorAbort_WritesProblemJSONResponse verifies HTTP response output, TestNilErrorAbort_DoesNothing ensures nil-safe behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Ah, the standards hop—RFC seven-oh-eight,
Where problems now detail their fate,
No more plain messages, but structured replies,
My errors now speak in problem-JSON guise! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and concisely summarizes the main change: conforming HTTP responses to the problem+json standard as required by the objectives.
Linked Issues check ✅ Passed All code changes align with issue #2 requirements: RFC 7807 problem-details format implemented with type/title/status/detail fields, Content-Type set to application/problem+json, and comprehensive test coverage added.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing RFC 7807 compliance for the errs package; no unrelated modifications are present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch peyton/feat-errs-conform-problemjson-do9

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
errs/json_test.go (1)

55-66: Consider closing response body for best practices consistency.

While httptest.ResponseRecorder doesn't leak resources if the body isn't closed, it's good practice to close response.Body to maintain consistency with real HTTP client usage patterns and prevent issues if tests are later refactored.

🧹 Optional: Add defer to close response body
 	response := recorder.Result()
+	defer response.Body.Close()
 	if response.StatusCode != http.StatusNotFound {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@errs/json_test.go` around lines 55 - 66, The test fetches the response via
recorder.Result() into the variable response but never closes response.Body;
after obtaining response (the result of recorder.Result()) add a defer
response.Body.Close() immediately before decoding to ensure the response body is
closed consistently (i.e., insert a defer response.Body.Close() right after
response := recorder.Result() and before
json.NewDecoder(response.Body).Decode(&body)).
errs/errs.go (1)

111-114: Consider logging marshal errors for observability.

While json.Marshal failing is extremely unlikely here (the struct contains only basic types from controlled sources), silently discarding the error could make debugging difficult if it ever does occur. The client would receive an empty body with the correct status code and headers.

🔧 Optional: Log marshal errors for debugging
 	data, err := json.Marshal(e)
-	if err == nil {
+	if err != nil {
+		// Log unexpected marshal failure; body will be empty but headers/status are already sent
+		zerolog.Ctx(e.ctx).Error().Err(err).Msg("failed to marshal problem+json response")
+	} else {
 		_, _ = w.Write(data)
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@errs/errs.go` around lines 111 - 114, The json.Marshal call that serializes
variable e into data ignores marshal errors (data, err := json.Marshal(e)) and
silently skips writing a response body; update the error handling to log the
marshal error and write a safe fallback response body so the client still gets
useful content. Specifically, in the function that writes the error response
(the block using variables data, err and writer w), if json.Marshal returns a
non-nil err, call the appropriate logger (or fmt.Fprintf to w as fallback) to
record the marshal error and then write a simple JSON or plain-text fallback
message to w before returning.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@errs/errs.go`:
- Line 4: Remove the unused bytes package import and the unused struct field:
delete the "bytes" import entry and remove the `b bytes.Buffer` field
declaration (the `b` field) from the relevant error response struct so the code
no longer references an unused Buffer after `Abort()` was changed to use
`json.Marshal()` directly; search for the struct that defines `b bytes.Buffer`
and remove that field and the import.

---

Nitpick comments:
In `@errs/errs.go`:
- Around line 111-114: The json.Marshal call that serializes variable e into
data ignores marshal errors (data, err := json.Marshal(e)) and silently skips
writing a response body; update the error handling to log the marshal error and
write a safe fallback response body so the client still gets useful content.
Specifically, in the function that writes the error response (the block using
variables data, err and writer w), if json.Marshal returns a non-nil err, call
the appropriate logger (or fmt.Fprintf to w as fallback) to record the marshal
error and then write a simple JSON or plain-text fallback message to w before
returning.

In `@errs/json_test.go`:
- Around line 55-66: The test fetches the response via recorder.Result() into
the variable response but never closes response.Body; after obtaining response
(the result of recorder.Result()) add a defer response.Body.Close() immediately
before decoding to ensure the response body is closed consistently (i.e., insert
a defer response.Body.Close() right after response := recorder.Result() and
before json.NewDecoder(response.Body).Decode(&body)).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c4c8c804-7226-48f6-aeb4-867c2d193c46

📥 Commits

Reviewing files that changed from the base of the PR and between 8703d17 and 7b7164d.

📒 Files selected for processing (4)
  • errs/README.md
  • errs/errs.go
  • errs/json.go
  • errs/json_test.go

Comment thread errs/errs.go
@@ -3,6 +3,7 @@ package errs
import (
"bytes"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if bytes.Buffer field 'b' or bytes package is used anywhere in errs package
echo "=== Checking usage of bytes.Buffer field 'b' ==="
rg -n '\.b\.' --type=go errs/

echo "=== Checking usage of bytes package functions ==="
rg -n 'bytes\.' --type=go errs/

echo "=== Checking if 'b' field is accessed ==="
ast-grep --pattern 'e.b.$_($$$)'

Repository: omniaura/go-kit

Length of output: 244


Remove unused bytes import and b bytes.Buffer field.

The bytes package (line 4) and b bytes.Buffer field (line 26) are no longer used after Abort() was updated to use json.Marshal() directly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@errs/errs.go` at line 4, Remove the unused bytes package import and the
unused struct field: delete the "bytes" import entry and remove the `b
bytes.Buffer` field declaration (the `b` field) from the relevant error response
struct so the code no longer references an unused Buffer after `Abort()` was
changed to use `json.Marshal()` directly; search for the struct that defines `b
bytes.Buffer` and remove that field and the import.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

errs: conform to problem+json standard

1 participant