Actions must return a revel.Result, which handles the HTTP response generation and adheres to the simple interface:

type Result interface {
	Apply(req *Request, resp *Response)
}

revel.Controller provides a few methods to produce different results:

NOTE: From v0.14, the following changes:
  • `RenderJson` is now `RenderJSON`
  • `RenderJsonP` is now `RenderJSONP`
  • `RenderXml` is now `RenderXML`
  • Render(), RenderTemplate()
    • render a template, passing arguments.
  • RenderJSON(), RenderXML()
    • serialize a structure to json or xml.
  • RenderText()
    • return a plaintext response.
  • Redirect()
    • redirect to another action or URL
  • RenderFile(), RenderFileName()
    • return a file inline or to be downloaded as an attachment.
  • RenderError()
    • return a 500 response that renders the errors/500.html template.
  • NotFound()
    • return a 404 response that renders the errors/404.html template.
  • Todo()
    • return a stub response (500)

Additionally, the developer may define a result with CustomResult and return that.

Setting the Status Code / Content Type

Each built-in Result has a default HTTP Status Code and Content Type. To override those defaults, simply set those properties on the response:

func (c App) Index() revel.Result {
	c.Response.Status = http.StatusTeapot
	c.Response.ContentType = "application/dishware"
	return c.Render()
}

You can override the default status code by setting one yourself:

func (c *App) CreateEntity() revel.Result {
    c.Response.Status = 201
    return c.Render()
}

Controller.Render()

Called within an action (e.g. “Controller.Action”), Controller.Render() does two things:

  1. Adds all arguments to the controller’s ViewArgs, using their local identifier as the key.
  2. Executes the template “views/Controller/Action.html”, passing in the controller’s ViewArgs as the data map.

If unsuccessful (e.g. it could not find the template), an ErrorResult is returned instead.

This allows the developer to write:

func (c MyApp) Action() revel.Result {
	myValue := calculateValue()
	return c.Render(myValue)
}

and to use myValue in their template. This is usually more convenient than constructing an explicit map, since in many cases the data will need to be handled as a local variable anyway.

Note: Revel looks at the calling method name to determine the Template path and to look up the argument names. Therefore, `c.Render()` may only be called from Actions.
// Example using mix of render args and variables
// This renders the `views/MyController/showSutuff.html` template as
// eg <pre>foo={{.foo}} bar={{.bar}} abc={{.abc}} xyz={{.xyz}}</pre>
func (c MyController) ShowStuff() revel.Result {
    c.ViewArgs["foo"] = "bar"
    c.ViewArgs["bar"] = 1
    abc := "abc"
    xyz := "xyz"
    return c.Render(xyz, abc)
}

// Example renders the `views/Foo/boo.xhtml` tempate
func (c MyController) XTemp() revel.Result {
    c.ViewArgs["foo"] = "bar"
    c.ViewArgs["bar"] = 1
    return c.RenderTemplate("Foo/boo.xhtml")
}

Controller.RenderFile() / Controller.RenderFileName()

Within an action it is sometimes necessary to serve a file (e.g. an attachment). For this case the functions Controller.RenderFile() and Controller.RenderFileName() are there.

The main difference is that Controller.RenderFile() needs an *os.File and Controller.RenderFileName() takes a file path as a string. Both require a Content-Disposition option which can be revel.Attachment or revel.Inline.

  • revel.Attachment forces the browser to download the file. The filename and size are derived from the passed *os.File or file path.
  • revel.Inline indicates the browser that it may render the file inline. Note that when browsers can’t display the file a download is still performed.
  • revel.NoDisposition omits the content disposition header and let the browser figure out what to do, also omits the file name from the header.

Controller.RenderFileName() can also return an error in case the file is not found. See Controller.RenderError()

func (c App) File() revel.Result {
	f, _ := os.Open("/path/to/attachment.pdf")
	return c.RenderFile(f, revel.Inline)
}

func (c App) Filename() revel.Result {
	return c.RenderFileName("/path/to/attachment.docx", revel.Attachment)
}

Controller.RenderJSON() / Controller.RenderXML()

The application may call RenderJSON, RenderJSONP or RenderXML and pass in any Go type, usually a struct. Revel will serialize it using json.Marshal or xml.Marshal.

If results.pretty=true in conf/app.conf then serialization will be done using MarshalIndent instead, to produce nicely indented output for human consumption.

// Simple example

type Stuff struct {
    Foo string ` json:"foo" xml:"foo" `
    Bar int ` json:"bar" xml:"bar" `
}

func (c MyController) MyWork() revel.Result {
    data := make(map[string]interface{})
    data["error"] = nil
    stuff := Stuff{Foo: "xyz", Bar: 999}
    data["stuff"] = stuff
    return c.RenderJSON(data)
    // or alternately 
    // return c.RenderXML(data)
}

Redirect()

  • A helper function for generating HTTP redirects.
  • It may be used in two ways and both return a 302 Temporary Redirect HTTP status code.

Redirect to an action with no arguments:

    return c.Redirect(Hotels.Settings)
  • This form is useful as it provides a degree of type safety and independence from the routing and generates the URL automatically.

Redirect to a formatted string:

return c.Redirect("/hotels/%d/settings", hotelId)

  • This form is necessary to pass arguments.
  • It returns a 302 Temporary Redirect status code.

Custom Result

Below is a simple example of creating a custom revel.Result.

Create this type:

import ("net/http")

type MyHtml string

func (r MyHtml) Apply(req *revel.Request, resp *revel.Response) {
	resp.WriteHeader(http.StatusOK, "text/html")
	resp.GetWriter().Write([]byte(r))
}

Then use it in the action MyApp.Hello:

func (c *MyApp) Hello() revel.Result {
	return MyHtml("<html><body>Hello Result</body></html>")
}
GitHub Labels