For information about how to interpret errors from github.com/lib/pq, see http://godoc.org/github.com/lib/pq#Error.
Here is what I do:
// ShowError sends an appropriate error message.
func ShowError(w http.ResponseWriter, r *http.Request, err error) {
switch e := err.(type) {
case *pq.Error:
switch e.Code {
case "23502":
// not-null constraint violation
http.Error(w, fmt.Sprint("Some required data was left out:
", e.Message), http.StatusForbidden)
return
case "23503":
// foreign key violation
switch r.Method {
case "DELETE":
http.Error(w, fmt.Sprint("This record can’t be deleted because another record refers to it:
", e.Detail), http.StatusForbidden)
return
}
case "23505":
// unique constraint violation
http.Error(w, fmt.Sprint("This record contains duplicated data that conflicts with what is already in the database:
", e.Detail), http.StatusForbidden)
return
case "23514":
// check constraint violation
http.Error(w, fmt.Sprint("This record contains inconsistent or out-of-range data:
", e.Message), http.StatusForbidden)
return
default:
msg := e.Message
if d := e.Detail; d != "" {
msg += "
" + d
}
if h := e.Hint; h != "" {
msg += "
" + h
}
http.Error(w, msg, http.StatusInternalServerError)
return
}
case *strconv.NumError:
http.Error(w, fmt.Sprintf(`"%s" is not a valid number.`, e.Num), http.StatusBadRequest)
return
default:
switch err {
case sql.ErrNoRows:
http.NotFound(w, r)
return
}
}
http.Error(w, err.Error(), http.StatusInternalServerError)
}