2

I'm trying to build a web service which would receive an HTTP PATCH request to update some fields in a "users" table (so I don't know how many nor which ones have to be updated).

I decided to work with Gin and because I'm working with Postgres, I'm using pgx.

The request...

PATCH {{protocol}}{{host}}/update-user/USER_ID_XXX HTTP/1.1
content-type: application/json
Authorization: Bearer : TOKEN_XXX

{
    "review_count": 2,
    "rating": 2.2,
}

... is handled by the Patch method

func (handler *userHandler) Patch(c *gin.Context) {
    reqBody := &users.User{}
    err := c.BindJSON(reqBody) <------ BREAKS
    if err != nil {
        c.JSON(http.StatusBadRequest, rest_errors.NewInternalServerError("JSON Binding Failed while trying to patch user", err))
        return
    }
    ...

The User struct makes uses of pgtypes. This is because, in the context of a GET request, if I retrieve a User from Postgres who has a review_count field set to null, i get an error when trying to marshal the result. So the pgtype.Int struct encapsulate the original value, a few other fields and contains a MarshalJSON() function to do the job properly ( see the MarshalJSON function here in pgtype.Int2 )

user_dto.go

type User struct {
    Id                string        `json:"id"`
    ...
    ReviewCount       pgtype.Int2   `json:"review_count"`
    Rating            float32       `json:"rating"`
    ...
}

Back to our PATCH request, the problem naturally comes in when I receive a field that is "pgtyped" like review_count .... Gin tries to unmarshal it and fails because it parses an int value and he's asked to put it into the pgtype.Int2 struct. So when I call err := c.BindJSON(reqBody) I get this error

"json: cannot unmarshal number into Go struct field User.ReviewCount of type pgtype.Int2"

I never had to implement this kind of feature before and I must confess that I know nothing about the "best options" if only I knew one that is working :D

Big_Boulard
  • 799
  • 1
  • 13
  • 28
  • 1
    While pgtype.Int2 does have a MarshalJSON method it's missing the corresponding UnmarshalJSON method. BindJSON does unmarshaling, not marshaling. That's why it doesn't know how to unmarshal `int` into `struct`. Some other pgtype int types (int4 & int8) do have UnmarshalJSON. Why int2 doesn't I can't tell. – mkopriva Apr 13 '22 at 18:48
  • Man, you're right! I didn't see it. Well, now I get my object. I'll post an issue in their Github repo just in case it's an oversight. – Big_Boulard Apr 13 '22 at 20:08
  • 1
    The unmarshall func has been added in the last commit https://github.com/jackc/pgtype/commit/25558de3bd1bd2441cd3442394502b567ea94fbe – Big_Boulard Apr 19 '22 at 07:58

0 Answers0