gin icon indicating copy to clipboard operation
gin copied to clipboard

feat(binding): add support for encoding.UnmarshalText in uri/query binding

Open takanuva15 opened this issue 7 months ago • 7 comments
trafficstars

With this PR, users can now specify parser=encoding.TextUnmarshaler in their form/uri tag to enable automatic binding using the encoding.TextUnmarshaler interface from the Golang standard library. Since this new parser tag is 100% opt-in only, this is fully backwards-compatible with previous versions of gin.

Merging this PR will resolve a number of tickets regarding this functionality:

  • https://github.com/gin-gonic/gin/issues/4177
  • https://github.com/gin-gonic/gin/pull/3933#issuecomment-2692206957
  • https://github.com/gin-gonic/gin/pull/3045

closes #4177


Sample code to run:

package main

import (
  "encoding"
  "strings"

  "github.com/gin-gonic/gin"
)

type Birthday string

func (b *Birthday) UnmarshalText(text []byte) error {
  *b = Birthday(strings.Replace(string(text), "-", "/", -1))
  return nil
}

var _ encoding.TextUnmarshaler = (*Birthday)(nil) //assert Birthday implements encoding.TextUnmarshaler

func main() {
  route := gin.Default()
  var request struct {
    Birthday         Birthday   `form:"birthday,parser=encoding.TextUnmarshaler"`
    Birthdays        []Birthday `form:"birthdays,parser=encoding.TextUnmarshaler" collection_format:"csv"`
    BirthdaysDefault []Birthday `form:"birthdaysDef,default=2020-09-01;2020-09-02,parser=encoding.TextUnmarshaler" collection_format:"csv"`
  }
  route.GET("/test", func(ctx *gin.Context) {
    _ = ctx.BindQuery(&request)
    ctx.JSON(200, request)
  })
  _ = route.Run(":8088")
}

Test it with:

curl 'localhost:8088/test?birthday=2000-01-01&birthdays=2000-01-01,2000-01-02'

Result

{"Birthday":"2000/01/01","Birthdays":["2000/01/01","2000/01/02"],"BirthdaysDefault":["2020/09/01","2020/09/02"]

takanuva15 avatar Mar 27 '25 18:03 takanuva15

Codecov Report

:white_check_mark: All modified and coverable lines are covered by tests. :white_check_mark: Project coverage is 98.82%. Comparing base (3dc1cd6) to head (8a07c82). :warning: Report is 187 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4203      +/-   ##
==========================================
- Coverage   99.21%   98.82%   -0.40%     
==========================================
  Files          42       44       +2     
  Lines        3182     3484     +302     
==========================================
+ Hits         3157     3443     +286     
- Misses         17       30      +13     
- Partials        8       11       +3     
Flag Coverage Δ
?
--ldflags="-checklinkname=0" -tags sonic 98.81% <100.00%> (?)
-tags go_json 98.75% <100.00%> (?)
-tags nomsgpack 98.80% <100.00%> (?)
go-1.18 ?
go-1.19 ?
go-1.20 ?
go-1.21 ?
go-1.24 98.82% <100.00%> (?)
go-1.25 98.82% <100.00%> (?)
macos-latest 98.82% <100.00%> (-0.40%) :arrow_down:
ubuntu-latest 98.82% <100.00%> (-0.40%) :arrow_down:

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

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

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

codecov[bot] avatar Mar 27 '25 18:03 codecov[bot]

@appleboy ready for review. I verified locally that all my new changes are covered with the new tests I added. The linting failure is unrelated to my changes since I did not add any sprintf calls to my code

takanuva15 avatar Apr 28 '25 21:04 takanuva15

Please rebase the master branch. @takanuva15

appleboy avatar May 21 '25 00:05 appleboy

@appleboy done, just rebased it now

takanuva15 avatar May 21 '25 02:05 takanuva15

I'm not sure why the coverage shows as dropped, but I just ran a full coverage report via

go test -cover -coverprofile=c.out ./... -coverpkg=./... \
      && go tool cover -html=c.out -o coverage.html

and it shows 100% coverage on form_mapping.go, which is the only file I modified.

image

takanuva15 avatar May 21 '25 13:05 takanuva15

@takanuva15 Please help to resolve the conflicts.

appleboy avatar May 27 '25 12:05 appleboy

@takanuva15 Please help to resolve the conflicts.

done

takanuva15 avatar May 27 '25 13:05 takanuva15

I will take it.

appleboy avatar Sep 23 '25 00:09 appleboy