🔥 Feature: Enhance CheckConstraint method for improved error handling (#3356)

* 🔥 Feature: Enhance CheckConstraint method for improved error handling

* Revert "🔥 Feature: Enhance CheckConstraint method for improved error handling"

This reverts commit 68e8777b4c.

* Reapply "🔥 Feature: Enhance CheckConstraint method for improved error handling"

This reverts commit 9e6c8e68df.

* 🚨 Test: Add comprehensive tests for CheckConstraint method with various constraint scenarios

* 🩹 Fix: lint error

* 🩹 Fix: Update CheckConstraint method to return true for noConstraint and improve error handling

* ♻️ Refactor: Remove unused CheckConstraint test cases and reorganize benchmark test cases for clarity

* ♻️ Refactor: Remove outdated test cases from path_testcases_test.go and clean up CheckConstraint method in path.go

* 📚 Doc: Update custom constraints section to clarify overriding behavior

* 🔥 Feature: Enhance CheckConstraint method for improved error handling

* Revert "🔥 Feature: Enhance CheckConstraint method for improved error handling"

This reverts commit 68e8777b4c.

* Reapply "🔥 Feature: Enhance CheckConstraint method for improved error handling"

This reverts commit 9e6c8e68df.

* 🚨 Test: Add comprehensive tests for CheckConstraint method with various constraint scenarios

* 🩹 Fix: lint error

* 🩹 Fix: Update CheckConstraint method to return true for noConstraint and improve error handling

* ♻️ Refactor: Remove unused CheckConstraint test cases and reorganize benchmark test cases for clarity

* ♻️ Refactor: Remove outdated test cases from path_testcases_test.go and clean up CheckConstraint method in path.go

* 📚 Doc: Update custom constraints section to clarify overriding behavior

* 📚 Doc: Add caution note about custom constraints overriding built-in constraints in routing guide

---------

Co-authored-by: Juan Calderon-Perez <835733+gaby@users.noreply.github.com>
Co-authored-by: RW <rene@gofiber.io>
docs-emoji
JIeJaitt 2025-04-01 14:48:19 +08:00 committed by GitHub
parent bb12633c8b
commit c5c7f86d85
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 39 additions and 12 deletions

View File

@ -250,6 +250,10 @@ app.Get("/:test<int>?", func(c fiber.Ctx) error {
Custom constraints can be added to Fiber using the `app.RegisterCustomConstraint` method. Your constraints have to be compatible with the `CustomConstraint` interface.
:::caution
Attention, custom constraints can now override built-in constraints. If a custom constraint has the same name as a built-in constraint, the custom constraint will be used instead. This allows for more flexibility in defining route parameter constraints.
:::
It is a good idea to add external constraints to your project once you want to add more specific rules to your routes.
For example, you can add a constraint to check if a parameter is a valid ULID.

39
path.go
View File

@ -672,12 +672,25 @@ func getParamConstraintType(constraintPart string) TypeConstraint {
}
}
//nolint:errcheck // TODO: Properly check _all_ errors in here, log them & immediately return
// CheckConstraint validates if a param matches the given constraint
// Returns true if the param passes the constraint check, false otherwise
//
//nolint:errcheck // TODO: Properly check _all_ errors in here, log them or immediately return
func (c *Constraint) CheckConstraint(param string) bool {
var err error
var num int
// First check if there's a custom constraint with the same name
// This allows custom constraints to override built-in constraints
for _, cc := range c.customConstraints {
if cc.Name() == c.Name {
return cc.Execute(param, c.Data...)
}
}
// check data exists
var (
err error
num int
)
// Validate constraint has required data
needOneData := []TypeConstraint{minLenConstraint, maxLenConstraint, lenConstraint, minConstraint, maxConstraint, datetimeConstraint, regexConstraint}
needTwoData := []TypeConstraint{betweenLenConstraint, rangeConstraint}
@ -696,11 +709,7 @@ func (c *Constraint) CheckConstraint(param string) bool {
// check constraints
switch c.ID {
case noConstraint:
for _, cc := range c.customConstraints {
if cc.Name() == c.Name {
return cc.Execute(param, c.Data...)
}
}
return true
case intConstraint:
_, err = strconv.Atoi(param)
case boolConstraint:
@ -744,14 +753,14 @@ func (c *Constraint) CheckConstraint(param string) bool {
data, _ := strconv.Atoi(c.Data[0])
num, err = strconv.Atoi(param)
if num < data {
if err != nil || num < data {
return false
}
case maxConstraint:
data, _ := strconv.Atoi(c.Data[0])
num, err = strconv.Atoi(param)
if num > data {
if err != nil || num > data {
return false
}
case rangeConstraint:
@ -759,12 +768,18 @@ func (c *Constraint) CheckConstraint(param string) bool {
data2, _ := strconv.Atoi(c.Data[1])
num, err = strconv.Atoi(param)
if num < data || num > data2 {
if err != nil || num < data || num > data2 {
return false
}
case datetimeConstraint:
_, err = time.Parse(c.Data[0], param)
if err != nil {
return false
}
case regexConstraint:
if c.RegexCompiler == nil {
return false
}
if match := c.RegexCompiler.MatchString(param); !match {
return false
}

View File

@ -713,6 +713,14 @@ func init() {
{url: "/api/v1/", params: []string{""}, match: true},
},
},
// Add test case for RegexCompiler == nil
{
pattern: "/api/v1/:param<regex(\\d+)>",
testCases: []routeTestCase{
{url: "/api/v1/123", params: []string{"123"}, match: true},
{url: "/api/v1/abc", params: nil, match: false},
},
},
}...,
)
}