2

I have two simple api methods in my code. Method with endpoind /api/user/create creates user. Field username is unique. When i trying to create user with same username that already exists in database, i have an error in 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"

I want to show this error in response to user, or somehow identify type of error in my code, to show different error messages for user. I know only that if i have error user returns me id=0. But it doesnt seems like a good message for user.

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 with user struct:

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
}
2
  • 2
    Have you considered checking the error returned by Create? (e.g. result := GetDB().Create(user); if result.Error != nil {...) More info in the docs here and here. Commented Dec 23, 2020 at 19:34
  • @Brits thank you. Exactly what i looking for Commented Dec 23, 2020 at 19:45

2 Answers 2

1

As for pq v1.5.2 and gorm v1.9.12

First, you need to identify whether create method call returns error or not. Like so

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

Then the pq package has special type which maps to postgres server error. It contains fields which can help you to identify the error severity, it's code, table which related to error etc.

Full list of psql fields identifiers can be found here in

Error and Notice Message Fields

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

To resolve your issue as an option we can use field

Code

Which is a string type representation of error code. But firstly, we need to cast an error and check type cast was successful. Like so

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

    // code to handle specific error code
}

List of error codes can be found both in the official postgresql docs https://www.postgresql.org/docs/9.3/errcodes-appendix.html

And actual go pq specific mappings to the error in the github.com/lib/pq/error.go as for pq library

And finally we can handle error as duplicate by 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
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

As per the comments gorm provides access to database errors from the Create record function as follows:

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

Please note that checking the error string is likely to make your application database specific (but this may not be an issue for you). The answers to this question may provide further assistance.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.