17

I am learning Go by building a simple API interface for a web server. I want to return a simple message in JSON, when a default route is hit.

So far, reading online, this is the easiest way to return a literal JSON string, and encode it and send it to the user.

func GetDefault(c *gin.Context)  {
    jsonData := []byte(`{"msg":"this worked"}`)

    var v interface{}
    json.Unmarshal(jsonData, &v)
    data := v.(map[string]interface{})  

    c.JSON(http.StatusOK,data)
}

Is this the most efficient / fastest way to do it?

in node.js and express, I would do something like:

return res.status(200).json({"msg":"this worked"});

Whats the best way to do this in Go + Gin?

icza
  • 389,944
  • 63
  • 907
  • 827
tritium_3
  • 648
  • 1
  • 8
  • 17
  • 1
    `c.JSON(http.StatusOK, map[string]string{"msg":"this worked"})` is closer to the node.js example. – mkopriva Jun 19 '19 at 09:40
  • @mkopriva The asker has the JSON response ready as a `string` value. – icza Jun 19 '19 at 09:41
  • @icza I noticed that, however `{"msg":"this worked"}` in node is not a string literal but an object. So I've reasoned that if they can use an object in node, why not a map in go? – mkopriva Jun 19 '19 at 09:46
  • yeah not necessarily needs to be a string, the example node.js code is what i'm aiming for. an object that is easily constructed without using a predefined struct. – tritium_3 Jun 19 '19 at 19:39

2 Answers2

32

One option is to use Context.Data() where you provide the data to send (along with the content type):

func GetDefault(c *gin.Context)  {
    jsonData := []byte(`{"msg":"this worked"}`)

    c.Data(http.StatusOK, "application/json", jsonData)
}

You may also use a constant for the content type:

func GetDefault(c *gin.Context)  {
    jsonData := []byte(`{"msg":"this worked"}`)

    c.Data(http.StatusOK, gin.MIMEJSON, jsonData)
}

If your data is availabe as a string value and is big, you can avoid converting it to []byte if you use Context.DataFromReader():

func GetDefault(c *gin.Context) {
    jsonStr := `{"msg":"this worked"}`

    c.DataFromReader(http.StatusOK,
        int64(len(jsonStr)), gin.MIMEJSON, strings.NewReader(jsonStr), nil)
}

This solution also works if you have your JSON as an io.Reader, e.g. an os.File.

icza
  • 389,944
  • 63
  • 907
  • 827
  • 2
    While all your answers are technically correct, it seems overkill to have so much effort put into sending a JSON-formatted string, when [`Context.JSON()`](https://pkg.go.dev/github.com/gin-gonic/gin?utm_source=godoc#Context.JSON) does that job effortlessly... – Gwyneth Llewelyn Mar 28 '22 at 23:49
  • 3
    @GwynethLlewelyn the high-level Context.JSON is great, but this answer is very useful when you already have a JSON-literal byteArray, e.g. such as output from some subprocess that spits out JSON already. Thanks – keyvan Aug 07 '22 at 19:57
  • 1
    @keyvan — hm! Ok, granted, I wasn't assuming that at all, and I think I'll agree with you that in such a scenario, it might be more efficient to do it this way, as opposed to go for `Context.JSON()`. Then again, I guess I'm 'wired' to prefer clarity and readability as opposed to efficiency, and that's why I personally still prefer @eduardo-hitek's answer, which 'works' independently of the particular edge case being considered, and is reasonably idiomatic for Gin Gonic. It might, however, not be the 'best' way to do it in many special scenarios, where efficiency might be crucial! – Gwyneth Llewelyn Aug 20 '22 at 17:01
24

you can use the gin.H struct on you response:

c.JSON(http.StatusOK, gin.H{"msg":"this worked"})
Eduardo Hitek
  • 553
  • 2
  • 13
  • 2
    Since, from context, it's clear that the OP is using the Gin Gonic framework, this answer represents the best, idiomatic way to do it under Gin. The other answers may be 'correct', strictly speaking, but they're not 'best practices' for those who use Gin Gonic. – Gwyneth Llewelyn Mar 28 '22 at 23:48