Reputation: 123
I have written a very simple Go app using the Martini library. When putting together a simple REST API example I wanted to render JSON data back to the user when an error occurred like:
{
error: "Document Not Found",
code: 404
}
I'm using the following code to return a map that Martini can render into JSON. package ErrorResponces
import "net/http"
type ErrJson interface {
RenderErr(v int)
}
func RenderErr(v int) map [string]interface{} {
var returnMap = map[string]interface{} {
"error": http.StatusText(v),
"code": v,
}
return returnMap
}
Later in my controller code I try and test this method using
fmt.Println(ErrJson.RenderErr(400))
However I get the following error:
controllers\FoodController.go:25: cannot use 400 (type int) as type ErrorResponces.ErrJson in function argument: int does not implement ErrorResponces.ErrJson (missing RenderErr method)
controllers\FoodController.go:25: not enough arguments in call to ErrorResponces.ErrJson.RenderErr controllers\FoodController.go:25: ErrorResponces.ErrJson.RenderErr(400) used as value
I'm having a hard time figuring out exactly what this error is talking about.
Upvotes: 2
Views: 1918
Reputation: 151
It seems that you're trying to called a function directly on an interface type instead of an object which implements that interface.
Here's a simple example that returns JSON data:
package main
import (
"encoding/json"
"github.com/codegangsta/martini"
"net/http"
)
func Encode(v ...interface{}) (string, error) {
var data interface{} = v
if v == nil {
// So that empty results produces `[]` and not `null`
data = []interface{}{}
} else if len(v) == 1 {
data = v[0]
}
b, err := json.Marshal(data)
return string(b), err
}
func RenderErr(v int) map[string]interface{} {
var returnMap = map[string]interface{}{
"error": http.StatusText(v),
"code": v,
}
return returnMap
}
func main() {
m := martini.Classic()
m.Get("/", func(c martini.Context, w http.ResponseWriter, r *http.Request) string {
w.Header().Set("Content-Type", "application/json")
str, err := Encode(RenderErr(400))
if err != nil {
panic(err)
}
return str
})
m.Run()
}
If you wanted to use your interface idea, you could do something like this (I tried to copy what you were basically doing):
package main
import (
"encoding/json"
"github.com/codegangsta/martini"
"net/http"
)
func Encode(v ...interface{}) (string, error) {
var data interface{} = v
if v == nil {
// So that empty results produces `[]` and not `null`
data = []interface{}{}
} else if len(v) == 1 {
data = v[0]
}
b, err := json.Marshal(data)
return string(b), err
}
type ErrJson interface {
RenderErr() string
}
type ErrJsonCode int
func (e ErrJsonCode) RenderErr() string {
var returnMap = map[string]interface{}{
"error": http.StatusText(int(e)),
"code": int(e),
}
str, err := Encode(returnMap)
if err != nil {
panic(err)
}
return str
}
func main() {
m := martini.Classic()
m.Get("/", func(c martini.Context, w http.ResponseWriter, r *http.Request) string {
w.Header().Set("Content-Type", "application/json")
return ErrJsonCode(400).RenderErr()
})
m.Run()
}
I'm not sure I would design it like this though. I would probably make it more generic and have it support multiple content types, and not have an error tied to its content type. Here is a decent article about building a restful API with Martini: http://0value.com/build-a-restful-API-with-Martini (it uses some advanced concepts).
Upvotes: 2