Skip to content

Refine v3 core and add modular validation#12

Merged
rluders merged 1 commit intomainfrom
feature/v3-hardening-and-ci
Apr 18, 2026
Merged

Refine v3 core and add modular validation#12
rluders merged 1 commit intomainfrom
feature/v3-hardening-and-ci

Conversation

@rluders
Copy link
Copy Markdown
Owner

@rluders rluders commented Apr 18, 2026

Summary

  • restructure the v3 core into smaller request/response/problem files
  • add the optional validation/playground submodule and richer examples/docs
  • harden ParseRequest against nil-input panics and preserve validator-provided statuses
  • add fuller CI/release workflows plus focused tests and benchmarks

Verification

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

Summary by CodeRabbit

Release Notes

  • New Features

    • Added fluent request and response builders for cleaner, chainable API usage.
    • Introduced configurable RFC 9457 problem response type URLs via ProblemConfig.
    • Added playground validation adapter for optional request validation.
  • Refactor

    • Redesigned request parsing with simplified ParseRequest signature.
    • Decoupled validation into optional external adapters.
    • Refactored response construction with builder and helper patterns.
  • Documentation

    • Updated README with v3 migration guide and mental model.
  • Chores

    • Updated examples to v3 API; added new REST API example.
    • Added CI and release GitHub Actions workflows.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 18, 2026

📝 Walkthrough

Walkthrough

Major version upgrade from v2 to v3 introducing a modular architecture: extracts validation into a separate validation/playground module, refactors request parsing with delegated body decoding and path binding, introduces fluent builder APIs for problems and responses, removes global state in favor of configuration objects, and updates all examples and CI/CD workflows accordingly.

Changes

Cohort / File(s) Summary
GitHub Actions Workflows
.github/workflows/ci.yml, .github/workflows/release.yml, .github/workflows/go.yml
Added new CI workflow with four jobs (root, validation-playground, examples matrix, workspace sync verification); added Release workflow with verify and github-release jobs; removed legacy go.yml workflow.
Root Module
go.mod
Updated module path from v2 to v3, removed explicit dependency declarations.
Problem Handling
problem_details.go, problem_config.go, problem_builder.go, problem_helpers.go
Moved global state to ProblemConfig struct with default mappings; renamed BlankUrl to BlankURL; added validation for HTTP status clamping; introduced ProblemBuilder fluent API and helper functions (ProblemBadRequest, ProblemNotFound).
Request Processing
request.go, request_types.go, request_decode.go, request_bind.go, request_internal.go, request_validate.go
Refactored ParseRequest to delegate body decoding and path binding; removed RequestParamSetter constraint; introduced ParseOptions configuration; added BodyDecodeError and PathParamError typed errors; extracted validation to ValidateRequest with concurrency-safe default validator management.
Response Handling
response.go, response_builder.go, response_helpers.go, response_meta.go, response_write.go
Removed Response[T] and Meta types from response.go; added ReplyBuilder and ResponseBuilder[T] fluent APIs via Reply(), Respond(), RespondProblem(); reintroduced Response[T], PageMeta, CursorMeta in response_meta.go; delegated serialization to internal writeResponse.
Validation Module
validation/playground/go.mod, validation/playground/validator.go, validation.go
Extracted validation logic from core package into validation/playground; removed validation.go from root; introduced playground.Validator adapter for go-playground/validator with New, RegisterDefault, NewWithValidator constructors.
Examples
examples/stdmux/..., examples/gorillamux/..., examples/chi/..., examples/restapi/...
Updated stdmux, gorillamux, chi examples to use v3 API (removed validation tags, updated ParseRequest signature, added nil parameter, changed validator setup); added new comprehensive restapi example with pagination, CRUD endpoints, concurrent user store, and structured error handling.
Documentation & Tests
README.md, *_test.go, *_benchmark_test.go
Extensively updated README with v3 mental model, migration guide, builder API examples; refactored all test suites to remove testify/assert, use typed errors (errors.Is/errors.As), validate new builder patterns; added benchmarks for request decoding and response sending.

Sequence Diagrams

sequenceDiagram
    actor Client
    participant Router
    participant ParseRequest
    participant DecodeRequestBody
    participant BindPathParams
    participant ValidateRequest
    participant Handler

    Client->>Router: HTTP Request
    Router->>ParseRequest: ParseRequest[T](..., opts, pathParams)
    
    ParseRequest->>DecodeRequestBody: Decode JSON body
    alt Body Decode Success
        DecodeRequestBody-->>ParseRequest: Decoded T
    else Decode Error
        DecodeRequestBody-->>ParseRequest: BodyDecodeError
        ParseRequest->>Router: Write ProblemDetails (400/413)
        Router-->>Client: Error Response
        Note over ParseRequest: Return with error
    end
    
    ParseRequest->>BindPathParams: Bind path params
    alt Binding Success
        BindPathParams-->>ParseRequest: Populated T
    else Binding Error
        BindPathParams-->>ParseRequest: PathParamError
        ParseRequest->>Router: Write ProblemDetails (400)
        Router-->>Client: Error Response
        Note over ParseRequest: Return with error
    end
    
    alt Not SkipValidation
        ParseRequest->>ValidateRequest: Validate T
        alt Validation Success
            ValidateRequest-->>ParseRequest: nil
        else Validation Failure
            ValidateRequest-->>ParseRequest: ProblemDetails
            ParseRequest->>Router: Write ProblemDetails (400+)
            Router-->>Client: Error Response
            Note over ParseRequest: Return with error
        end
    end
    
    ParseRequest-->>Handler: Valid T, nil error
    Handler->>Router: Process request
Loading
sequenceDiagram
    actor Handler
    participant Reply/Respond
    participant ResponseBuilder
    participant writeResponse
    participant Client

    Handler->>Reply/Respond: Reply() / Respond(data)
    Reply/Respond-->>ResponseBuilder: ReplyBuilder / ResponseBuilder[T]
    
    Handler->>ResponseBuilder: .Status(...).Meta(...).Header(...)
    ResponseBuilder-->>Handler: Self (chainable)
    
    Handler->>ResponseBuilder: .Write(w) / .OK(w) / .Created(w, location)
    ResponseBuilder->>writeResponse: writeResponse(code, data, problem, meta, headers)
    
    alt Problem Response (status >= 400)
        writeResponse->>writeResponse: writeProblemDetail(...)
        writeResponse->>Client: Content-Type: application/problem+json
        writeResponse->>Client: Write ProblemDetails JSON
    else Success Response
        writeResponse->>writeResponse: Marshal Response[T]
        writeResponse->>Client: Content-Type: application/json
        writeResponse->>Client: Write { data, meta } JSON
    end
    
    writeResponse-->>Handler: Done
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

Poem

🐰 From v2's rigid paths to v3's fluent dance,
Builders bloom and validators prance,
Request flows now split with grace,
Problems configured in their place,
A modular hutch—hop along with us!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.51% 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 'Refine v3 core and add modular validation' clearly and accurately summarizes the main changes: restructuring v3 core into smaller files and introducing optional modular validation via a new playground submodule.

✏️ 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 feature/v3-hardening-and-ci

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: 12

🧹 Nitpick comments (4)
problem_config.go (1)

30-43: Redundant clone in mergeProblemConfig.

DefaultProblemConfig() already returns a deep clone, so the additional merged.Clone() on line 42 performs a second unnecessary deep copy on every merge call.

♻️ Proposed simplification
 func mergeProblemConfig(config *ProblemConfig) ProblemConfig {
 	merged := DefaultProblemConfig()
 	if config == nil {
 		return merged
 	}

 	if config.BaseURL != "" {
-		merged.BaseURL = config.BaseURL
+		merged.BaseURL = strings.TrimRight(config.BaseURL, "/")
 	}
 	for key, value := range config.ErrorTypePaths {
-		merged.ErrorTypePaths[key] = value
+		merged.ErrorTypePaths[key] = normalizeProblemPath(value)
 	}
-	return merged.Clone()
+	return merged
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@problem_config.go` around lines 30 - 43, The function mergeProblemConfig
performs an unnecessary second deep copy by calling merged.Clone() before
returning; since DefaultProblemConfig() already returns a deep clone, remove the
redundant cloned return and return the merged variable directly. Update
mergeProblemConfig (referencing the symbols mergeProblemConfig,
DefaultProblemConfig, and merged.Clone) to eliminate the extra Clone call so the
function returns merged without an additional deep copy.
examples/stdmux/main.go (1)

34-38: StdMuxParamExtractor ignores key and only works for /submit/ paths.

The extractor hard-codes the /submit/ prefix and disregards the key argument, so if ParseRequest is ever called with additional path fields, every lookup returns the same suffix. Since this is example code the current behavior is fine for the demo, but a tiny switch on key (or using strings.TrimPrefix) would make the example more instructive and future-proof.

♻️ Suggested tweak
-func StdMuxParamExtractor(r *http.Request, key string) string {
-	// Remove "/submit/" (7 characters) from the URL path to get just the "id"
-	// Example: /submit/123 -> 123
-	return r.URL.Path[len("/submit/"):] // Skip the "/submit/" part
-}
+func StdMuxParamExtractor(r *http.Request, key string) string {
+	switch key {
+	case "id":
+		return strings.TrimPrefix(r.URL.Path, "/submit/")
+	}
+	return ""
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/stdmux/main.go` around lines 34 - 38, StdMuxParamExtractor currently
ignores the key parameter and always trims the hard-coded "/submit/" prefix;
update StdMuxParamExtractor to use the provided key (or a switch on key) when
extracting params — e.g., compute the expected prefix from key (like
"/"+key+"/") and use strings.TrimPrefix or conditional logic to return the
suffix only when that prefix matches, falling back to r.URL.Path or empty string
otherwise; change references inside StdMuxParamExtractor to use the key variable
rather than the literal "/submit/".
.github/workflows/release.yml (1)

60-68: Gate the github-release job to tag-triggered events or provide explicit tag_name for manual dispatch.

The workflow is triggered by both push with v* tags and workflow_dispatch. When triggered via workflow_dispatch on a non-tag ref, the github-release job will attempt to create a release against a non-existent tag (since github.ref_name will be a branch name, not a tag). Add an explicit if: github.ref_type == 'tag' condition to the job, or provide tag_name explicitly in the action step. The GITHUB_TOKEN should have sufficient permissions via the workflow's permissions: contents: write setting, but consider adding it explicitly for clarity if the release step fails.

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

In @.github/workflows/release.yml around lines 60 - 68, The github-release job
currently runs for workflow_dispatch and push events and will error when
dispatching on non-tag refs; update the github-release job (job name
"github-release") to only run for tags by adding a job-level condition like if:
github.ref_type == 'tag' OR, alternatively, pass an explicit tag to the
softprops/action-gh-release step (the step that uses
softprops/action-gh-release@v2) by supplying tag_name: ${{ github.ref_name }} so
it doesn’t attempt to create a release for a branch; also ensure the workflow
permissions include contents: write (or document adding it) so the GITHUB_TOKEN
has rights to create releases.
validation/playground/validator.go (1)

60-65: Return JSON field names in validation errors.

The validation errors currently expose Go struct field names (e.g., Email, Name) instead of the JSON field names sent by clients (e.g., email, name). Examples like examples/restapi/main.go show structs with both JSON and validation tags where field names differ. Register a JSON tag-name function so ValidationErrorDetail.Field matches the request payload structure and improves API error clarity.

♻️ Proposed refactor
 import (
 	"errors"
 	"net/http"
+	"reflect"
+	"strings"
 
 	playgroundvalidator "github.com/go-playground/validator/v10"
 	"github.com/rluders/httpsuite/v3"
 )
@@
 func New() *Validator {
-	return NewWithValidator(playgroundvalidator.New(), nil)
+	validate := playgroundvalidator.New()
+	validate.RegisterTagNameFunc(jsonFieldName)
+	return NewWithValidator(validate, nil)
 }
@@
 func NewWithValidator(validate *playgroundvalidator.Validate, problems *httpsuite.ProblemConfig) *Validator {
 	if validate == nil {
 		validate = playgroundvalidator.New()
+		validate.RegisterTagNameFunc(jsonFieldName)
 	}
@@
 }
+
+func jsonFieldName(field reflect.StructField) string {
+	name := strings.Split(field.Tag.Get("json"), ",")[0]
+	if name == "-" {
+		return ""
+	}
+	if name != "" {
+		return name
+	}
+	return field.Name
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@validation/playground/validator.go` around lines 60 - 65, The
ValidationErrorDetail currently uses Go struct field names because the validator
instance hasn't been told to use JSON tag names; register a tag-name function on
the validator (via validator.RegisterTagNameFunc) that returns the JSON tag
(strings.Split(f.Tag.Get("json"), ",")[0]) and treats "-" as empty, ensure this
registration happens when the validator is constructed (before any validation
runs), and then the existing loop that builds errorDetails from validationErrors
and httpsuite.ValidationErrorDetail.Field will produce JSON field names instead
of Go struct names.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@examples/restapi/go.mod`:
- Line 17: Update the vulnerable dependency declaration "golang.org/x/crypto
v0.32.0" in go.mod to v0.45.0 or later; replace the version token for
golang.org/x/crypto with the new version, run `go get
golang.org/x/crypto@v0.45.0` (or newer) and then `go mod tidy` to update go.sum,
and re-run your vulnerability scanner to verify the issue is resolved.

In `@examples/restapi/main.go`:
- Around line 127-142: The offset computation can overflow because page and
page_size come from the query string; ensure you clamp/validate them and perform
the multiplication safely before casting to an index. Specifically, after
reading page and pageSize from readPositiveInt, enforce minimums (page >= 1,
pageSize >= 1) and compute the offset using a wider integer type (e.g., int64)
or check for overflow: if int64(page-1)*int64(pageSize) >= int64(len(users))
then set start = len(users) else set start = (page-1)*pageSize; then compute end
= min(len(users), start+pageSize) and use users[start:end] and NewPageMeta(page,
pageSize, len(users)).

In `@problem_details.go`:
- Around line 7-15: ProblemDetails currently marshals Extensions as a nested
"extensions" object; implement custom JSON marshaling on the ProblemDetails type
so Extensions are emitted as additional top-level members per RFC 9457. Add a
MarshalJSON (and optionally UnmarshalJSON) for ProblemDetails that builds a
map[string]interface{} with the core fields (Type, Title, Status, Detail,
Instance) only when non-empty, then range over p.Extensions and copy each
key/value into that map (overwriting duplicates if needed), and finally
json.Marshal that map; reference the ProblemDetails type and its Extensions
field when making the change.

In `@README.md`:
- Around line 208-213: The README contains absolute local filesystem links to
the examples (e.g., `/home/rluders/Projects/rluders/httpsuite/examples`,
`/home/rluders/Projects/rluders/httpsuite/examples/stdmux/main.go`,
`/home/rluders/Projects/rluders/httpsuite/examples/gorillamux/main.go`,
`/home/rluders/Projects/rluders/httpsuite/examples/chi/main.go`,
`/home/rluders/Projects/rluders/httpsuite/examples/restapi/main.go`); replace
them with repository-relative links like `examples/`, `examples/stdmux/main.go`,
`examples/gorillamux/main.go`, `examples/chi/main.go`, and
`examples/restapi/main.go` so links resolve on GitHub and in clones.

In `@request_bind_test.go`:
- Around line 3-7: Add the "context" import to request_bind_test.go and replace
every call to httptest.NewRequest(...) with
httptest.NewRequestWithContext(context.Background(), ...) used in the test
functions (look for the httptest.NewRequest calls in the file) so each test
request is context-aware; ensure all occurrences are updated (the import list
and all places creating requests).

In `@request_decode.go`:
- Around line 82-91: In the trailing-content check in request_decode.go (the
block that decodes into the local variable trailing using
decoder.Decode(&trailing)), replace the direct comparison err != io.EOF with an
errors.Is(err, io.EOF) check and add handling for *http.MaxBytesError: if
errors.Is(err, io.EOF) is false then if errors.As(err, &maxBytesErr) return a
BodyDecodeError with Kind BodyDecodeErrorBodyTooLarge, otherwise preserve the
existing behavior of returning BodyDecodeErrorMultipleDocuments; this change
should be applied to the trailing Decode() handling near the Decode(&trailing)
call and use the existing BodyDecodeError types and error wrapping patterns
already used for the first Decode() call.

In `@request_internal.go`:
- Around line 48-54: The branch handling BodyDecodeErrorBodyTooLarge currently
returns the generic status variable (400); update this branch so it returns HTTP
413 Payload Too Large instead. Locate the BodyDecodeErrorBodyTooLarge case in
request_internal.go and change the returned status to
http.StatusRequestEntityTooLarge (or the equivalent 413 constant) when calling
NewProblemDetails so the response and status code reflect the MaxBodyBytes
violation.

In `@response_builder.go`:
- Around line 55-63: The Headers merge currently calls b.Header(key, value)
which uses http.Header.Set and therefore overwrites earlier values for the same
header key; update both ReplyBuilder.Headers and ResponseBuilder.Headers to
append values instead of replacing them by using http.Header.Add (or the
builder's equivalent add method) for each value so multi-valued headers (e.g.,
Set-Cookie, Link, Vary, WWW-Authenticate) are preserved.

In `@response_meta.go`:
- Line 5: Remove the `omitempty` JSON tag from fields that can validly be
zero/false so those values are serialized; specifically update the struct tags
for Response[T].Data and CursorMeta.HasNext / CursorMeta.HasPrev to drop
`omitempty` so values like 0, false, and "" are preserved in JSON output, then
run tests or marshal examples to verify the Data and HasNext/HasPrev fields
appear when set to zero/false.

In `@response_write.go`:
- Around line 25-31: The code is returning raw serializer errors to clients via
NewProblemDetails(..., err.Error(), ...); instead replace the client-facing
detail with a generic message (e.g., "An unexpected error occurred") while
logging the original err for diagnostics, then call writeProblemDetail as
before; update the block that creates internalError (NewProblemDetails,
GetProblemTypeURL, internalError) to use the generic detail and ensure you log
err (using the existing logger or standard log) before returning the 500.
- Around line 55-58: The writeProblemDetail path currently applies headers and
calls w.WriteHeader before encoding the ProblemDetails JSON, so encoding
failures (e.g., from ProblemDetails.Extensions) cannot be recovered; change
writeProblemDetail to first marshal/encode the normalized ProblemDetails into a
buffer (mirroring writeResponse), check for encoding errors, and only then call
applyHeaders(w, headers), set the Content-Type and
w.WriteHeader(effectiveStatus), and write the buffered bytes; reference
functions/variables: writeProblemDetail, applyHeaders, writeResponse,
ProblemDetails.Extensions, normalized, effectiveStatus.

In `@validation/playground/go.mod`:
- Line 15: The go.mod entries pinning "golang.org/x/crypto v0.32.0" are
vulnerable; update each require line that references golang.org/x/crypto
(currently "golang.org/x/crypto v0.32.0") to a secure release such as v0.50.0
(or at minimum v0.45.0) so downstream consumers don’t inherit the vulnerable ssh
packages; edit the require statement in each impacted module (the lines
containing "golang.org/x/crypto v0.32.0") to the new version and run go mod tidy
to update go.sum accordingly.

---

Nitpick comments:
In @.github/workflows/release.yml:
- Around line 60-68: The github-release job currently runs for workflow_dispatch
and push events and will error when dispatching on non-tag refs; update the
github-release job (job name "github-release") to only run for tags by adding a
job-level condition like if: github.ref_type == 'tag' OR, alternatively, pass an
explicit tag to the softprops/action-gh-release step (the step that uses
softprops/action-gh-release@v2) by supplying tag_name: ${{ github.ref_name }} so
it doesn’t attempt to create a release for a branch; also ensure the workflow
permissions include contents: write (or document adding it) so the GITHUB_TOKEN
has rights to create releases.

In `@examples/stdmux/main.go`:
- Around line 34-38: StdMuxParamExtractor currently ignores the key parameter
and always trims the hard-coded "/submit/" prefix; update StdMuxParamExtractor
to use the provided key (or a switch on key) when extracting params — e.g.,
compute the expected prefix from key (like "/"+key+"/") and use
strings.TrimPrefix or conditional logic to return the suffix only when that
prefix matches, falling back to r.URL.Path or empty string otherwise; change
references inside StdMuxParamExtractor to use the key variable rather than the
literal "/submit/".

In `@problem_config.go`:
- Around line 30-43: The function mergeProblemConfig performs an unnecessary
second deep copy by calling merged.Clone() before returning; since
DefaultProblemConfig() already returns a deep clone, remove the redundant cloned
return and return the merged variable directly. Update mergeProblemConfig
(referencing the symbols mergeProblemConfig, DefaultProblemConfig, and
merged.Clone) to eliminate the extra Clone call so the function returns merged
without an additional deep copy.

In `@validation/playground/validator.go`:
- Around line 60-65: The ValidationErrorDetail currently uses Go struct field
names because the validator instance hasn't been told to use JSON tag names;
register a tag-name function on the validator (via
validator.RegisterTagNameFunc) that returns the JSON tag
(strings.Split(f.Tag.Get("json"), ",")[0]) and treats "-" as empty, ensure this
registration happens when the validator is constructed (before any validation
runs), and then the existing loop that builds errorDetails from validationErrors
and httpsuite.ValidationErrorDetail.Field will produce JSON field names instead
of Go struct names.
🪄 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: 2c1d7169-dca6-4bad-bca8-c24e1e692c69

📥 Commits

Reviewing files that changed from the base of the PR and between bc310e5 and bd26a02.

⛔ Files ignored due to path filters (6)
  • examples/chi/go.sum is excluded by !**/*.sum
  • examples/gorillamux/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 (47)
  • .github/workflows/ci.yml
  • .github/workflows/go.yml
  • .github/workflows/release.yml
  • README.md
  • examples/chi/go.mod
  • examples/chi/main.go
  • examples/gorillamux/go.mod
  • examples/gorillamux/main.go
  • examples/restapi/go.mod
  • examples/restapi/main.go
  • examples/stdmux/go.mod
  • examples/stdmux/main.go
  • go.mod
  • problem_builder.go
  • problem_builder_test.go
  • problem_config.go
  • problem_config_test.go
  • problem_details.go
  • problem_details_test.go
  • problem_helpers.go
  • problem_helpers_test.go
  • request.go
  • request_bind.go
  • request_bind_test.go
  • request_decode.go
  • request_decode_test.go
  • request_internal.go
  • request_test.go
  • request_test_helpers_test.go
  • request_types.go
  • request_validate.go
  • request_validate_test.go
  • response.go
  • response_benchmark_test.go
  • response_builder.go
  • response_builder_test.go
  • response_helpers.go
  • response_helpers_test.go
  • response_meta.go
  • response_meta_test.go
  • response_test.go
  • response_write.go
  • validation.go
  • validation/playground/go.mod
  • validation/playground/validator.go
  • validation/playground/validator_test.go
  • validation_test.go
💤 Files with no reviewable changes (3)
  • .github/workflows/go.yml
  • validation.go
  • validation_test.go

Comment thread examples/restapi/go.mod
Comment thread examples/restapi/main.go
Comment thread problem_details.go
Comment thread README.md
Comment thread request_bind_test.go
Comment thread response_builder.go
Comment thread response_meta.go
Comment thread response_write.go
Comment thread response_write.go
Comment thread validation/playground/go.mod
@rluders rluders merged commit 916b770 into main Apr 18, 2026
8 checks passed
@rluders rluders deleted the feature/v3-hardening-and-ci branch April 18, 2026 21:52
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