Возврат ошибок postgres в ответ API

Dec 24 2020

В моем коде есть два простых метода api. Метод с конечной точкой /api/user/createсоздает пользователя. Поле usernameуникальное. Когда я пытаюсь создать пользователя с таким же именем пользователя, которое уже существует в базе данных, у меня появляется ошибка в консоли:

(/home/andrej/go/src/go_contacts/models/users.go:19) 
[2020-12-23 22:03:10]  pq: duplicate key value violates unique constraint "users_username_key"

Я хочу показать эту ошибку в ответ пользователю или как-то определить тип ошибки в моем коде, чтобы отображать различные сообщения об ошибках для пользователя. Я знаю только, что если у меня есть ошибка, userмне возвращается id = 0. Но это не похоже на хорошее сообщение для пользователя.

main.go

package main

import (
    "fmt"
    "go_contacts/controllers"
    "net/http"
    "os"

    "github.com/gorilla/mux"
    "github.com/joho/godotenv"
)

func main() {
    godotenv.Load(".env")


    router := mux.NewRouter()
    router.HandleFunc("/", controllers.ReturnHello).Methods("GET")
    router.HandleFunc("/api/user/create", controllers.CreateUser).Methods("POST")

    port := os.Getenv("PORT")
    if port == "" {
        port = "8000"
    }

    err := http.ListenAndServe(":"+port, router)
    if err != nil {
        fmt.Print(err)
    }
}

models.go со структурой пользователя:

package models

import (
    u "go_contacts/utils"

    "github.com/jinzhu/gorm"
)

// User base model
type User struct {
    gorm.Model
    Username string `json:"username" gorm:"unique"`
    Password string `json:"password"`
    Email    string `json:"email"`
}

// Create new user
func (user *User) Create() map[string]interface{} {
    GetDB().Create(user)

    if user.ID <= 0 {
        return u.Message(false, "Failed to create user, connection error.")
    }

    response := u.Message(true, "Account has been created")
    response["user"] = user
    return response
}

Ответы

1 AlekseySpirin Dec 24 2020 at 17:04

Что касается pq v1.5.2 и gorm v1.9.12

Во-первых, вам нужно определить, возвращает ли вызов метода create ошибку или нет. Вот так

err := GetDB().Create(user).Error
if err != nil {
    // code to handle error
}

Тогда пакет pq имеет специальный тип, который соответствует ошибке сервера postgres. Он содержит поля, которые могут помочь вам определить серьезность ошибки, ее код, таблицу, относящуюся к ошибке и т. Д.

Полный список идентификаторов полей psql можно найти здесь, в

Поля сообщений об ошибках и уведомлений

https://www.postgresql.org/docs/current/protocol-error-fields.html

Чтобы решить вашу проблему, мы можем использовать поле

Code

Это строковое представление кода ошибки. Но во-первых, нам нужно выдать ошибку и проверить, что приведение типа прошло успешно. Вот так

err := GetDB().Create(user).Error
if err != nil {
    pqErr, ok := err.(pq.Error)
    if !ok {
        log.Fatal(err)
    }

    // code to handle specific error code
}

Список кодов ошибок можно найти как в официальных документах postgresql. https://www.postgresql.org/docs/9.3/errcodes-appendix.html

И фактические сопоставления go pq с ошибкой в ​​github.com/lib/pq/error.go как для библиотеки pq

И, наконец, мы можем обрабатывать ошибку как дубликат по коду

err := GetDB().Create(user).Error
if err != nil {
    pqErr, ok := err.(pq.Error)
    if !ok {
        log.Fatal(err)
    }

    // note that type casting here is redundant and used for showing specific 
    // string type from pq library
    if pqErr.Code == pq.ErrorCode("23505") { // 23505 is unique_violation error code for psql
        // now you can create error and write it to a message to return it for 
        // a client
    }
}
1 Brits Dec 24 2020 at 02:59

Согласно комментариям, gorm предоставляет доступ к ошибкам базы данных из функции создания записи следующим образом:

result := GetDB().Create(user)
if result.Error != nil {
   // Do something with the error
}

Обратите внимание, что проверка строки ошибки может сделать базу данных вашего приложения специфичной (но это может не быть проблемой для вас). Ответы на этот вопрос могут оказать дополнительную помощь.