Skip to content

🔥 feat: Add All method to Bind #3373

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
May 14, 2025

Conversation

edvardsanta
Copy link
Contributor

@edvardsanta edvardsanta commented Mar 25, 2025

Description

This pull request introduces a new All method in the Bind struct to unify data binding from multiple sources (URL parameters, body, query, headers, and cookies) into a single struct. It also includes corresponding documentation updates, test cases, and a benchmark for the new method.

New All method in Bind struct:

  • Implementation of All method: Added a new All method in the Bind struct to bind data from multiple sources into a struct pointer. It processes the sources in a predefined precedence order and ensures that only unset fields are updated. Helper functions mergeStruct and isZero were added to support this functionality.

Testing and benchmarking:

  • Test cases for All method: Introduced comprehensive test cases for the All method, including scenarios for invalid output types, partial JSON, precedence handling, and different content types (e.g., JSON, form data). Added a RequestConfig helper struct to simplify test setup.
  • Benchmark for All method: Added a benchmark test to measure the performance of the All method under repeated binding operations.

Documentation updates:

  • API documentation for All method: Updated the API documentation to include the All method, detailing its usage, precedence order, and an example.

These changes enhance the flexibility and usability of the Bind struct by consolidating multiple data sources into a single binding operation while maintaining clear documentation and robust testing.

Fixes #3363

Changes introduced

List the new features or adjustments introduced in this pull request. Provide details on benchmarks, documentation updates, changelog entries, and if applicable, the migration guide.

  • Benchmarks: Describe any performance benchmarks and improvements related to the changes.
  • Documentation Update: Detail the updates made to the documentation and links to the changed files.
  • Changelog/What's New: Include a summary of the additions for the upcoming release notes.
  • Migration Guide: If necessary, provide a guide or steps for users to migrate their existing code to accommodate these changes.
  • API Alignment with Express: Explain how the changes align with the Express API.
  • API Longevity: Discuss the steps taken to ensure that the new or updated APIs are consistent and not prone to breaking changes.
  • Examples: Provide examples demonstrating the new features or changes in action.

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)
  • Enhancement (improvement to existing features and functionality)
  • Documentation update (changes to documentation)
  • Code consistency (non-breaking change which improves code reliability and robustness)

Checklist

Before you submit your pull request, please make sure you meet these requirements:

  • Followed the inspiration of the Express.js framework for new functionalities, making them similar in usage.
  • Conducted a self-review of the code and provided comments for complex or critical parts.
  • Updated the documentation in the /docs/ directory for Fiber's documentation.
  • Added or updated unit tests to validate the effectiveness of the changes or new features.
  • Ensured that new and existing unit tests pass locally with the changes.
  • Verified that any new dependencies are essential and have been agreed upon by the maintainers/community.
  • Aimed for optimal performance with minimal allocations in the new code.
  • Provided benchmarks for the new code to analyze and improve upon.

Commit formatting

Please use emojis in commit messages for an easy way to identify the purpose or intention of a commit. Check out the emoji cheatsheet here: CONTRIBUTING.md

This commit introduces a new `All` method to the `Bind` struct, enabling the binding of request data from multiple sources (URI parameters, body, query parameters, headers, and cookies) into a single struct.

The `All` method iterates through the available binding sources, applying them in a predefined precedence order. It merges the values from each source into the output struct, only updating fields that are currently unset.

Changes:

- Added `All` method to `Bind` struct.
- Added `mergeStruct` helper function to merge struct values.
- Added `isZero` helper function to check if a value is zero.
- Added a test case for the `All` method in `bind_test.go` to validate its functionality.
Copy link
Contributor

coderabbitai bot commented Mar 25, 2025

Walkthrough

A new method, All, has been added to the Bind struct to enable binding data from multiple HTTP sources (URI parameters, body, query parameters, headers, and cookies) into a single struct, following a defined precedence. The implementation introduces helper functions for merging struct fields and checking zero values. Comprehensive tests and a benchmark for the new method have been added, including a utility for request configuration and coverage for field precedence and error handling.

Changes

File(s) Change Summary
bind.go Added Bind.All(out any) error method to bind from multiple sources with precedence; added helpers mergeStruct and isZero.
bind_test.go Added RequestConfig struct and ApplyTo method; new tests for Bind.All covering precedence, error handling, and partial data; added benchmark for Bind.All.
docs/api/bind.md Added documentation for Bind.All method including usage example and precedence rules.
docs/whats_new.md Updated to include Bind().All() unified binding feature and precedence order.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Bind
    participant URI
    participant Body
    participant Query
    participant Header
    participant Cookie

    Client->>Bind: All(out)
    Bind->>URI: Bind URI params
    Bind->>Body: Bind body
    Bind->>Query: Bind query params
    Bind->>Header: Bind headers
    Bind->>Cookie: Bind cookies
    Bind-->>Client: Populated struct (with precedence)
Loading

Assessment against linked issues

Objective Addressed Explanation
Implement Bind.All method to bind from multiple request sources (URI, body, query, headers, cookies) into a single struct (#3363)
Enforce source precedence: URI > Body > Query > Headers > Cookies (#3363)
Provide error handling for binding failures in All method (#3363)
Add tests covering binding from multiple sources, precedence, and error cases (#3363)

Suggested reviewers

  • ReneWerner87
  • gaby

Poem

🐇 In code fields wide and deep,
The binder hops without a leap.
From params, body, query, and more,
It gathers data to the core.
With tests and docs, it’s quite the call—
A rabbit’s joy: the Bind.All! ✨

Tip

⚡️ Faster reviews with caching
  • CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.

Enjoy the performance boost—your workflow just got faster.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb68706 and 8703fef.

📒 Files selected for processing (1)
  • docs/whats_new.md (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • docs/whats_new.md
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: unit (1.24.x, windows-latest)
  • GitHub Check: unit (1.24.x, macos-13)
  • GitHub Check: unit (1.23.x, windows-latest)
  • GitHub Check: Compare
  • GitHub Check: repeated
  • GitHub Check: Analyse

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@edvardsanta edvardsanta changed the title feat: Add All method to Bind 🔥 feat: Add All method to Bind Mar 25, 2025
@ReneWerner87 ReneWerner87 added this to v3 Mar 25, 2025
@ReneWerner87 ReneWerner87 added this to the v3 milestone Mar 25, 2025
@edvardsanta
Copy link
Contributor Author

@ReneWerner87 please let me know if you have any feedback, suggestions, or improvements for the code. I’ll make any necessary adjustments and work on improving the tests when I have some time.

@gaby gaby moved this to In Progress in v3 Mar 26, 2025
The changes include:

- Added `RequestConfig` struct to encapsulate request configuration (ContentType, Body, Headers, Cookies, Query).
- Implemented `ApplyTo` method on `RequestConfig` to apply the configuration to the context.
- Created multiple test cases for `Bind.All` covering successful binding, missing fields, overriding query parameters, and form binding.
- Added a test case `Test_Bind_All_Uri_Precedence` to validate the precedence of URI parameters.
- Added benchmark test `BenchmarkBind_All` to measure the performance of the `Bind.All` method.
- Refactored the `TestBind_All` to use the new `RequestConfig` and assertion libraries.
@edvardsanta edvardsanta marked this pull request as ready for review April 21, 2025 03:24
@edvardsanta edvardsanta requested a review from a team as a code owner April 21, 2025 03:24
Copy link
Contributor

@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 (4)
bind.go (2)

299-309: Remove the initial blank line inside the for block to satisfy revive / empty-lines lint rule

golangci‑lint fails with extra empty line at the start of a block.
A one‑line diff fixes it:

 for _, bindFunc := range sources {
-
+	// attempt bind from the current source
 	if err := bindFunc(tempStruct); err != nil {
 		return err
 	}
🧰 Tools
🪛 GitHub Check: lint

[failure] 301-301:
empty-lines: extra empty line at the start of a block (revive)

🪛 GitHub Actions: golangci-lint

[error] 301-301: golangci-lint (revive): extra empty line at the start of a block (empty-lines)


314-327: mergeStruct copies only top‑level zero fields – nested structs remain partially empty

Because the function checks isZero on the destination field as a whole,
a nested struct such as Address{City, Zip} will never receive the City
coming from a later source once any field inside Address has a
non‑zero value.
If deep merging is important, consider recursing into nested structs or
requiring pointer fields.

Not blocking, but worth documenting in godoc to avoid surprises.

bind_test.go (2)

1919-2041: Run each table‑driven sub‑test in parallel and use require for fatal assertions

  1. Add t.Parallel() inside the sub‑test to comply with the tparallel
    lint suggestion and speed up the suite.
  2. Replace assert.NoError with require.NoError so the test aborts
    immediately on failure, keeping subsequent checks safe.
 		t.Run(tt.name, func(t *testing.T) {
+			t.Parallel()
 			bind := newBind(app)
@@
-			err := bind.All(tt.out)
-			if tt.wantErr {
-				assert.Error(t, err)
+			err := bind.All(tt.out)
+			if tt.wantErr {
+				require.Error(t, err)
 				return
 			}
-			assert.NoError(t, err)
+			require.NoError(t, err)
🧰 Tools
🪛 GitHub Check: lint

[failure] 2027-2027:
require-error: for error assertions use require (testifylint)


[failure] 1949-1949:
fieldalignment: struct with 48 pointer bytes could be 40 (govet)


[failure] 1921-1921:
fieldalignment: struct with 72 pointer bytes could be 64 (govet)


[failure] 1919-1919:
Test_Bind_All's subtests should call t.Parallel (tparallel)


1891-1917: RequestConfig.ApplyTo leaves previous request state untouched – add a reset

Because the same ctx is reused, fields that are not overridden by the
current RequestConfig (query string, cookies, headers, …) survive from
earlier test cases, leading to flakiness (see wrong ID above).

Insert a reset at the top of ApplyTo:

 func (rc *RequestConfig) ApplyTo(ctx Ctx) {
+	ctx.Request().Reset()
 	if rc.Body != nil {

(This doesn’t affect production code – it’s only a test helper.)

🧰 Tools
🪛 GitHub Check: lint

[failure] 1891-1891:
fieldalignment: struct with 64 pointer bytes could be 56 (govet)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 85cce3c and 32dd82b.

📒 Files selected for processing (2)
  • bind.go (2 hunks)
  • bind_test.go (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
bind_test.go (2)
Learnt from: sixcolors
PR: gofiber/fiber#2922
File: middleware/cors/utils.go:63-71
Timestamp: 2024-07-26T21:00:12.902Z
Learning: The project uses the testify/assert package for assertions in unit tests.
Learnt from: sixcolors
PR: gofiber/fiber#2922
File: middleware/cors/utils.go:63-71
Timestamp: 2024-10-08T19:06:06.583Z
Learning: The project uses the testify/assert package for assertions in unit tests.
🪛 GitHub Check: lint
bind.go

[failure] 301-301:
empty-lines: extra empty line at the start of a block (revive)

bind_test.go

[failure] 2076-2076:
fieldalignment: struct with 72 pointer bytes could be 64 (govet)


[failure] 2046-2046:
fieldalignment: struct with 32 pointer bytes could be 24 (govet)


[failure] 2027-2027:
require-error: for error assertions use require (testifylint)


[failure] 1949-1949:
fieldalignment: struct with 48 pointer bytes could be 40 (govet)


[failure] 1921-1921:
fieldalignment: struct with 72 pointer bytes could be 64 (govet)


[failure] 1919-1919:
Test_Bind_All's subtests should call t.Parallel (tparallel)


[failure] 1891-1891:
fieldalignment: struct with 64 pointer bytes could be 56 (govet)

🪛 GitHub Actions: golangci-lint
bind.go

[error] 301-301: golangci-lint (revive): extra empty line at the start of a block (empty-lines)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Compare
  • GitHub Check: repeated
  • GitHub Check: Analyse

Copy link

codecov bot commented Apr 21, 2025

Codecov Report

Attention: Patch coverage is 92.85714% with 3 lines in your changes missing coverage. Please review.

Project coverage is 84.16%. Comparing base (4321dfe) to head (8703fef).
Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
bind.go 92.85% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3373      +/-   ##
==========================================
+ Coverage   84.00%   84.16%   +0.16%     
==========================================
  Files         119      119              
  Lines       11897    11939      +42     
==========================================
+ Hits         9994    10049      +55     
+ Misses       1475     1462      -13     
  Partials      428      428              
Flag Coverage Δ
unittests 84.16% <92.85%> (+0.16%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@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: 3

♻️ Duplicate comments (1)
bind_test.go (1)

2008-2008: ⚠️ Potential issue

Test expectation for Form binding needs correction.

When testing Form binding, with id=2 in the body, the expected ID should be 2, not 1. This appears to be a carryover from the previous test that had different data.

-				ID:    1,
+				ID:    2,

This also highlights a potential issue with request context reuse between tests. It would be clearer to explicitly reset or create a new context for each test case.

🧹 Nitpick comments (4)
bind_test.go (4)

1891-1897: Well-designed RequestConfig struct for test configuration.

This utility struct provides a clean way to configure request parameters for tests. The design is comprehensive, covering all the request components needed for the binding tests.

However, the struct could be optimized for memory efficiency:

type RequestConfig struct {
-	ContentType string
-	Body        []byte
-	Headers     map[string]string
-	Cookies     map[string]string
-	Query       string
+	Body        []byte
+	Headers     map[string]string
+	Cookies     map[string]string
+	ContentType string
+	Query       string
}

The static analysis indicates field alignment issues - reordering fields from largest to smallest can improve memory efficiency.

🧰 Tools
🪛 GitHub Check: lint

[failure] 1891-1891:
fieldalignment: struct with 64 pointer bytes could be 56 (govet)


2074-2112: Good benchmark implementation for the All method.

The benchmark properly measures the performance of the All method with realistic data and all binding sources. This addresses the previous request for benchmarks.

Similar to the User struct in the tests, this one also has field alignment issues:

type User struct {
-	ID        int                   `param:"id" query:"id" json:"id" form:"id"`
-	Avatar    *multipart.FileHeader `form:"avatar"`
-	Name      string                `query:"name" json:"name" form:"name"`
-	Email     string                `json:"email" form:"email"`
-	Role      string                `header:"x-user-role"`
-	SessionID string                `json:"session_id" cookie:"session_id"`
+	Avatar    *multipart.FileHeader `form:"avatar"`
+	ID        int                   `param:"id" query:"id" json:"id" form:"id"`
+	Name      string                `query:"name" json:"name" form:"name"`
+	Email     string                `json:"email" form:"email"`
+	Role      string                `header:"x-user-role"`
+	SessionID string                `json:"session_id" cookie:"session_id"`
}
🧰 Tools
🪛 GitHub Check: lint

[failure] 2076-2076:
fieldalignment: struct with 72 pointer bytes could be 64 (govet)


1921-1928: User struct efficiently captures binding from multiple sources.

The struct correctly uses tags for different binding sources (param, query, json, form, header, cookie) which demonstrates the capability of the new All method.

The field ordering could be optimized for memory efficiency (pointer fields first):

type User struct {
-	ID        int                   `param:"id" query:"id" json:"id" form:"id"`
-	Avatar    *multipart.FileHeader `form:"avatar"`
-	Name      string                `query:"name" json:"name" form:"name"`
-	Email     string                `json:"email" form:"email"`
-	Role      string                `header:"x-user-role"`
-	SessionID string                `json:"session_id" cookie:"session_id"`
+	Avatar    *multipart.FileHeader `form:"avatar"`
+	ID        int                   `param:"id" query:"id" json:"id" form:"id"`
+	Name      string                `query:"name" json:"name" form:"name"`
+	Email     string                `json:"email" form:"email"`
+	Role      string                `header:"x-user-role"`
+	SessionID string                `json:"session_id" cookie:"session_id"`
}
🧰 Tools
🪛 GitHub Check: lint

[failure] 1921-1921:
fieldalignment: struct with 72 pointer bytes could be 64 (govet)


2046-2050: User struct in URI precedence test is appropriately designed.

The struct correctly includes tags for different binding sources to test precedence rules.

Similar to the other structs, field alignment could be optimized:

type User struct {
-	ID    int    `param:"id" json:"id" query:"id" form:"id"`
-	Name  string `json:"name"`
-	Email string `json:"email"`
+	ID    int    `param:"id" json:"id" query:"id" form:"id"`
+	Name  string `json:"name"`
+	Email string `json:"email"`
}
🧰 Tools
🪛 GitHub Check: lint

[failure] 2046-2046:
fieldalignment: struct with 32 pointer bytes could be 24 (govet)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 32dd82b and 4799c50.

📒 Files selected for processing (1)
  • bind_test.go (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
bind_test.go (2)
Learnt from: sixcolors
PR: gofiber/fiber#2922
File: middleware/cors/utils.go:63-71
Timestamp: 2024-07-26T21:00:12.902Z
Learning: The project uses the testify/assert package for assertions in unit tests.
Learnt from: sixcolors
PR: gofiber/fiber#2922
File: middleware/cors/utils.go:63-71
Timestamp: 2024-10-08T19:06:06.583Z
Learning: The project uses the testify/assert package for assertions in unit tests.
🪛 GitHub Check: lint
bind_test.go

[failure] 2076-2076:
fieldalignment: struct with 72 pointer bytes could be 64 (govet)


[failure] 2046-2046:
fieldalignment: struct with 32 pointer bytes could be 24 (govet)


[failure] 2027-2027:
require-error: for error assertions use require (testifylint)


[failure] 1949-1949:
fieldalignment: struct with 48 pointer bytes could be 40 (govet)


[failure] 1921-1921:
fieldalignment: struct with 72 pointer bytes could be 64 (govet)


[failure] 1919-1919:
Test_Bind_All's subtests should call t.Parallel (tparallel)


[failure] 1891-1891:
fieldalignment: struct with 64 pointer bytes could be 56 (govet)

⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: unit (1.24.x, windows-latest)
  • GitHub Check: unit (1.23.x, windows-latest)
  • GitHub Check: repeated
  • GitHub Check: Compare
🔇 Additional comments (5)
bind_test.go (5)

13-13: Good addition of the required import.

Adding the strings package is necessary for the new test functionality, particularly for the request body creation in Test_Bind_All_Uri_Precedence.


19-19: Appropriate use of testify/assert package.

Using the assert package from testify aligns with the project's testing conventions as indicated in the retrieved learnings.


1899-1916: Clean implementation of ApplyTo method.

The method correctly applies all configuration properties to the request context in a logical order. The null checks prevent errors when optional fields aren't provided.


2043-2072: Good test for URI parameter precedence.

This test properly verifies that URI parameters take precedence over query parameters and JSON body when binding data, which is an important behavior of the new All method.

The test correctly sets up the scenario:

  1. URI parameter: id=111
  2. Query parameter: id=888
  3. JSON body: {"id": 999, ...}

And it verifies that the URI parameter value (111) is chosen.

🧰 Tools
🪛 GitHub Check: lint

[failure] 2046-2046:
fieldalignment: struct with 32 pointer bytes could be 24 (govet)


1946-1946: Test query parameter setup could be improved.

In the defaultConfig function, the query ID duplicates the ID from the JSON body.

Since the test is verifying binding behavior, consider making the IDs different to better validate the precedence rules:

-			Query: "id=1&name=john",
+			Query: "id=2&name=john",

This would make it clearer which source is being used when checking the bound value.

- Reordered fields in `RequestConfig` and `User` structs for field alignment
- Updated `Test_Bind_All` to use `require.NoError` for more robust error checking.
- Corrected header key casing in `Test_Bind_All` to `X-User-Role` to match the struct tag.
- Added `t.Parallel()` to the test function to enable parallel test execution.
@gaby gaby requested a review from Copilot April 21, 2025 03:45
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces an All method for the Bind struct to enable the merging of request data from multiple sources (URI, body, query, headers, and cookies), following a defined precedence order. Key changes include adding a new All method and mergeStruct helper in bind.go and comprehensive unit tests in bind_test.go covering various binding scenarios.

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
bind_test.go Adds tests for the new All method with various binding cases.
bind.go Implements the All method and mergeStruct helper to combine data from multiple sources.
Comments suppressed due to low confidence (1)

bind_test.go:1945

  • [nitpick] Consider adding test cases where fields with valid zero values (such as numeric fields intentionally set to 0) are bound, to verify that the merge logic handles them correctly.
Query: "id=1&name=john",

This commit adds documentation for the `Bind.All` function to the API documentation.

The documentation includes:

- A description of the function's purpose and precedence order for binding data from different sources (URI, body, query, headers, cookies).
Copy link
Contributor

@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: 1

🧹 Nitpick comments (2)
docs/api/bind.md (2)

446-451: Clarify merging semantics
The description and precedence list explain the order of sources but don’t explicitly state that All only sets zero‑valued fields and preserves values from higher‑precedence binders. Consider adding a note, for example:

“By design, All will not override non‑zero fields set by earlier binders; it only populates fields that remain at their zero value.”


462-462: Fix code fence formatting
The example block is opened with go (with a space). For consistency, it should be go (no space) to correctly highlight as Go code.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e6ff948 and 87a8dea.

📒 Files selected for processing (1)
  • docs/api/bind.md (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: unit (1.24.x, windows-latest)
  • GitHub Check: repeated
  • GitHub Check: unit (1.23.x, windows-latest)
  • GitHub Check: Compare
🔇 Additional comments (1)
docs/api/bind.md (1)

28-28: Binder list updated to include All
The new All binder is now listed under the Binders section. Placing it after the URI binder aligns with its broad, catch‑all scope.

@edvardsanta edvardsanta marked this pull request as draft April 21, 2025 19:01
@ReneWerner87
Copy link
Member

@edvardsanta PR is ready for review or ? can I switch from draft to normal?

@ReneWerner87
Copy link
Member

then I would take a look at it tomorrow

@edvardsanta
Copy link
Contributor Author

edvardsanta commented May 12, 2025

@ReneWerner87,

Sure, I can move it from draft to open. Just a heads-up that there are a few technical debts in the current implementation:

What's implemented

  • Precedence is in the following fixed order:
  1. URL Parameters (URI)
  2. Request Body (e.g., JSON or form data)
  3. Query Parameters
  4. Request Headers
  5. Cookies
  • Values are populated based on the first non-zero/non-empty value found in that order.

Technical Debts

  • ❌ No support for custom precedence configuration.
  • ❌ No validation logic for inputs (e.g., type checks, required fields).
  • ❌ No explicit handling of empty or zero values beyond default precedence.

If you're okay with that, i will openn the PR now. Feel free to create a follow-up issue for addressing these debts. I'd like to improve it later on, but since I just started at a new company, I’m a bit stretched for time right now.

PS: Just realized I wrote this in the issue instead of the PR, i thought I was already commenting on it

@edvardsanta edvardsanta marked this pull request as ready for review May 12, 2025 14:16
Copy link
Member

@ReneWerner87 ReneWerner87 left a comment

Choose a reason for hiding this comment

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

LGTM

@ReneWerner87
Copy link
Member

ReneWerner87 commented May 13, 2025

@gaby gaby requested a review from Copilot May 13, 2025 11:40
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces a new All method for the Bind struct that unifies data binding from multiple sources into a single struct, along with accompanying documentation, tests, and benchmarks.

  • Added the All method in Bind to process URL parameters, body, query, headers, and cookies in a defined precedence order.
  • Updated API docs with usage examples and added comprehensive tests and a benchmark for the new binding functionality.

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
docs/api/bind.md Added documentation for the new All method with clear examples.
bind_test.go Introduced test cases and benchmarks to validate the new All method.
bind.go Implemented the All method along with helper functions mergeStruct and isZero.
Comments suppressed due to low confidence (1)

bind.go:296

  • [nitpick] Consider renaming 'tempStruct' to 'sourceStruct' or a similarly descriptive name to clarify its role in holding the temporary binding results.
tempStruct := reflect.New(outElem.Type()).Interface()

@edvardsanta edvardsanta requested a review from gaby May 14, 2025 12:46
@ReneWerner87 ReneWerner87 merged commit 7182029 into gofiber:main May 14, 2025
16 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in v3 May 14, 2025
efectn pushed a commit to ckoch786/fiber that referenced this pull request May 15, 2025
* feat: Add All method to Bind

This commit introduces a new `All` method to the `Bind` struct, enabling the binding of request data from multiple sources (URI parameters, body, query parameters, headers, and cookies) into a single struct.

The `All` method iterates through the available binding sources, applying them in a predefined precedence order. It merges the values from each source into the output struct, only updating fields that are currently unset.

Changes:

- Added `All` method to `Bind` struct.
- Added `mergeStruct` helper function to merge struct values.
- Added `isZero` helper function to check if a value is zero.
- Added a test case for the `All` method in `bind_test.go` to validate its functionality.

* feat: Enhance Bind.All with comprehensive testing and configuration

The changes include:

- Added `RequestConfig` struct to encapsulate request configuration (ContentType, Body, Headers, Cookies, Query).
- Implemented `ApplyTo` method on `RequestConfig` to apply the configuration to the context.
- Created multiple test cases for `Bind.All` covering successful binding, missing fields, overriding query parameters, and form binding.
- Added a test case `Test_Bind_All_Uri_Precedence` to validate the precedence of URI parameters.
- Added benchmark test `BenchmarkBind_All` to measure the performance of the `Bind.All` method.
- Refactored the `TestBind_All` to use the new `RequestConfig` and assertion libraries.

* fix: Correct form binding in Test_Bind_All

* refactor: Improve Bind.All test and struct field ordering

- Reordered fields in `RequestConfig` and `User` structs for field alignment
- Updated `Test_Bind_All` to use `require.NoError` for more robust error checking.
- Corrected header key casing in `Test_Bind_All` to `X-User-Role` to match the struct tag.
- Added `t.Parallel()` to the test function to enable parallel test execution.

* feat: Document Bind.All function in API documentation

This commit adds documentation for the `Bind.All` function to the API documentation.

The documentation includes:

- A description of the function's purpose and precedence order for binding data from different sources (URI, body, query, headers, cookies).

* docs: lint Bind.All documentation

* fix: Update parameter tags from 'param' to 'uri' in bind_test.go

* fix: Update parameter tags from 'param' to 'uri' in bind.md

* test: Replace assert with require in bind_test.go

* feat: Add support for unified binding with defined precedence order in whats_new.md

---------

Co-authored-by: RW <[email protected]>
mdelapenya added a commit to mdelapenya/fiber that referenced this pull request May 19, 2025
* main:
  Update AGENTS.md
  Create AGENTS.md
  🐛 bug: fix redirection flash messages violate cookie structure (gofiber#3457)
  build(deps): bump codecov/codecov-action from 5.4.2 to 5.4.3
  🚀 Improve routing treeBuild flow (gofiber#3456)
  build(deps): bump github.com/tinylib/msgp from 1.2.5 to 1.3.0 (gofiber#3447)
  build(deps): bump DavidAnson/markdownlint-cli2-action from 19 to 20
  🔥 feat: Add All method to Bind (gofiber#3373)
  📝 docs: Document usage of Custom Tags in Logger middleware (gofiber#3446)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

Feature Proposal: Universal Request Binding with ctx.Bind().All()
4 participants