google / uuid

Go package for UUIDs based on RFC 4122 and DCE 1.1: Authentication and Security Services.
BSD 3-Clause "New" or "Revised" License
5.16k stars 362 forks source link

Should uuid.Nil marshal to null instead of all zeroes #119

Closed maroux closed 4 weeks ago

maroux commented 11 months ago

The library uses the uuid.Nil value as an empty value. This suggests to me that Nil value is treated as a special value, which is in line with the RFC. However, the behavior of this value when marshaling to json is questionable. The library serializes to 00000000-0000-0000-0000-000000000000 (play) instead of null. Should this behavior be changed? Marshaling to text can probably yield an error, or just empty string, not sure.

petkostas commented 8 months ago

I ran into some problems while using UUID with the echo framework, which caused me a lot of inconvenience. I would be grateful if there is a solution available for this issue. Moreover, this problem results in an extra burden of validations that need to be implemented.

TestResultDTO struct {
    ConsumerId uuid.UUID `json:"consumer_id,omitempty"`
}
func (h *Handler) TestRun(c echo.Context) error {
    var testResultDTO models.TestResultDTO
    err := c.Bind(&testResultDTO)
    if err != nil {
        return err
    }
    jsonString, err := json.Marshal(testResultDTO)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(jsonString))
    return c.JSON(http.StatusCreated, testResultDTO)
}

Sending a POST request to the test endpoint:

curl --request POST \
  --url http://localhost:xxxx/test \
  --header 'Content-Type: application/json' \
  --header 'User-Agent: foo' \
  --data '{}'
{
    "consumer_id": "00000000-0000-0000-0000-000000000000"
}

Which in this case is undesirable.

I attempted the following method, but it did not properly evaluate and had issues with structures that produce new UUIDs.

TestResultDTO struct {
    ConsumerId uuid.NullUUID `json:"consumer_id,omitempty"`
}

Outcome from the same endpoint:

{
    "consumer_id": null
}

There needs to be a solution that is more compliant with other libraries. Especially when you need to perform the following in order to reduce overhead:

ProviderId         uuid.NullUUID  `json:"provider_id,omitempty" validate:"required_without=ConsumerId,uuid"`
ConsumerId      uuid.NullUUID  `json:"consumer_id,omitempty" validate:"required_without=ProviderId,uuid"`
tyliec commented 4 months ago

Following up on this, but did you ever find a solution?

Personally was expecting omitempty to result in nothing, rather than a bunch of 00000000-0000-0000-0000-000000000000s

mazar commented 3 months ago

I'm interested in a solution for this as well.

Mirko607 commented 1 month ago

Who else would like to marshal uuid.Nil to json null? Give a 👍

pborman commented 4 weeks ago

What you want is uuid.NullUUID which is like a UUID but it can be null (at the cost of additional data).

uuid.Nil has a specific definition and it is not null. From RFC 4122:

[4.1.7]  Nil UUID

   The nil UUID is special form of UUID that is specified to have all
   128 bits set to zero. 

I am going to close this issue since uuid.NullUUID has the behavior you want.