2

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.

1 Answer 1

2

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).

Sign up to request clarification or add additional context in comments.

1 Comment

ahh! I see now. Thank you for the resources as well

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.