2

I'm trying to code some simple CRUD focused in employees management, but in this point I'm a little confused so how I should to use struct attributes json:... and gorm: for declaring specific data types and constraints to the new database table and specific values sended in json format from Postman. Are you working with Go-Gorm?

//db file
package tiposDocumentos

import (
    "bitbucket.org/username/repositoryname/db"
    "bitbucket.org/username/repositoryname/models"
)

// Inserta un nuevo tipo de documento en la base de datos.
func InsertTipoDocumento(tp models.TiposDocumentos) (bool, error) {
    db.PsqlDb.AutoMigrate(&tp)
    if db.PsqlDb.NewRecord(tp) {
        err := db.PsqlDb.Create(&tp)
        if err != nil {
            return false, nil
        }
    } else {
        return false, errors.New("clave primaria se encuentra en uso")
    }

    return true, nil
}
package models
    
type TiposDocumentos struct {
        TdoCodigo       string  `json:"tdo_codigo" gorm:"column:tdo_codigo;type:varchar(3);PRIMARY_KEY;AUTO_INCREMENT:false"`
        TdoDescripcion  string  `json:"tdo_descripcion" gorm:"column:tdo_descripcion;type:varchar(50)"`
        TdoCodigoAfip   string  `json:"tdo_codigo_afip" gorm:"column:tdo_codigo_afip;type:varchar(10)"`
}
package routers

import (
    "bitbucket.org/username/repositoryname/db/tiposDocumentos"
    "bitbucket.org/username/repositoryname/models"
    "encoding/json"
    "fmt"
    "net/http"
)

var (
    tp models.TiposDocumentos
)

// Valida registro recibido y lo inserta en la base de datos.
func PostTiposDocuemntos(w http.ResponseWriter, r *http.Request) {
    err := json.NewDecoder(r.Body).Decode(&tp)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    estado, err := tiposDocumentos.InsertTipoDocumento(tp)
    if estado == false {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    w.WriteHeader(http.StatusCreated)
}

In this point, after send the request from Postman the program create successfully the table and its specifications and retrieve code 201 but the record was not inserted in the table. enter image description here View from pgAdmin4 enter image description here

Thanks ☻

Error after insert sucesfuly a new record in the database:

2020/07/13 12:43:28 http: panic serving 127.0.0.1:64546: runtime error: invalid memory address or nil pointer dereference
goroutine 36 [running]:
net/http.(*conn).serve.func1(0xc000230d20)
        C:/Go/src/net/http/server.go:1772 +0x140
panic(0x8085e0, 0xbb5e20)
        C:/Go/src/runtime/panic.go:975 +0x3f1
bitbucket.org/emanuelvald/gestion_personal/routers.PostTiposDocuemntos(0x912c20, 0xc00005e000, 0xc000058200)
        C:/Projects/Go/src/bitbucket.org/emanuelvald/gestion_personal/routers/tiposDocumentos.go:44 +0x151
net/http.HandlerFunc.ServeHTTP(0x893498, 0x912c20, 0xc00005e000, 0xc000058200)
        C:/Go/src/net/http/server.go:2012 +0x4b
github.com/gorilla/mux.(*Router).ServeHTTP(0xc00022a0c0, 0x912c20, 0xc00005e000, 0xc000058000)
        C:/Projects/Go/src/github.com/gorilla/mux/mux.go:210 +0xe9
net/http.serverHandler.ServeHTTP(0xc000270000, 0x912c20, 0xc00005e000, 0xc000058000)
        C:/Go/src/net/http/server.go:2807 +0xaa
net/http.(*conn).serve(0xc000230d20, 0x9137a0, 0xc000038080)
        C:/Go/src/net/http/server.go:1895 +0x873
created by net/http.(*Server).Serve
        C:/Go/src/net/http/server.go:2933 +0x363

8
  • 1
    When this if db.PsqlDb.NewRecord(tp) { is not satisfied you are returning true, nil which you then interpret as "everything went well" even though it obviously did not. Fix the logic first. Commented Jul 13, 2020 at 14:52
  • I fixed this problem and the the NewRecord function return false as if primary key was used but the table is empty!!! Commented Jul 13, 2020 at 15:39
  • 1
    Add the full stack trace of the panic to the question and I'll point out the exact file and line that's causing the crash. But if I had to guess, gorm Create returns the *DB instance and not an error, so the err variable is always a non-nil *DB, and therefore if err != nil { is always satisfied... then in that branch you return false, nil and subsequently you have the caller invoke err.Error() on that nil error value and boom! Commented Jul 13, 2020 at 15:57
  • 1
    The proper way to check gorm errors is to inspect the Error field of the *DB instance. i.e. err := db.Create(&tp).Error and then if err is not nil, you need to return it to the caller return false, err. Commented Jul 13, 2020 at 16:01
  • 1
    The stack trace shows that the origin of the panic is coming from the routers.PostTiposDocuemntos function in file ...routers/tiposDocumentos.go on line 44. Commented Jul 13, 2020 at 16:30

1 Answer 1

2

Consider what happens when err is non-nil here:

 if err != nil {
     return false, nil
 }

and then you do this:

estado, err := tiposDocumentos.InsertTipoDocumento(tp)
if estado == false {
    http.Error(w, err.Error(), http.StatusBadRequest)
    return
}

So, estado is false, and then you try to access err.Error(), but err is nil, so you get a

invalid memory address or nil pointer dereference

You probably just need to do:

 if err != nil {
     return false, err
 }

and then do:

if err != nil {
    http.Error(w, err.Error(), http.StatusBadRequest)
    return
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you so much Dave, I fixed my code with your help. Now I can insert new records in my CRUD project and I don't retrieve errors. See you!!!
@YoungAlCapone if possible try to follow the guidelines: stackoverflow.com/help/someone-answers
Sorry, I forgot accept your answer. Thanks again :)

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.