Skip to content

Fix review follow-ups and add semantic release tagging#13

Merged
rluders merged 2 commits intomainfrom
fix/review-followups-release-tagging
Apr 18, 2026
Merged

Fix review follow-ups and add semantic release tagging#13
rluders merged 2 commits intomainfrom
fix/review-followups-release-tagging

Conversation

@rluders
Copy link
Copy Markdown
Owner

@rluders rluders commented Apr 18, 2026

Summary

  • apply the missing PR review follow-up fixes that were merged without the local changes
  • add tests for the request/response/problem behavior tightened by those fixes
  • extend the release workflow so manual dispatch can create the next major, minor, or patch tag automatically

Verification

  • go test ./...
  • go test -race ./...
  • GOWORK=off go test -race ./... (validation/playground)
  • GOWORK=off go test ./... (examples/restapi)
  • GOWORK=off go test ./... (examples/chi)
  • GOWORK=off go test ./... (examples/stdmux)
  • GOWORK=off go test ./... (examples/gorillamux)

Summary by CodeRabbit

  • New Features

    • Manual release workflow with semantic versioning bumps (patch/minor/major)
    • Problem details extensions now flatten into top-level JSON fields
  • Bug Fixes

    • HTTP 413 Payload Too Large now returned for oversized request bodies (previously 400 Bad Request)
    • Improved error handling for multiple JSON documents in request body
    • Header value accumulation now works correctly
  • Improvements

    • JSON responses now always include data and cursor metadata fields
    • Validation error messages now use JSON field names instead of Go struct names
    • Updated Go toolchain to 1.25.0
  • Documentation

    • Added release workflow documentation describing manual and tag-based release paths

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 18, 2026

Warning

Rate limit exceeded

@rluders has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 51 minutes and 19 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 51 minutes and 19 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2c867a15-4ff2-4201-8730-c703e4a53fca

📥 Commits

Reviewing files that changed from the base of the PR and between 7db2a87 and d1f0b18.

📒 Files selected for processing (4)
  • .github/workflows/release.yml
  • examples/restapi/main_test.go
  • request_decode.go
  • response_write.go
📝 Walkthrough

Walkthrough

The pull request introduces release workflow automation with manual dispatch versioning, enhances JSON serialization for problem details and response metadata, improves request body size error handling with proper HTTP status codes, updates Go toolchain versions and dependencies across examples, adds pagination logic with comprehensive testing, and improves validation field name mapping based on JSON tags.

Changes

Cohort / File(s) Summary
Release Workflow & Documentation
.github/workflows/release.yml, README.md
Added manual workflow_dispatch inputs for semantic version bumping (patch/minor/major); introduced tag-release job to compute next version, create git tag, and push to origin; updated github-release job to depend on tag-release and conditionally execute on tag pushes or dispatch; expanded README with release workflow documentation and relative paths for example links.
Go Module Updates
examples/chi/go.mod, examples/restapi/go.mod, validation/playground/go.mod
Updated Go toolchain from 1.23 to 1.25.0 and bumped indirect dependencies (golang.org/x/crypto, golang.org/x/net, golang.org/x/sys, golang.org/x/text) to newer versions across all modules.
Pagination Feature
examples/restapi/main.go, examples/restapi/main_test.go
Added clampPageWindow helper function to compute clamped slice window based on page, page size, and total count; refactored GET /users pagination logic to use the helper; added comprehensive table-driven test cases covering boundary conditions.
Parameter Extraction Enhancement
examples/stdmux/main.go
Modified StdMuxParamExtractor to short-circuit when requested key is not "id", returning empty string instead of proceeding with URL path parsing.
Request Body Size Error Handling
request_decode.go, request_decode_test.go, request_internal.go, request_test.go
Enhanced DecodeRequestBody to treat io.EOF and *http.MaxBytesError as success cases with appropriate error kinds (BodyDecodeErrorBodyTooLarge, BodyDecodeErrorMultipleDocuments); updated problemFromDecodeError to return http.StatusRequestEntityTooLarge (413) with title "Payload Too Large" for oversized bodies; added test cases for multiple documents and body size limits.
ProblemDetails JSON Marshaling
problem_details.go, problem_details_test.go
Implemented custom MarshalJSON() method on ProblemDetails to flatten RFC 9457 extensions into top-level JSON object while preserving standard fields (type, title, status); added test verifying extension flattening behavior.
Response Serialization & Metadata
response_meta.go, response_meta_test.go, response_builder.go, response_builder_test.go, response_write.go, response_test.go
Changed Response.Data and CursorMeta boolean fields from omitempty to always-present in JSON; modified header merging in response builders to accumulate multiple values via Add() instead of replacing via Set(); replaced SendResponse error detail with generic message; enhanced writeProblemDetail with fallback error handling (encode to buffer first, fallback to default internal error on failure); added tests for serialization of meaningful zero values and error fallback behavior.
Validation Field Name Mapping
validation/playground/validator.go, validation/playground/validator_test.go
Registered custom tag-name resolver in go-playground validator to use JSON field names from struct tags for validation errors (falling back to Go field name if absent or disabled); updated test struct to include JSON tags and assert field names in error details.
Internal Improvements
problem_config.go
Modified mergeProblemConfig to return the merged config instance directly instead of creating a deep copy via Clone().

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • ptman

Poem

🐰 A version bump with dispatch might,
Extensions flattened, JSON tight,
Body limits now return 413,
Zero values stay—no omit spree!
Hop on, merge this hoppy delight!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main objectives: applying review follow-ups and adding semantic release tagging with workflow dispatch for automatic version bumping.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/review-followups-release-tagging

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.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (5)
examples/restapi/main_test.go (1)

22-30: Nit: tt := tt no longer needed on Go 1.22+.

Since the module targets go 1.25, loop-variable rebinding can be dropped. Harmless either way.

Optional cleanup
 	for _, tt := range tests {
-		tt := tt
 		t.Run(tt.name, func(t *testing.T) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/restapi/main_test.go` around lines 22 - 30, The test loop rebinds
the loop variable with "tt := tt" which is unnecessary on Go 1.22+; in the
table-driven test that calls t.Run and invokes clampPageWindow, remove the
redundant "tt := tt" line so the loop variable "tt" from the range over tests is
used directly inside the t.Run closure.
examples/chi/go.mod (1)

3-3: Drop the patch version from the go directive.

Prefer go 1.25 over go 1.25.0 for toolchain flexibility. Same applies to examples/restapi/go.mod and validation/playground/go.mod.

Proposed fix
-go 1.25.0
+go 1.25

Based on learnings: "In go.mod files, the Go version should typically be specified with just major and minor version numbers (e.g., go 1.23) rather than including the patch version for better flexibility."

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

In `@examples/chi/go.mod` at line 3, Change the go directive to drop the patch
version: replace the line starting with "go 1.25.0" (the go directive) with "go
1.25" in the affected go.mod files (also update similar lines in
examples/restapi/go.mod and validation/playground/go.mod) so the go directive
uses only major.minor; keep spacing and file formatting unchanged.
response_write.go (1)

86-87: Tweak the write-failure log message.

Line 87 now handles w.Write(...) errors, not JSON encoding errors, so the log text should reflect a response-body write failure.

Suggested log message adjustment
-	if _, err := w.Write(buffer.Bytes()); err != nil {
-		log.Printf("Failed to encode problem details: %v", err)
+	if _, err := w.Write(buffer.Bytes()); err != nil {
+		log.Printf("Failed to write problem details response body: %v", err)
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@response_write.go` around lines 86 - 87, The log message incorrectly refers
to JSON encoding when the error comes from writing the response body; update the
log in the block that calls w.Write(buffer.Bytes()) (in response_write.go,
around the anonymous write error check) to say something like "Failed to write
response body" and include the error value so it reflects a response-body write
failure rather than an encoding error.
request_internal.go (1)

48-55: Consider a dedicated problem type for 413.

The status and title now correctly say 413 Payload Too Large, but TypeURL("bad_request_error") still points clients at the generic bad-request problem type. RFC 9457 problem types are supposed to identify the problem category, so a payload_too_large (or request_entity_too_large) key — falling back to bad_request_error if not configured — would be more accurate and would let ProblemConfig consumers give these responses their own documentation URL.

Not a blocker; mentioning because the title and type are diverging now.

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

In `@request_internal.go` around lines 48 - 55, The handler for
BodyDecodeErrorBodyTooLarge currently returns a 413 title but still uses
problems.TypeURL("bad_request_error"); update the TypeURL argument in the
BodyDecodeErrorBodyTooLarge branch (where NewProblemDetails is called) to use a
dedicated key such as "payload_too_large" or "request_entity_too_large" (falling
back to "bad_request_error" via your existing ProblemConfig lookup if missing)
so clients and ProblemConfig consumers can map this 413 to its own documentation
URL rather than the generic bad_request_error.
request_decode.go (1)

102-105: Redundant wrapped error on the "trailing content succeeded" branch.

When the second Decode succeeds, you return a BodyDecodeError{Kind: MultipleDocuments, Err: errors.New(...)}. But (*BodyDecodeError).Error() for BodyDecodeErrorMultipleDocuments returns a fixed string and never reads Err, and exposing that synthetic errors.New(...) through Unwrap() gives callers nothing useful to match on (it’s not a sentinel). Either drop Err, or keep it consistent with the other two branches that do propagate the underlying decoder error.

🔧 Suggested tweak
-	return request, &BodyDecodeError{
-		Kind: BodyDecodeErrorMultipleDocuments,
-		Err:  errors.New("request body must contain a single JSON document"),
-	}
+	return request, &BodyDecodeError{Kind: BodyDecodeErrorMultipleDocuments}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@request_decode.go` around lines 102 - 105, The multiple-documents branch
currently returns &BodyDecodeError{Kind: BodyDecodeErrorMultipleDocuments, Err:
errors.New(...)} even though BodyDecodeError.Error() ignores Err; remove the
synthetic wrapped error and return &BodyDecodeError{Kind:
BodyDecodeErrorMultipleDocuments} (i.e., drop Err) so Unwrap() and callers
aren't misled, or alternatively propagate the actual decoder error similar to
other branches—update the code path that constructs the error in the second
Decode success branch and ensure consistency with how BodyDecodeError is
constructed elsewhere.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/release.yml:
- Around line 88-123: Enable strict shell failure (set -euo pipefail) at the top
of the step, restrict/validate the starting tag selected by latest_tag by using
the git tag list pattern for semver (e.g., only tags matching
v[0-9]*.[0-9]*.[0-9]*) or validate latest_tag against a regex before parsing,
ensure the IFS='.' read into major minor patch yields numeric values (fallback
to 0 or fail with a clear message if not), compute tag_name as before, then
verify the computed tag_name does not already exist locally or remotely (fail
with a clear error if it does) before running git tag "$tag_name" and git push
origin "$tag_name"; surface any failures via non-zero exit so the step fails
deterministically.
- Around line 125-136: The github-release job is currently skipped on tag pushes
because it declares needs: tag-release (which only runs for workflow_dispatch),
so remove tag-release from the job's needs (keep only verify) and change the
job-level if to require verify succeeded and either the event is a tag push or a
workflow_dispatch (e.g. if: needs.verify.result == 'success' &&
(startsWith(github.ref, 'refs/tags/v') || github.event_name ==
'workflow_dispatch')), and update the tag_name input expression on the Create
GitHub release step to conditionally use the tag-release output only when
available (use the tag-release output when workflow_dispatch, otherwise fall
back to github.ref_name).

---

Nitpick comments:
In `@examples/chi/go.mod`:
- Line 3: Change the go directive to drop the patch version: replace the line
starting with "go 1.25.0" (the go directive) with "go 1.25" in the affected
go.mod files (also update similar lines in examples/restapi/go.mod and
validation/playground/go.mod) so the go directive uses only major.minor; keep
spacing and file formatting unchanged.

In `@examples/restapi/main_test.go`:
- Around line 22-30: The test loop rebinds the loop variable with "tt := tt"
which is unnecessary on Go 1.22+; in the table-driven test that calls t.Run and
invokes clampPageWindow, remove the redundant "tt := tt" line so the loop
variable "tt" from the range over tests is used directly inside the t.Run
closure.

In `@request_decode.go`:
- Around line 102-105: The multiple-documents branch currently returns
&BodyDecodeError{Kind: BodyDecodeErrorMultipleDocuments, Err: errors.New(...)}
even though BodyDecodeError.Error() ignores Err; remove the synthetic wrapped
error and return &BodyDecodeError{Kind: BodyDecodeErrorMultipleDocuments} (i.e.,
drop Err) so Unwrap() and callers aren't misled, or alternatively propagate the
actual decoder error similar to other branches—update the code path that
constructs the error in the second Decode success branch and ensure consistency
with how BodyDecodeError is constructed elsewhere.

In `@request_internal.go`:
- Around line 48-55: The handler for BodyDecodeErrorBodyTooLarge currently
returns a 413 title but still uses problems.TypeURL("bad_request_error"); update
the TypeURL argument in the BodyDecodeErrorBodyTooLarge branch (where
NewProblemDetails is called) to use a dedicated key such as "payload_too_large"
or "request_entity_too_large" (falling back to "bad_request_error" via your
existing ProblemConfig lookup if missing) so clients and ProblemConfig consumers
can map this 413 to its own documentation URL rather than the generic
bad_request_error.

In `@response_write.go`:
- Around line 86-87: The log message incorrectly refers to JSON encoding when
the error comes from writing the response body; update the log in the block that
calls w.Write(buffer.Bytes()) (in response_write.go, around the anonymous write
error check) to say something like "Failed to write response body" and include
the error value so it reflects a response-body write failure rather than an
encoding error.
🪄 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: a76e0253-27c3-408d-a91a-dee250990b6b

📥 Commits

Reviewing files that changed from the base of the PR and between 916b770 and 7db2a87.

⛔ Files ignored due to path filters (5)
  • examples/chi/go.sum is excluded by !**/*.sum
  • examples/restapi/go.sum is excluded by !**/*.sum
  • go.work is excluded by !**/*.work
  • go.work.sum is excluded by !**/*.sum
  • validation/playground/go.sum is excluded by !**/*.sum
📒 Files selected for processing (23)
  • .github/workflows/release.yml
  • README.md
  • examples/chi/go.mod
  • examples/restapi/go.mod
  • examples/restapi/main.go
  • examples/restapi/main_test.go
  • examples/stdmux/main.go
  • problem_config.go
  • problem_details.go
  • problem_details_test.go
  • request_decode.go
  • request_decode_test.go
  • request_internal.go
  • request_test.go
  • response_builder.go
  • response_builder_test.go
  • response_meta.go
  • response_meta_test.go
  • response_test.go
  • response_write.go
  • validation/playground/go.mod
  • validation/playground/validator.go
  • validation/playground/validator_test.go

Comment thread .github/workflows/release.yml
Comment thread .github/workflows/release.yml
@rluders rluders merged commit e4422b5 into main Apr 18, 2026
8 checks passed
@rluders rluders deleted the fix/review-followups-release-tagging branch April 18, 2026 23:21
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.

1 participant