I am working on an API and GET and POST are working fine except when I try and get a select record by its ID (e.g. /articles/2). The article exists and when retrieving all records via the /articles route I get a proper response. Here is the stack trace.
$ go run main.go
[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] GET / --> main.index (3 handlers)
[GIN-debug] GET /articles --> main.ArticlesList (3 handlers)
[GIN-debug] POST /articles --> main.ArticlePost (3 handlers)
[GIN-debug] GET /articles/:article_id --> main.ArticlesDetail (3 handlers)
[GIN-debug] Listening and serving HTTP on :8000
2015/06/18 10:31:49 Panic recovery -> interface conversion: error is *errors.errorString, not *errors.Error
c:/go/src/runtime/panic.go:387 (0x4114b6)
gopanic: reflectcall(unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
c:/go/src/runtime/iface.go:181 (0x40ae1a)
assertI2T: panic(&TypeAssertionError{*tab.inter.typ._string, *tab._type._string, *t._string, ""})
c:/Users/Fresh/go/src/github.com/jisaw/portfolio-server/main.go:37 (0x401261)
checkErr: log.Fatalln(msg, err.(*errors.Error).ErrorStack())
c:/Users/Fresh/go/src/github.com/jisaw/portfolio-server/main.go:97 (0x401e2c)
getArticle: checkErr(err, "selectOne failed")
c:/Users/Fresh/go/src/github.com/jisaw/portfolio-server/main.go:60 (0x4016a7)
ArticlesDetail: article := getArticle(a_id)
c:/Users/Fresh/go/src/github.com/gin-gonic/gin/context.go:86 (0x43694a)
(*Context).Next: c.handlers[c.index](c)
c:/Users/Fresh/go/src/github.com/gin-gonic/gin/logger.go:56 (0x442ff0)
func.007: c.Next()
c:/Users/Fresh/go/src/github.com/gin-gonic/gin/context.go:86 (0x43694a)
(*Context).Next: c.handlers[c.index](c)
c:/Users/Fresh/go/src/github.com/gin-gonic/gin/recovery.go:43 (0x4437e0)
func.009: c.Next()
c:/Users/Fresh/go/src/github.com/gin-gonic/gin/context.go:86 (0x43694a)
(*Context).Next: c.handlers[c.index](c)
c:/Users/Fresh/go/src/github.com/gin-gonic/gin/gin.go:249 (0x43b275)
(*Engine).handleHTTPRequest: context.Next()
c:/Users/Fresh/go/src/github.com/gin-gonic/gin/gin.go:230 (0x43aff9)
(*Engine).ServeHTTP: engine.handleHTTPRequest(c)
c:/go/src/net/http/server.go:1703 (0x4ad385)
serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
c:/go/src/net/http/server.go:1204 (0x4ab378)
(*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
c:/go/src/runtime/asm_386.s:2287 (0x435c01)
goexit:
And the Code
package main
import (
"github.com/gin-gonic/gin"
"database/sql"
"github.com/coopernurse/gorp"
_ "github.com/mattn/go-sqlite3"
"log"
"time"
"strconv"
"github.com/go-errors/errors"
)
type Article struct {
Id int64 `db:"article_id"`
Created int64
Title string
Content string
}
var dbmap = initDb()
func initDb() gorp.DbMap {
db, err := sql.Open("sqlite3", "db.sqlite3")
checkErr(err, "sql.Open faild")
dbmap := gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}
dbmap.AddTableWithName(Article{}, "articles").SetKeys(true, "Id")
err = dbmap.CreateTablesIfNotExists()
checkErr(err, "Create tables failed")
return dbmap
}
func checkErr(err error, msg string) {
if err != nil {
log.Fatalln(msg, err.(*errors.Error).ErrorStack())
}
}
func index (c *gin.Context) {
content := gin.H{"Hello": "World"}
c.JSON(200, content)
}
func ArticlesList(c *gin.Context) {
var articles []Article
_, err := dbmap.Select(&articles, "select * from articles order by article_id")
checkErr(err, "Select failed")
content := gin.H{}
for k, v := range articles {
content[strconv.Itoa(k)] =v
}
c.JSON(200, content)
}
func ArticlesDetail(c *gin.Context) {
article_id := c.Params.ByName("id")
a_id, _ := strconv.Atoi(article_id)
article := getArticle(a_id)
content := gin.H{"title": article.Title, "content": article.Content}
c.JSON(200, content)
}
func ArticlePost(c *gin.Context) {
var json Article
c.Bind(&json)
article := createArticle(json.Title, json.Content)
if article.Title == json.Title {
content := gin.H{
"result": "Success",
"title": article.Title,
"content": article.Content,
}
c.JSON(201, content)
} else {
c.JSON(500, gin.H{"result": "An error occured"})
}
}
func createArticle(title, body string) Article {
article := Article{
Created: time.Now().UnixNano(),
Title: title,
Content: body,
}
err := dbmap.Insert(&article)
checkErr(err, "Insert failed")
return article
}
func getArticle(article_id int) Article {
article := Article{}
err := dbmap.SelectOne(&article, "select * from articles where article_id=?", article_id)
checkErr(err, "selectOne failed")
return article
}
func main() {
app := gin.Default()
app.GET("/", index)
app.GET("/articles", ArticlesList)
app.POST("/articles", ArticlePost)
app.GET("/articles/:article_id", ArticlesDetail)
app.Run(":8000")
}
The stacktrace is explicit:
interface conversion: error is *errors.errorString, not *errors.Error
.So in
checkErr()
, the type assertion onerr
is wrong.Here is the solution:
If you need to understand why you are getting this
panic
, I'd suggest you to read the Golang specs about type assertions.