Skip to content
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

Binding uuid.UUID using ShouldBind #2423

Open
VEDA-IT opened this issue Jul 2, 2020 · 6 comments
Open

Binding uuid.UUID using ShouldBind #2423

VEDA-IT opened this issue Jul 2, 2020 · 6 comments

Comments

@VEDA-IT
Copy link

VEDA-IT commented Jul 2, 2020

Description

Binding uuid.UUID using ShouldBind gives error ["45e1f85e-bca5-458d-bd9c-c56edd8f847b"] is not valid value for uuid.UUID

How to reproduce

Used Postman to make request:
Content-Type: multipart/form-data
Body with form-data:
key: colorID
value: 45e1f85e-bca5-458d-bd9c-c56edd8f847b

// Go model in which I want to map
type Test struct {
     colorID uuid.UUID `binding:"required" form:"colorID"`
}

func test(ctx *gin.Context) {
    t := Test{}
    err := ctx.ShouldBind(&t)
    if err != nil {
	panic(err)
    }
}

Actual result

["45e1f85e-bca5-458d-bd9c-c56edd8f847b"] is not valid value for uuid.UUID
@quentinvernot
Copy link

quentinvernot commented Aug 3, 2020

I have the same issue when attempting to bind with url-safe base64 values, I couldn't find a way to define a custom type handle the binding and error handling on its own and had to basically decode the string and handle the error in every handler. it's possible to use custom types when using json.Unmarshal, but, even though ShouldBind falls back to using enconding/json as well, the input value isn't json in those cases (it's a string for uuid.UUID and my case), and the binding fails.

Maybe TextUnmarshaler could be used as another fallback? uuid.UUID implements the UnmarshalText method, and it would be easy to do for custom types too.

It could be seen as API-breaking though, since TextUnmarshaler is a pretty common interface, people using ShouldBind to bind to structs with non-primitive fields may have surprises.

@vivl4725
Copy link

vivl4725 commented Aug 4, 2020

I have this problem too, but I found solution!

You can change uuid.UUID to string and place in binding uuid tag!

@damarowen
Copy link

If you use github.com/google/uuid package, you can use uuid.Parse

example:
_ID , err := uuid.Parse(dto.ID)
c, err := s.CampaignRepository.FindById(_ID)

reference :
https://stackoverflow.com/questions/62952279/how-to-convert-a-uuid-string-into-uuid-type

@hungtcs
Copy link

hungtcs commented Feb 20, 2023

+1. Any way to serialization and deserialization uri bindding or query bindding?

@AnatolyUA
Copy link

This function can be used to try to assign UUID to reflect.Value.

package binding

import (
	uuid "github.com/satori/go.uuid"
	"github.com/stretchr/testify/assert"
	"reflect"
	"testing"
)

func tryAssignUUID(s string, value reflect.Value) bool {
	l := len(s)
	if value.Kind() == reflect.Array &&
		value.Len() == 16 &&
		value.Index(0).Kind() == reflect.Uint8 &&
		(l == 32 || l == 36 || l == 38 || l == 41 || l == 45) {
		if uid, uErr := uuid.FromString(s); uErr == nil {
			value.Set(reflect.ValueOf(uid))
			return true
		}
	}
	return false
}

func Test_tryAssignUUID(t *testing.T) {
	mm := map[string][]string{
		"id":  []string{"df67786a-a543-4958-87ca-426954c626d5"},
		"ids": []string{"df67786a-a543-4958-87ca-426954c626d5", "68dc3815-6ab5-4883-81a1-96eff25b659f"},
	}
	type UUIDs struct {
		Id  uuid.UUID   `uri:"Id"`
		Ids []uuid.UUID `uri:"Ids"`
	}

	var received UUIDs
	if err := mapFormByTag(&received, mm, "uri"); err != nil {
		t.Error(err)
	}

	expected := UUIDs{
		Id: uuid.FromStringOrNil("df67786a-a543-4958-87ca-426954c626d5"),
		Ids: []uuid.UUID{
			uuid.FromStringOrNil("df67786a-a543-4958-87ca-426954c626d5"),
			uuid.FromStringOrNil("68dc3815-6ab5-4883-81a1-96eff25b659f"),
		},
	}

	assert.Equal(t, received, expected)
}

To make it work with arrays I added a case to setWithProperType like:

	case reflect.Array:
		if tryAssignUUID(val, value) {
			return nil
		}
		return errUnknownType

And modification for setByForm:

	case reflect.Array:
		if !ok {
			vs = []string{opt.defaultValue}
		}
		if len(vs) != value.Len() {
			if len(vs) == 1 && tryAssignUUID(vs[0], value) {
				return true, nil
			}
			return false, fmt.Errorf("%q is not valid value for %s", vs, value.Type().String())
		}
		return true, setArray(vs, value, field)

@AnatolyUA
Copy link

It would be preferable to merge #3045, though.

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

No branches or pull requests

6 participants