ส่งคืนข้อผิดพลาด postgres ในการตอบสนอง api

Dec 24 2020

ฉันมีวิธี api ง่ายๆสองวิธีในโค้ดของฉัน วิธีที่มี endpoind /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

ขั้นแรกคุณต้องระบุว่าสร้างการเรียกใช้เมธอดส่งคืนข้อผิดพลาดหรือไม่ เช่นนั้น

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

และการแมปเฉพาะ 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ให้การเข้าถึงข้อผิดพลาดของฐานข้อมูลจากฟังก์ชันCreate recordดังต่อไปนี้:

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

โปรดทราบว่าการตรวจสอบสตริงข้อผิดพลาดมีแนวโน้มที่จะทำให้ฐานข้อมูลแอปพลิเคชันของคุณมีความเฉพาะเจาะจง (แต่นี่อาจไม่ใช่ปัญหาสำหรับคุณ) คำตอบสำหรับคำถามนี้อาจให้ความช่วยเหลือเพิ่มเติม