Creating a Reusable Function
So far, we've been using the HTML
method of Gin's context to render directly from route handlers. This is fine when we always want to render HTML. However, if we want to change the format of the response based on the request, we should refactor this part out into a single function that takes care of rendering. By doing this, we can let the route handler focus on validation and data fetching.
A route handler has to do the same kind of validation, data fetching and data processing irrespective of the desired response format. Once this part is done, this data can be used to generate the response in the desired format. If we need an HTML response, we can pass this data to the HTML template and generate the page. If wee need a JSON response, we can convert this data to JSON and send it back. Likewise for XML.
We'll create a render
function in main.go
that will be used by all the route handlers. This function will take care of rendering in the right format based on the request's Accept
header.
In Gin, the Context
passed to a route handler contains a field named Request
. This field contains the Header
field which contains all the request headers. We can use the Get
method on Header
to extract the Accept
header as follows:
// c is the Gin Context
c.Request.Header.Get("Accept")
- If this is set to
application/json
, the function will render JSON, - If this is set to
application/xml
, the function will render XML, and - If this is set to anything else or is empty, the function will render HTML.
The complete render
function is as follows:
// Render one of HTML, JSON or CSV based on the 'Accept' header of the request
// If the header doesn't specify this, HTML is rendered, provided that
// the template name is present
func render(c *gin.Context, data gin.H, templateName string) {
switch c.Request.Header.Get("Accept") {
case "application/json":
// Respond with JSON
c.JSON(http.StatusOK, data["payload"])
case "application/xml":
// Respond with XML
c.XML(http.StatusOK, data["payload"])
default:
// Respond with HTML
c.HTML(http.StatusOK, templateName, data)
}
}