-
Notifications
You must be signed in to change notification settings - Fork 0
Introduction to Layr Routing
Every time you surf the web you are visiting resources wich are routed by some server implementations. Routing mechanisms are designed to handle HTTP/HTTPS requests, perform some action with its request's data and send back a response. Designed to keep Business logic separated from View logic, Layr routing is pretty simple and will helps you to don't repeat yourself on your diary task during web development. At this chapter we will undestand:
- How Layr routing works
- How to render templates
- How to send JSON as response
- How to receive JSON as parameter
- How to receive parameters in routing methods
- How to render custom Content Types
// CustomerResource.scala
import layr.api.ResponseBuilder._
import layr.api._
@WebResource("customer")
class CustomerResource {
@GET def printHelloWorldTemplate()
= template("customer.xhtml")
}
At above example, we "wire" the URL /customer/
to customer.xhtml
template. ResponseBuilder
is a simple DSL that will helps to routing you templates, which their methods are described at end of this document.
Routing is basically defining for which URI and HTTP Method a class will be responsible for handle a request. In Layr, it's done through web method annotations (layr.api.GET, layr.api.POST, layr.api.PUT and layr.api.DELETE
). Both four annotations should be used on methods of a class annotated with layr.api.WebResource
annotation.
The layr.api.WebResource
defines which is the root URI a class will handle. And, as said before, the web methods annotations will wire the method to a URI. They have an optional value which can be used to append a route URI to root URI. At the bellow example, we've defined a route which will render a template every time the URI /customers/list is called.
import static layr.api.ResponseBuilder.*;
import static layr.api.*;
// web resource class
@WebResource("customer")
class CustomerResource {
// web method annotation representing GET request
@GET("list")
// route method
public Response renderCustomerList(){
return template("customerList.xhtml");
}
}
By default, Layr comes with (X)HTML and JSON support. Which output type will be rendered is defined based on Response objected that is returned at the route method. It holds all information needed to Layr routing mechanism choose between its possible output formats. ResponseBuilder API provide lot of methods which will make our life easier with rendering.
At our last sample the static method layr.api.ResponseBuilder.template
created a Response object to render a template named "customerList.xhtml". At bellow example we will bind some values to the template, and render a populated HTML to the browser. You could also note its possible to set a more specific root path in the WebResource annotation.
@WebResource("customer/list")
public class CustomerResource {
final static Map<Long,Customer> data = new HashMap<Long,Customer>();
@GET
public Response renderCustomerHome(){
return template("customerList.xhtml")
.set("list", data.values());
}
public static class Customer {
Long id;
String name;
// some getters and setters ...
}
}
Bellow is the customerList.xhtml
template which will be populated with all customer populated on data
.
<!DOCTYPE html>
<html xmlns:tpl="urn:layr:template">
<head><title>Customer List</title></head>
<body>
<h1>Customer List</h1>
<ul>
<tpl:foreach var="customer" values="#{list}">
<li id="customer#{customer.id}">#{customer.name}</li>
</tpl:foreach>
</ul>
</body>
</html>
Learn more about how Layr templates works reading the 'Using HTML template effectively with Layr' article.
Resource classes could have many route methods, every one with its specifics output responses. It could be used to render any (X)HTML you want, but also could render a JSON object. Again, the default ResponseBuilder will help us to accomplish this:
@WebResource("customer/data")
public class CustomerResource {
final static Map<Long,Customer> data = new HashMap<Long,Customer>();
@GET("first")
public Response retrieveFisrtCustomer(){
return json( data.get(0) );
}
@GET
public Collection<Customer> retrieveCustomers(){
return data.values();
}
}
At this example, we exposed two methods which returns the first customer set on our data and the list of available customers, respectively. But, there's a tiny difference between them: the first one was made through ResponseBuilder.json
method, but the second one wasn't.
The ResponseBuilder.json
is a helper method that could be used to send JSON response every time you need it. In other hands, when the returned object isn't a Response instance, Layr's default behaviour is to send this object to the default OutputRenderer mechanism, which is JSON.
To learn how you can change the default OutputRenderer take a look at Handling Custom Content-Type's article.
Resource classes could also to handle JSON objects sent by the browser/http client. It is done putting an object that represents the JSON object as parameter into the route method, as the sample Scala code bellow.
@WebResource("customer")
class CustomerResource {
// Some DAO/Service implementation of customer
CustomerService customerService;
@GET("edit/{id}")
def renderEditCustomer( @QueryParameter("id") Long id ):Customer
= template("customerForm.xhtml")
.parameters( customerService.get( id ) )
@POST
def save( Customer customer ):Response = {
Long id = customerService.save( customer )
return statusCode(204).header( "Location", s"customer/edit/$id" )
}
}
class Customer {
@BeanProperty Long id
@BeanProperty String name
}
On this example, we have a resource class that render a form when receive a GET in /customer/edit/<id>
and could receive a JSON through a POST at /customer
. Layr out-of-box could handle JSON and URL Encoded parameters, and can also handle custom Content-Type's through its InputConverter feature. To grant that the request is doing fine, and could handle the JSON request, just assert that "Content-Type" HTTP header is set to "application/json".
TODO