The code is available on GitHub: https://github.com/ftomassetti/BlogService_SparkExample.
The tutorial is written by Federico Tomassetti, you can read other posts from this author on his blog.
How to offer both JSON and HTML responses?
To offer the same data as JSON or HTML we could use different strategies. The two simplest ones are:
- using different endpoints for JSON and HTML
- use the Accept header to determine what format of data to return
The first strategy is very simple to implement: You just have to create different routes. For example, we could offer the JSON data in response to the endpoints /service/posts and /service/posts/:id while offering HTML data in response to the endpoints /posts and /posts/:id. This is because we typically want shorter URLs for the content intended for human beings. In this post we will focus on the Accept-header strategy though, which requires a bit of work.
An HTTP request reaching our service brings a lot of information, including the URL (of which we can parse specific parts to derive parameters), query parameters, a body and headers.
An interesting header is Accept. It can be used to specify the format that the caller is able to process or the formats it prefers. A web browser typically set this header to contains text/html. Other applications prefer to work with format like JSON or XML (for the young kids out there: XML is a weird markup thing we used to have before JSON).
The actual content of the header can be quite complex, for example, my browser sends:
This is a list of formats in the order in which they are preferred by the browser (see content negotiation for details).
Let's see how use the Accept header to decide when to return HTML from Spark (spoiler alert: it is easy!)
Producing HTML programmatically using j2html
Let'see how we could generate HTML from Java. We are going to use j2html , a library from David Ã se. David, among other things, is involved in the Spark project and redesigned the whole website (if you are interested in reading more about him have a look at this interview about his involvement in open-source).
Let's start by adding the dependency in our POM file:
- we start from the body of the page and we insert two elements in it: an header (h1) and a div which will contain all the posts
- we then take all the posts and map each post to the corresponding piece of html code
- each single post is map to a div which contains an header (h2) for the title a paragraph (p) for the content and a list (ul) for the categories
- each single category is simple mapped to an element of the list (li)
I think j2html is great when prototyping HTML pages because it avoids us the hassle of setup a template engine. In addition to that is very useful when you need to generate small pieces of HTML to be used to composed larger pages. However if you want to build complex layouts you may want to use templates to achieve a stronger separation between logic and presentation. In the next paragraph we take a look at templates.
The example using j2html is present in the GitHub repository under the tag j2html
Producing HTML: Using the FreeMarker template engine
One thing that I like about FreeMarker is that it is quite flexible. For example we can use different strategies to find the templates. The two common approaches are:
- pack the templates inside the application (as part of the jar/war produced and deployed)
- leave the templates outside the application
The first strategy makes deployment easier: The package contains everything, including the templates. The second one allows for modifying the templates without having to re-package and redeploy the application.
I prefer the first option (at least when templates are reasonably stable) so we are going to see how we can store the templates as resource files.
Let's start by creating a file named posts.ftl under the directory src/main/resources. The template will not contain dynamic parts just this simple content:
Cool, we are able to load and display a template but so far the template does not contain any dynamic content: it is just producing the same page whatever content we have in our blog. Let's correct this.
In the code to render the template we used a map:
- we start by iterating on the posts (posts is a key in the map we passed to the FreeMarker enginer, so we can access it here)
- for each post we display title, content and publishing_date
- we iterate on the categories of the single post and display them
As we have seen in this post Spark can be easily integrated with template engines and FreeMarker is a decent choice. I personally think that Spark is great for RESTful services but it does a pretty good job also for common user-facing web applications and it can be easily used for mixed applications (RESTful service + HTML interface, as we have seen in this post).
There are improvements to be done to use templates in a large application. For example you may want to define a common structure (header, navigation column, footer) to be used in all the different templates, without having to maintain copies. To understand how to do this and more advanced topics I suggest to take a look at the FreeMarker documentation but feel free to write a comment here or use the Spark forum.