Repository: gin-gonic/gin
Pull request #4047 (2024-09-03 01:14:45)

fix: Set default value for form fields
- Use provided default value in struct tags when binding a request input to struct for validation.

Fixes: How to apply default value if empty value provided by client during model binding? #4042, #13042df, #a41721a

- With pull requests:
  - Open your pull request against `master`
  - Your pull request should have no more than two commits, if not you should squash them.
  - It should pass all tests in the available continuous integration systems such as GitHub Actions.
  - You should add/modify tests to cover your proposed code changes.
  - If your pull request contains a new feature, please document it on the README.



ahmadSaeedGoda: @thinkerou @appleboy Kindly review the tiny portion, highly appreciated! :cool: 
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/gin-gonic/gin/pull/4047?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 98.85%. Comparing base [(`3dc1cd6`)](https://app.codecov.io/gh/gin-gonic/gin/commit/3dc1cd6572b4e3a0cd170a15debe546c2c72294f?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) to head [(`497351c`)](https://app.codecov.io/gh/gin-gonic/gin/commit/497351c8dd88f69a8f67381ba0e63b5ef7d49728?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic).
> Report is 68 commits behind head on master.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master    #4047      +/-   ##
==========================================
- Coverage   99.21%   98.85%   -0.36%     
==========================================
  Files          42       44       +2     
  Lines        3182     2801     -381     
==========================================
- Hits         3157     2769     -388     
- Misses         17       19       +2     
- Partials        8       13       +5     
```

| [Flag](https://app.codecov.io/gh/gin-gonic/gin/pull/4047/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | Coverage Δ | |
|---|---|---|
| [](https://app.codecov.io/gh/gin-gonic/gin/pull/4047/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `?` | |
| [-tags "sonic avx"](https://app.codecov.io/gh/gin-gonic/gin/pull/4047/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `98.84% <100.00%> (?)` | |
| [-tags go_json](https://app.codecov.io/gh/gin-gonic/gin/pull/4047/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `98.84% <100.00%> (?)` | |
| [-tags nomsgpack](https://app.codecov.io/gh/gin-gonic/gin/pull/4047/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `98.83% <100.00%> (?)` | |
| [go-1.18](https://app.codecov.io/gh/gin-gonic/gin/pull/4047/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `?` | |
| [go-1.19](https://app.codecov.io/gh/gin-gonic/gin/pull/4047/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `?` | |
| [go-1.20](https://app.codecov.io/gh/gin-gonic/gin/pull/4047/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `?` | |
| [go-1.21](https://app.codecov.io/gh/gin-gonic/gin/pull/4047/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `98.85% <100.00%> (-0.36%)` | :arrow_down: |
| [go-1.22](https://app.codecov.io/gh/gin-gonic/gin/pull/4047/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `98.85% <100.00%> (?)` | |
| [macos-latest](https://app.codecov.io/gh/gin-gonic/gin/pull/4047/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `98.85% <100.00%> (-0.36%)` | :arrow_down: |
| [ubuntu-latest](https://app.codecov.io/gh/gin-gonic/gin/pull/4047/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | `98.85% <100.00%> (-0.36%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic#carryforward-flags-in-the-pull-request-comment) to find out more.

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/gin-gonic/gin/pull/4047?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic).


Patch:
diff --git a/binding/form_mapping.go b/binding/form_mapping.go
index 4a35866..a84536f 100644
--- a/binding/form_mapping.go
+++ b/binding/form_mapping.go
@@ -261,6 +261,9 @@ func setByForm(value reflect.Value, field reflect.StructField, form map[string][
 
 		if len(vs) > 0 {
 			val = vs[0]
+			if val == "" {
+				val = opt.defaultValue
+			}
 		}
 		if ok, err := trySetCustom(val, value); ok {
 			return ok, err


Test patch:
diff --git a/binding/form_mapping_test.go b/binding/form_mapping_test.go
index c6db033..8cf7465 100644
--- a/binding/form_mapping_test.go
+++ b/binding/form_mapping_test.go
@@ -69,6 +69,7 @@ func TestMappingBaseTypes(t *testing.T) {
 
 func TestMappingDefault(t *testing.T) {
 	var s struct {
+		Str   string `form:",default=defaultVal"`
 		Int   int    `form:",default=9"`
 		Slice []int  `form:",default=9"`
 		Array [1]int `form:",default=9"`
@@ -76,6 +77,7 @@ func TestMappingDefault(t *testing.T) {
 	err := mappingByPtr(&s, formSource{}, "form")
 	require.NoError(t, err)
 
+	assert.Equal(t, "defaultVal", s.Str)
 	assert.Equal(t, 9, s.Int)
 	assert.Equal(t, []int{9}, s.Slice)
 	assert.Equal(t, [1]int{9}, s.Array)
@@ -152,6 +154,24 @@ func TestMappingForm(t *testing.T) {
 	assert.Equal(t, 6, s.F)
 }
 
+func TestMappingFormFieldNotSent(t *testing.T) {
+	var s struct {
+		F string `form:"field,default=defVal"`
+	}
+	err := mapForm(&s, map[string][]string{})
+	require.NoError(t, err)
+	assert.Equal(t, "defVal", s.F)
+}
+
+func TestMappingFormWithEmptyToDefault(t *testing.T) {
+	var s struct {
+		F string `form:"field,default=DefVal"`
+	}
+	err := mapForm(&s, map[string][]string{"field": {""}})
+	require.NoError(t, err)
+	assert.Equal(t, "DefVal", s.F)
+}
+
 func TestMapFormWithTag(t *testing.T) {
 	var s struct {
 		F int `externalTag:"field"`