Retourne des erreurs postgres dans la réponse de l'API

Dec 24 2020

J'ai deux méthodes API simples dans mon code. La méthode avec endpoind /api/user/createcrée l'utilisateur. Le champ usernameest unique. Lorsque j'essaie de créer un utilisateur avec le même nom d'utilisateur qui existe déjà dans la base de données, j'ai une erreur dans la console:

(/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"

Je veux afficher cette erreur en réponse à l'utilisateur, ou identifier en quelque sorte le type d'erreur dans mon code, pour afficher différents messages d'erreur pour l'utilisateur. Je sais seulement que si j'ai une erreur userme renvoie id = 0. Mais cela ne semble pas être un bon message pour l'utilisateur.

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 avec la structure de l'utilisateur:

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
}

Réponses

1 AlekseySpirin Dec 24 2020 at 17:04

Comme pour pq v1.5.2 et gorm v1.9.12

Tout d'abord, vous devez identifier si l'appel de méthode de création renvoie une erreur ou non. Ainsi

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

Ensuite, le package pq a un type spécial qui correspond à une erreur de serveur postgres. Il contient des champs qui peuvent vous aider à identifier la gravité de l'erreur, son code, la table liée à l'erreur, etc.

La liste complète des identificateurs de champs psql peut être trouvée ici dans

Champs de message d'erreur et d'avis

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

Pour résoudre votre problème en option, nous pouvons utiliser le champ

Code

Qui est une représentation de type chaîne du code d'erreur. Mais tout d'abord, nous devons convertir une erreur et vérifier que la conversion du type a réussi. Ainsi

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

    // code to handle specific error code
}

La liste des codes d'erreur peut être trouvée à la fois dans la documentation officielle de PostgreSQL https://www.postgresql.org/docs/9.3/errcodes-appendix.html

Et les mappages spécifiques de go pq à l'erreur dans github.com/lib/pq/error.go comme pour la bibliothèque pq

Et enfin, nous pouvons gérer l'erreur comme une duplication par code

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

Selon les commentaires, gorm permet d'accéder aux erreurs de base de données à partir de la fonction Créer un enregistrement comme suit:

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

Veuillez noter que la vérification de la chaîne d'erreur est susceptible de rendre votre base de données d'application spécifique (mais cela peut ne pas être un problème pour vous). Les réponses à cette question peuvent apporter une aide supplémentaire.