Repository: deepmap/oapi-codegen
Pull request #556 (2022-04-21 20:18:20)

Swap UUID format to byte array
With #546 merged in, UUIDs are defined as an alias for a string.

Before that implementation gets mass adoption, I wanted to propose a
slightly different alternative: basing the custom type off of
`uuid.UUID` over `string`.

This has the advantages of:
- Being convertable back to a `uuid.UUID` without having to parse the
  string a second time, or opening the conversion up to failure
  scenarios
- Still being easily convertable to `string` with the `uuid.UUID`'s
  `String` method
- Taking up less space in memory
- Reducing the number of invalid representations, since only `[16]byte`s
  can be represented, as opposed to all strings
- Not adding any dependencies, since `uuid.UUID` is already being
  imported

alexdulin: @deepmap-marcinr any possibility of a review on this? This would substantially lessen the burden on users to need to implement custom methids for marshaling/unmarshaling actual UUID types and greatly improve the usability of this project.

Patch:
diff --git a/pkg/types/uuid.go b/pkg/types/uuid.go
index a4fb36d..50515d8 100644
--- a/pkg/types/uuid.go
+++ b/pkg/types/uuid.go
@@ -7,13 +7,10 @@ import (
 	"github.com/google/uuid"
 )
 
-type UUID string
+type UUID uuid.UUID
 
 func (u UUID) MarshalJSON() ([]byte, error) {
-	if _, err := uuid.Parse(string(u)); err != nil {
-		return nil, errors.New("uuid: failed to pass validation")
-	}
-	return json.Marshal(string(u))
+	return json.Marshal(uuid.UUID(u).String())
 }
 
 func (u *UUID) UnmarshalJSON(data []byte) error {
@@ -21,9 +18,10 @@ func (u *UUID) UnmarshalJSON(data []byte) error {
 	if err := json.Unmarshal(data, &s); err != nil {
 		return err
 	}
-	if _, err := uuid.Parse(s); err != nil {
+	parsed, err := uuid.Parse(s)
+	if err != nil {
 		return errors.New("uuid: failed to pass validation")
 	}
-	*u = UUID(s)
+	*u = UUID(parsed)
 	return nil
 }


Test patch:
diff --git a/pkg/types/uuid_test.go b/pkg/types/uuid_test.go
index 7f19aaa..4ac689a 100644
--- a/pkg/types/uuid_test.go
+++ b/pkg/types/uuid_test.go
@@ -4,22 +4,24 @@ import (
 	"encoding/json"
 	"testing"
 
+	"github.com/google/uuid"
 	"github.com/stretchr/testify/assert"
 )
 
-func TestUUID_MarshalJSON_Fail(t *testing.T) {
-	testUUID := "this-is-not-a-uuid"
+func TestUUID_MarshalJSON_Zero(t *testing.T) {
+	var testUUID UUID
 	b := struct {
 		UUIDField UUID `json:"uuid"`
 	}{
-		UUIDField: UUID(testUUID),
+		UUIDField: testUUID,
 	}
-	_, err := json.Marshal(b)
-	assert.Error(t, err)
+	marshaled, err := json.Marshal(b)
+	assert.NoError(t, err)
+	assert.JSONEq(t, `{"uuid":"00000000-0000-0000-0000-000000000000"}`, string(marshaled))
 }
 
 func TestUUID_MarshalJSON_Pass(t *testing.T) {
-	testUUID := "9cb14230-b640-11ec-b909-0242ac120002"
+	testUUID := uuid.MustParse("9cb14230-b640-11ec-b909-0242ac120002")
 	b := struct {
 		UUIDField UUID `json:"uuid"`
 	}{
@@ -40,7 +42,7 @@ func TestUUID_UnmarshalJSON_Fail(t *testing.T) {
 }
 
 func TestUUID_UnmarshalJSON_Pass(t *testing.T) {
-	testUUID := UUID("9cb14230-b640-11ec-b909-0242ac120002")
+	testUUID := UUID(uuid.MustParse("9cb14230-b640-11ec-b909-0242ac120002"))
 	jsonStr := `{"uuid":"9cb14230-b640-11ec-b909-0242ac120002"}`
 	b := struct {
 		UUIDField UUID `json:"uuid"`