Devolver errores de postgres en la respuesta de la API
Tengo dos métodos api simples en mi código. El método con endpoind /api/user/create
crea usuario. El campo username
es único. Cuando intento crear un usuario con el mismo nombre de usuario que ya existe en la base de datos, tengo un error en la consola:
(/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"
Quiero mostrar este error en respuesta al usuario, o identificar de alguna manera el tipo de error en mi código, para mostrar diferentes mensajes de error para el usuario. Solo sé que si tengo un error, user
me devuelve id = 0. Pero no parece un buen mensaje para el usuario.
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
con estructura de usuario:
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
}
Respuestas
En cuanto a pq v1.5.2 y gorm v1.9.12
Primero, debe identificar si la llamada al método de creación devuelve un error o no. Al igual que
err := GetDB().Create(user).Error
if err != nil {
// code to handle error
}
Luego, el paquete pq tiene un tipo especial que se asigna al error del servidor de Postgres. Contiene campos que pueden ayudarlo a identificar la gravedad del error, su código, tabla relacionada con el error, etc.
La lista completa de identificadores de campos psql se puede encontrar aquí en
Campos de mensaje de error y aviso
https://www.postgresql.org/docs/current/protocol-error-fields.html
Para resolver su problema como una opción, podemos usar el campo
Code
Que es una representación de tipo cadena del código de error. Pero, en primer lugar, necesitamos emitir un error y comprobar que el tipo de conversión se realizó correctamente. Al igual que
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 lista de códigos de error se puede encontrar tanto en los documentos oficiales de postgresql https://www.postgresql.org/docs/9.3/errcodes-appendix.html
Y asignaciones específicas de go pq al error en github.com/lib/pq/error.go como para la biblioteca pq
Y finalmente podemos manejar el error como duplicado por código.
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
}
}
Según los comentarios, gorm proporciona acceso a los errores de la base de datos desde la función Crear registro de la siguiente manera:
result := GetDB().Create(user)
if result.Error != nil {
// Do something with the error
}
Tenga en cuenta que es probable que la comprobación de la cadena de error haga que la base de datos de su aplicación sea específica (pero es posible que esto no sea un problema para usted). Las respuestas a esta pregunta pueden proporcionar más ayuda.