Search code examples
restcurlgorevel

I cannot get posted body in revel go framework


I am trying to implement a basic CRUD using the Rest architecture in revel, but I am not able to send the data encoded in json format to an endpoint, I was try multiple ways to check the body content in the request, so now I have a "minimal compilable example":

  1. create a new project using revel cli tool.

  2. Apply the following changes

    diff --git a/app/controllers/app.go b/app/controllers/app.go
    index 1e94062..651dbec 100644
    --- a/app/controllers/app.go
    +++ b/app/controllers/app.go
    @@ -9,5 +9,6 @@ type App struct {
     }
    
     func (c App) Index() revel.Result {
    -   return c.Render()
    +   defer c.Request.Body.Close()
    +   return c.RenderJSON(c.Request.Body)
     }
    diff --git a/conf/routes b/conf/routes
    index 35e99fa..5d6d1d6 100644
    --- a/conf/routes
    +++ b/conf/routes
    @@ -7,7 +7,7 @@ module:testrunner
     # module:jobs
    
    
    -GET     /                                       App.Index
    +POST     /                                       App.Index
    
     # Ignore favicon requests
     GET     /favicon.ico                            404
    
  3. do a POST request:

    curl --request POST --header "Content-Type: application/json" --header "Accept: application/json" --data '{"name": "Revel framework"}' http://localhost:9000
    

My problem; the curl call does not give me an echo back (the same json {"name": "Revel framework"}), so what I am missing to use revel correctly?

PS: I can find some other related links to this problem but they do not work for me. For example this: https://github.com/revel/revel/issues/126


Solution

  • According to the source of Revel, when the request content type is either application/json or text/json, the content of request body is automatically read from stream and stored to c.Params.JSON which has type []byte.

    Since the Request.Body is a stream which can only be read once, you cannot read it again (and anyway, your code won't work even if Revel does not automatically read the stream, since c.Request.Body is not correctly serialiazable usingc.RenderJSON()).

    Revel has convenient function Params.BindJSON which converts c.Params.JSON to the golang object.

    Here's sample code.

    type MyData struct {
        Name string `json:"name"`
    }
    
    func (c App) Index() revel.Result {
        data := MyData{}
        c.Params.BindJSON(&data)
        return c.RenderJSON(data)
    }