如何在Golang应用程序中正确使用UUID4?

时间:2019-02-28 19:06:22

标签: go

我是Golang的新手,需要帮助!我有几个问题。

PostgreSQL数据库中,我有一个名为surveys的表。

CREATE TABLE SURVEYS(
  SURVEY_ID UUID PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
  SURVEY_NAME VARCHAR NOT NULL,
  SURVEY_DESCRIPTION TEXT,
  START_PERIOD TIMESTAMP,
  END_PERIOD TIMESTAMP
);

您会看到SURVEY_ID列为PRIMARY KEY,其类型为UUID4

Golang应用程序中,我为此表创建了struct

type Survey struct {
    ID string `json:"survey_id"`
    Name string `json:"survey_name"`
    Description utils.NullString `json:"survey_description"`
    StartPeriod utils.NullTime `json:"start_period"`
    EndPeriod utils.NullTime `json:"end_period"`
}

您会看到ID字段的类型为string。这是对的吗?我不确定这是最佳做法。

我的第二个问题是当我通过其ID向GET要求进行特定调查时遇到奇怪的结果。

例如,当我发出这样的请求时:

http://localhost:8000/api/survey/0cf1cf18-d5fd-474e-a8be-754fbdc89720

作为回应,我有这个:

{
    "survey_id": "0cf1cf18-d5fd-474e-a8be-754fbdc89720",
    "survey_name": "NAME",
    "survey_description": {
        "String": "DESCRIPTION",
        "Valid": true
    },
    "start_period": {
        "Time": "2019-01-01T00:00:00Z",
        "Valid": false
    },
    "end_period": {
        "Time": "0001-01-01T00:00:00Z",
        "Valid": false
    }
}

您会发现最后3个字段有问题:survey_descriptionstart_periodend_period。我想在一行中看到键和值。例如此处:

{
    "survey_id": "0cf1cf18-d5fd-474e-a8be-754fbdc89720",
    "survey_name": "NAME",
    "survey_description": "DESCRIPTION",
    "start_period": "2019-01-01 00:00:00",
    "end_period": null
}

我的代码到底在哪里出错?

utils.go:

package utils

import (
    "database/sql"
    "encoding/json"
    "fmt"
    "github.com/lib/pq"
    "time"
)

// NullTime is an alias for pq.NullTime data type.
type NullTime struct {
    pq.NullTime
}

// MarshalJSON for NullTime.
func (nt *NullTime) MarshalJSON() ([]byte, error) {
    if !nt.Valid {
        return []byte("null"), nil
    }
    val := fmt.Sprintf("\"%s\"", nt.Time.Format(time.RFC3339))
    return []byte(val), nil
}

// UnmarshalJSON for NullTime.
func (nt *NullTime) UnmarshalJSON(b []byte) error {
    err := json.Unmarshal(b, &nt.Time)
    nt.Valid = err == nil
    return err
}

// NullInt64 is an alias for sql.NullInt64 data type.
type NullInt64 struct {
    sql.NullInt64
}

// MarshalJSON for NullInt64.
func (ni *NullInt64) MarshalJSON() ([]byte, error) {
    if !ni.Valid {
        return []byte("null"), nil
    }
    return json.Marshal(ni.Int64)
}

// UnmarshalJSON for NullInt64.
func (ni *NullInt64) UnmarshalJSON(b []byte) error {
    err := json.Unmarshal(b, &ni.Int64)
    ni.Valid = err == nil
    return err
}

// NullString is an alias for sql.NullString data type.
type NullString struct {
    sql.NullString
}

// MarshalJSON for NullString.
func (ns *NullString) MarshalJSON() ([]byte, error) {
    if !ns.Valid {
        return []byte("null"), nil
    }
    return json.Marshal(ns.String)
}

// UnmarshalJSON for NullString.
func (ns *NullString) UnmarshalJSON(b []byte) error {
    err := json.Unmarshal(b, &ns.String)
    ns.Valid = err == nil
    return err
}

routes.go:

router.HandleFunc("/api/survey/{survey_id:[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}}", controllers.GetSurvey).Methods("GET")

controllers / survey.go:

var GetSurvey = func(responseWriter http.ResponseWriter, request *http.Request) {
    // Initialize variables.
    survey := models.Survey{}
    var err error

    vars := mux.Vars(request)

    // Execute SQL statement.
    err = database.DB.QueryRow("SELECT * FROM surveys WHERE survey_id = $1;", vars["survey_id"]).Scan(&survey.ID, &survey.Name, &survey.Description, &survey.StartPeriod, &survey.EndPeriod)

    // Shape the response depending on the result of the previous command.
    if err != nil {
        log.Println(err)
        switch err {
        case sql.ErrNoRows:
            utils.ResponseWithError(responseWriter, http.StatusNotFound, "The entry not found.")
        default:
            utils.ResponseWithError(responseWriter, http.StatusInternalServerError, err.Error())
        }
        return
    }
    utils.Response(responseWriter, http.StatusOK, survey)
}

2 个答案:

答案 0 :(得分:1)

好吧,我终于找到了结果。

我更改了表的结构:

type Survey struct {
    ID string `json:"survey_id"`
    Name string `json:"survey_name"`
    Description *string `json:"survey_description", sql:"index"`
    StartPeriod *time.Time `json:"start_period", sql:"index"`
    EndPeriod *time.Time `json:"end_period", sql:"index"`
}

答案 1 :(得分:0)

使用string作为UUID时没有任何问题。

对于MarshalJSON无法正常工作,我想我知道发生了什么事。您的null类型不实现MarshalJSON,仅实现指向它们的指针。解决方法是要么更改功能以使用非指针接收器,要么使结构中的字段成为指针。

func (ns *NullString) MarshalJSON() ([]byte, error)

如果确实为它们提供了指针,则可以将它们保持为空,因为它们可以为空。