go version)?go version go1.9.2 windows/amd64
Postgres, 9 and 10
I use this code below, found here: https://medium.com/@thedevsaddam/build-restful-api-service-in-golang-using-gin-gonic-framework-85b1a6e176f3
When I launch it with go run main.go and try to call the v1.GET("/", fetchAllTodo) API it throw like this:
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] POST /api/v1/todos/ --> main.createTodo (3 handlers)
[GIN-debug] GET /api/v1/todos/ --> main.fetchAllTodo (3 handlers)
[GIN-debug] GET /api/v1/todos/:id --> main.fetchSingleTodo (3 handlers)
[GIN-debug] PUT /api/v1/todos/:id --> main.updateTodo (3 handlers)
[GIN-debug] DELETE /api/v1/todos/:id --> main.deleteTodo (3 handlers)
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8080
[GIN] 2018/01/11 - 00:56:46 | 404 | 0s | ::1 | GET /api/v1
[GIN-debug] redirecting request 301: /api/v1/todos --> /api/v1/todos/
2018/01/11 00:56:50 [Recovery] panic recovered:
GET /api/v1/todos/ HTTP/1.1
Host: localhost:8080
Accept: */*
runtime error: invalid memory address or nil pointer dereference
C:/Go/src/runtime/panic.go:491 (0x42bff0)
gopanic: reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
C:/Go/src/runtime/panic.go:63 (0x42ae74)
panicmem: panic(memoryError)
C:/Go/src/runtime/signal_windows.go:161 (0x440302)
sigpanic: panicmem()
C:/Users/John/go/src/github.com/jinzhu/gorm/main.go:715 (0x942c7e)
(*DB).clone: db: s.db,
C:/Users/John/go/src/github.com/jinzhu/gorm/main.go:293 (0x93f1b5)
(*DB).Find: return s.clone().NewScope(out).inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db
C:/projects/gotest/main.go:71 (0x9884f1)
fetchAllTodo: db.Find(&todos)
C:/Users/John/go/src/github.com/gin-gonic/gin/context.go:107 (0x8efcb9)
(*Context).Next: c.handlers[c.index](c)
C:/Users/John/go/src/github.com/gin-gonic/gin/recovery.go:46 (0x9024c0)
RecoveryWithWriter.func1: c.Next()
C:/Users/John/go/src/github.com/gin-gonic/gin/context.go:107 (0x8efcb9)
(*Context).Next: c.handlers[c.index](c)
C:/Users/John/go/src/github.com/gin-gonic/gin/logger.go:83 (0x9017e2)
LoggerWithWriter.func1: c.Next()
C:/Users/John/go/src/github.com/gin-gonic/gin/context.go:107 (0x8efcb9)
(*Context).Next: c.handlers[c.index](c)
C:/Users/John/go/src/github.com/gin-gonic/gin/gin.go:359 (0x8f912c)
(*Engine).handleHTTPRequest: c.Next()
C:/Users/John/go/src/github.com/gin-gonic/gin/gin.go:326 (0x8f88b1)
(*Engine).ServeHTTP: engine.handleHTTPRequest(c)
C:/Go/src/net/http/server.go:2619 (0x66bd6a)
serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
C:/Go/src/net/http/server.go:1801 (0x667d93)
(*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
C:/Go/src/runtime/asm_amd64.s:2337 (0x457ee0)
goexit: BYTE $0x90 // NOP
[GIN] 2018/01/11 - 00:56:50 | 500 | 10.005ms | ::1 | GET /api/v1/todos/
exit status 2
package main
import (
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/postgres"
)
var db *gorm.DB
func init() {
//open a db connection
var err error
db, err := gorm.Open("postgres", "host=localhost user=postgres dbname=postgres sslmode=disable password=pass")
if err != nil {
panic("failed to connect database")
}
//Migrate the schema
db.AutoMigrate(&todoModel{})
}
func main() {
router := gin.Default()
v1 := router.Group("/api/v1/todos")
{
v1.POST("/", createTodo)
v1.GET("/", fetchAllTodo)
v1.GET("/:id", fetchSingleTodo)
v1.PUT("/:id", updateTodo)
v1.DELETE("/:id", deleteTodo)
}
router.Run()
}
type (
// todoModel describes a todoModel type
todoModel struct {
gorm.Model
Title string `json:"title"`
Completed int `json:"completed"`
}
// transformedTodo represents a formatted todo
transformedTodo struct {
ID uint `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
)
// createTodo add a new todo
func createTodo(c *gin.Context) {
completed, _ := strconv.Atoi(c.PostForm("completed"))
todo := todoModel{Title: c.PostForm("title"), Completed: completed}
db.Save(&todo)
c.JSON(http.StatusCreated, gin.H{"status": http.StatusCreated, "message": "Todo item created successfully!", "resourceId": todo.ID})
}
// fetchAllTodo fetch all todos
func fetchAllTodo(c *gin.Context) {
var todos []todoModel
var _todos []transformedTodo
db.Find(&todos)
if len(todos) <= 0 {
c.JSON(http.StatusNotFound, gin.H{"status": http.StatusNotFound, "message": "No todo found!"})
return
}
//transforms the todos for building a good response
for _, item := range todos {
completed := false
if item.Completed == 1 {
completed = true
} else {
completed = false
}
_todos = append(_todos, transformedTodo{ID: item.ID, Title: item.Title, Completed: completed})
}
c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": _todos})
}
// fetchSingleTodo fetch a single todo
func fetchSingleTodo(c *gin.Context) {
var todo todoModel
todoID := c.Param("id")
db.First(&todo, todoID)
if todo.ID == 0 {
c.JSON(http.StatusNotFound, gin.H{"status": http.StatusNotFound, "message": "No todo found!"})
return
}
completed := false
if todo.Completed == 1 {
completed = true
} else {
completed = false
}
_todo := transformedTodo{ID: todo.ID, Title: todo.Title, Completed: completed}
c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": _todo})
}
// updateTodo update a todo
func updateTodo(c *gin.Context) {
var todo todoModel
todoID := c.Param("id")
db.First(&todo, todoID)
if todo.ID == 0 {
c.JSON(http.StatusNotFound, gin.H{"status": http.StatusNotFound, "message": "No todo found!"})
return
}
db.Model(&todo).Update("title", c.PostForm("title"))
completed, _ := strconv.Atoi(c.PostForm("completed"))
db.Model(&todo).Update("completed", completed)
c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "message": "Todo updated successfully!"})
}
// deleteTodo remove a todo
func deleteTodo(c *gin.Context) {
var todo todoModel
todoID := c.Param("id")
db.First(&todo, todoID)
if todo.ID == 0 {
c.JSON(http.StatusNotFound, gin.H{"status": http.StatusNotFound, "message": "No todo found!"})
return
}
db.Delete(&todo)
c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "message": "Todo deleted successfully!"})
}
The problem was the line:
db, err := gorm.Open...
instead of:
db, err = gorm.Open...
So... the assignment.
Most helpful comment
The problem was the line:
db, err := gorm.Open...instead of:
db, err = gorm.Open...So... the assignment.