Thursday, 26 June 2014

RESTful Service with RESTEasy - Building a Sample Application (Tabernus)

Introduction


REST is an architectural style enabling networked applications to communicate with one another, typically over HTTP. It allows applications to create, retrieve, update and delete data on a server using simple HTTP requests. This is achieved using HTTP verbs such as GET, PUT, POST, DELETE and a URI describing the location of the resource.

For example, using REST we can:


Create a new Resource by invoking a POST request to
    • http://localhost:8080/RESTfulBookstore/bookstoreService/customer/
Update an existing Resource by invoking a PUT request to
    • http://localhost:8080/RESTfulBookstore/bookstoreService/customer/242
where 242 is the id of the customer whose details need to be updated.

Retrieve an existing Resource by invoking a GET request to
    • http://localhost:8080/RESTfulBookstore/bookstoreService/customer/51
where 51 is the id of the customer whose details need to be retrieved.

Delete an existing Resource by invoking a DELETE request to
    • http://localhost:8080/RESTfulBookstore/bookstoreService/customer/42
where 42 is the id of the customer whose details need to be deleted


The objective of this post is to provide an introduction to REST. To help achieve this, I developed a sample application that will be discussed below. The source for this sample application is available at here

Developing a sample application: Tabernus
My goal was to build something very simple which would help me become familiar with key concepts of the REST api and to this end I've knocked up a simple app. The scenario I'm going to model revolves around purchasing items from an online store (Tabernus). This store only sells 3 types of items: Books, Music CDs, and software.

The following diagram shows our domain entities.




A Customer can place many Orders. An Order comprises of a number of OrderItems each of which relate to a single item and specify the quantity required for that item. The API exposed by our RESTful service should enable us to perform essential CRUD tasks such as:
  • Creating a new Customer
  • Retrieving details for an existing Customer
  • Updating the details for an existing Customer
  • Deleting an existing Customer

Pre-requisites

The application was developed using java 6, Ant 1.8.4 and deployed in JBOSS AS 7.3. The following jars were also required




I also found it useful to install the WebServiceTester plugin for eclipse. This allowed me to test out urls and i could view the response that was sent back by the server.

Developing a Sample Application : Tabernus

Developing a RESTful application turned out to be quite simple and required very little code. It involved 3 main steps, which are described below.

Step 1 - Bootstrapping

A key step in implementing a RESTful application is to inform the underlying RESTful framework which class is to be used to deliver the service. Furthermore it needs to be told how that service should be deployed. The service class can be configured in one of two ways, namely as a singleton or on a per-request basis. In the former case, all HTTP requests are handled by one instance of our Service class. In a Per-request approach, a new instance of our service is instantiated to process the incoming request and is discarded at the end of that request. It should be noted that the latter implies statelessness as no service state is held between requests. This is in accordance with the HTTP protocol which is inherently stateless.

To configure our Service using either approach, we need to implement a class that extends Application. In this instance, I have opted for the per-request approach and the bootstrapping class (ApplicationConfig) is shown below,

@ApplicationPath("/")
public class ApplicationConfig extends Application {
    @SuppressWarnings("unchecked")
    public <Set<?>> getClasses() {
        return new HashSet<Class<?>>(Arrays.asList(BookstoreService.class));
   }
}

In this case, all incoming requests will be handled by the class BookstoreService.

The @ApplicationPath provides the relative base URL for our JAX-RS service.

The latest versions of resteasy don't require any configuration in the web.xml. For the most part it can be left empty, as follows:
   
  RESTfulBookstore


Step 2 - Annotation of Domain classes

A very useful feature of JAX-RS is that it provides support for (un)marshalling JAXB annotated classes.

Given below is an example of the Customer domain object.

@XmlRootElement(name="customer")
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer implements Serializable {

    private static final long serialVersionUID = -5757865852221123124L;

    @XmlAttribute(name="id")
    private int userId;

    @XmlElement
    private String forename;
 
    @XmlElement
    private String lastname;
 
    @XmlElement
    private String email;
 
    @XmlElement
    private List<Order> orders;

    ...................
    ...................

The @XmlRootElement annotation is used to identify the class as the main XML element, <customer>. The @XmlAttribute annotation is placed above the userId field. It will be used by JAXB to insert an attribute named 'id' (rather than userId) into the <customer> tag. Note that the name() attribute can be used with the various annotations to tell JAXB, how that java property is to be named in the XML document. If left unspecified, JAXB will use the default value which is essentially the name of the annotated field. Finally the @XmlElement annotation is used to decorate the various properties of our Java class. This instructs JAXB to map this property to a subelement of the XML element representing our Customer entity.

It's worth noting that the very last property which is a collection of Order instances is also decorated in the same way.


Step 3 - Expose the Service API

Next up, I had to write the service class (BookStoreService) which exposes an API to perform CRUD operations on Customer instances. The class is declared in the following way.

@Path("/bookstoreService")

public class BookstoreService {

private static final BackendService backendService = new BackendServiceImpl();

       ....................

       ....................



The @Path annotation is used to specify a URI matching pattern for incoming HTTP requests. Typically this would be relative to the context root of your application. It is required here at the class level to enable the BookstoreService to receive HTTP requests.

Finally note that this class references BackendService which is effectively a dummy service used here to simulate a real back-end service such as an EJB service tier. In the following sections, I'll provide the method implementations for performing basic CRUD operations on Customer instances.

Retrieve Single Customer

The First operation I looked at was to retrieve an existing Customer. The implementation is listed below,

 @GET
 @Path("/customer/{id}")
 @Produces("application/*+xml")
 public Customer getCustomer(@PathParam("id") int id) throws WebApplicationException {
  
  final Customer customer = backendService.getCustomer(id);
  
  if(customer == null) {
   throw new WebApplicationException(Response.Status.NOT_FOUND);
  }
  
  return customer;
 }


The annotation @GET marks this out to be accessible via a HTTP GET operation. The @Path annotation specifies the url pattern required to invoke this method. Note that the data-binding is made possible by using curly-bracket notation to wrap the id, i.e. {id}. A combination of these two annotations is sufficient to enable RESTeasy to map an incoming request to the Service method that needs to be invoked. The @Produces annotation is required to specify the response type. Finally the method argument is prefixed with the @PathParam annotation which indicates that this is a request parameter and needs to be passed as an argument to the method.

 The method itself is quite simple. It makes a request to the backend service to return the customer for the given customer id. It subsequently returns this as a response. Note that there is no requirement for us to transform this in anyway and all serialization is taken care of under the covers.

To test this, I wrote a simple JUnit Test. The RESTful service was deployed under JBOSS AS 7. The test is listed below:

 private Client client;

 @Before
 public void setUp() throws Exception {
  client = ClientBuilder.newClient();
 }

 @After
 public void tearDown() throws Exception {
  client = null;
 }

 /**
  * Tests that we can retrieve a specific customer using customer id
  */
 @Test
 public void testGetSpecificCustomer() {

  final int specificCustomerId = 2;

  WebTarget target = client.target("http://localhost:8080/RESTfulBookstore/bookstoreService/customer/"+String.valueOf(specificCustomerId));

  Response response = target.request().get();

  Customer customer = response.readEntity(Customer.class);

  response.close(); 

  assertEquals(200, response.getStatus());

 }


Accessing a REST resource is actually quite straightforward and is made possible using the client interface exposed by JAX-RS. The process is as follows


  1. Obtain an instance of the jax.ws.rs.client.Client interface by invoking the newClient() method on the class ClientBuilder
  2. Configure the Client with the target url. This will instruct the Client class to fire a http request at this address.
  3. Create a HTTP Request using the .getRequest() method
  4. Finally invoke the request. This will also specify which HTTP method (e.g. GET/PUT) will be executed.


This will return a response. The payload accompanying the response can be accessed by using the readEntity() method and passing as an argument the type of the Java class that is to be returned. Finally we finish up by ensuring that the response is closed.

Retrieve Collection of Customers (GET)

In a similar fashion, to retrieve a Collection of Customers we do the following

 
 @GET
 @Path("/customers")
 @Produces("application/*+xml")
 public List getAllCustomers() {  
    final List customers = backendService.getAllCustomers();
    return customers;
 }

Note that in this case, we want to retrieve all Customer instances and therefore don't need to specify a userId.

The Client code executes the request in the following way:

    
 WebTarget target = client.target("http://localhost:8080/RESTfulBookstore/bookstoreService/customers");

 Response response = target.request().get();

 List <Customer> customers = response.readEntity(new GenericType<list<Customer>>() {});

Note that in order to unmarshall returned content, the object type needs to be known. However generics information is not available at runtime, and therefore it becomes tricky to unmarshall the content. To get round this we need to declare a GenericType.

Create a New Customer (POST)

To create a new Resource on the Server, i.e. a new Customer instance, we need to use the HTTP POST operation.
 @POST
 @Path("/customer")
 @Consumes("application/*+xml")
 public Response createCustomer (Customer customer) throws URISyntaxException{    
  final int customerId = backendService.createCustomer(customer);
  return Response.status(201).contentLocation(new URI("/customer/"+customerId)).build();
 }


In this example we pass an instance of Customer as an argument to the method. This instance is subsequently passed onto the backend. To finish a response is returned with a HTTP code of 201 (indicates resource has been created).  Additionally the response will contain an a URI address which will enable the Client to access the newly created Customer instance.

The Client code executes the request in the following way:
        
 WebTarget target = client.target("http://localhost:8080/RESTfulBookstore/bookstoreService/customer/");

 final Customer newCustomer = new Customer("Fred", "Bloggs", "fbloggs@internet.com", "07851 444 555", "fbloggs");

 Response response = target.request().post(Entity.entity(newCustomer, "application/*+xml"));

Note that here we invoke the post() method instead of get() as before.

Update Existing Customer (PUT)

To edit an existing resource, i.e. update the Customer details we need to use the HTTP PUT operation.

 @PUT
 @Path("/customer/{id}")
 @Consumes("application/*+xml")
 public Response updateCustomer (@PathParam("id") int id, Customer newCustomer) throws URISyntaxException{

  final Customer existingCustomer = backendService.getCustomer(id);
  
  if(existingCustomer == null) {
   logger.warn("SERVER updateCustomer NO CUSTOMER FOUND: " + existingCustomer);   
   throw new WebApplicationException(Response.Status.NOT_FOUND);
  }
  
  
  existingCustomer.setEmail(newCustomer.getEmail());
  existingCustomer.setMobileNumber(newCustomer.getMobileNumber());
  existingCustomer.setPassword(newCustomer.getPassword());
  
  return Response.status(201).contentLocation(new URI("/customer/"+ newCustomer.getUserId())).build();
 }
 
The method uses the Customer id to perform a lookup. If it manages to retrieve the matching Customer instance, it will overwrite existing properties. To finish, it will return a 201 status and provide the URI location of the updated Customer instance.

The Client code executes the request in the following way:

 
 WebTarget target2 = client.target("http://localhost:8080/RESTfulBookstore/bookstoreService/customer/"+String.valueOf(customerId));
 Response response2 = target2.request().put(Entity.entity(customer, "application/*+xml"));

Note that in this case, we invoke the put() method on the Client interface.

Delete Existing Customer (DELETE)

The final example focusses on the HTTP DELETE operation.

 @DELETE
 @Path("/customer/{id}")
 public Response deleteCustomer (@PathParam("id") int id) throws URISyntaxException{

  final Customer existingCustomer = backendService.getCustomer(id);
  
  if(existingCustomer == null) {
   logger.warn("SERVER deleteCustomer NO CUSTOMER FOUND: " + existingCustomer);   
   throw new WebApplicationException(Response.Status.NOT_FOUND);
  }
  

  backendService.deleteCustomer(id);

  return Response.status(200).build();
 }


The method takes the customer id and invokes a method on back-end code to delete the corresponding Customer instance. The response returned contains a 200 status indicating to the client that the request was processed correctly without errors.

The Client code executes the request in the following way:

 WebTarget target2 = client.target("http://localhost:8080/RESTfulBookstore/bookstoreService/customer/"+String.valueOf(customerId));
 Response response2 = target2.request().delete();


Again note that we tell the Client class that we want fire off a HTTP DELETE request by invoking the delete() method.

The following shows output from firing of a get() for a customer with id of 2.




This completes the tutorial on implementing a RESTful service using resteasy. Any comments relating to corrections, omissions, etc are welcome.

Wednesday, 25 June 2014

Spring Integration - Building a Sample Application

Introduction


Spring Integration (SI) is a framework enabling a collection of individual applications to integrate together to deliver a business enterprise system. The framework is essentially a lightweight messaging system that enables spring based applications to communicate with one another and supports integration with external systems via declarative adaptors. It is based on the 'filters and pipes' design architecture. A key feature of it is that it achieves this integration in a minimally intrusive way.

The framework is built on 3 main components:
  • Messages
    • Encapsulate the data to be transferred from one place to another. They comprise of a header (holds meta data such as message-id, timestamp, etc) and a payload (your data typically in the form of a POJO). 
  • Channels
    • Provide a mechanism to transport messages from one endpoint to another. Represents the pipes in the pipes & filters architecture. SI offers two types of channels, namely Pollable and Subscribable Channels. The former rely on consumers to periodically check for messages whereas the latter is directly responsible for notifying registered consumers when messages become available.
  • Endpoints
    • Consumer/Producer of messages. Performs some action based on the payload. Endpoints come in various flavours, each performing a different function. These include Transformers (transform data), Routers (route data), Filters (filter data), Splitter (splits messages), Aggregator (aggregates group of messages into single message), Service Activator (connecting messages to Services) and Channel Adapters (connect channels to external applications).

The basic idea behind the SI framework is that applications communicate with each other by sending/receiving messages. These messages would typically contain the information (payload) required by the next application in the process pipeline. The transport of messages from one application to another is performed by Channel components. The Endpoints perform some action based on the payload. This could be routing the messages to another endpoint or processing the payload itself.

The objective of this post is to provide an introduction to Spring Integration. To help achieve this, I developed a sample application which will be discussed below. The source for this sample application is available at here. The project was built and run using spring-integration-4.0.0, maven 3.2.1 and jdk1.6.

The main dependency is for the relevant spring-integration jar as declared in the pom.xml:

 
  
   org.springframework.integration
   spring-integration-stream
   4.0.0.RC1
  
 
I ran the application using the maven exec plugin. This allows me to clean, package and run the application by invoking

 mvn clean package exec:java -P OnlineShop

from the command line. 


Developing a sample application: Tabernus

My goal as usual was to build something very simple which would help me to become familiar with key concepts of this framework and to this end I've knocked up a simple app which does not connect up individual systems but rather invokes methods on a POJO. Extending this to actual working applications shouldn't be too difficult.

The scenario I'm going to model revolves around purchasing items from an online store (Tabernus). This store only sells 3 types of items: Books, Music CDs, and software. During a Sale, the owners have decided to apply different discounts based on the item type. In this instance books, music and software benefit from discounts of 5%, 10%, and 15% respectively.

The following diagram shows our domain entities.




The class diagram shows that a Customer can place an Order comprising of a number of OrderItems which are of type Book, MusicCD or Software. The problem I need to solve is to design a system which can interrogate each Order and apply the correct discount based on the item type. Subsequently it should be able to compute the total cost of the order once the discounts have been applied.

To model this using Spring Integration we need the following pipeline





The above diagram shows various components most of which can be divided into 2 categories, channels (blue cylinder shapes) and endpoints (rectangular boxes).  The exception to this is the Poller component whose purpose is to enable the various endpoints to function correctly and discussion of it will be given later.

We'll start off by briefly covering the various stages in this pipeline as indicated by the numbers in red. Following this we will delve deeper into how we build this pipeline using the SI framework.

The pipeline is comprised of 6 major stages as reflected by the numbers in the diagram,

  1. The Gateway component represents the entry point to the messaging system. All new Orders will be submitted to this component which will in turn wrap them as messages and place them into the channel appropriately named ordersChannel.
  2. Using the Splitter component - each Order is decomposed into a collection of it's constituent OrderItem instances. Each of these is wrapped in a Message and placed in the orderItemsChannel.
  3. The Router component considers each OrderItem in turn and places it in the relevant channel, e.g. Book items will be placed in the bookItemsChannel etc. This allows us to consider the different item types separately.
  4. The ServiceActivator needs to consider messages within each of the 3 channels and calculate the correct discount based on the channel. After completing the calculation for each OrderItem, it will place the OrderItem in the processedItemsChannel.
  5. The Aggregator component will collect all OrderItem instances placed in the processedItemsChannel and reconstruct the original Order. This will subsequently be placed in the deliveriesChannel, which represents the end of the pipeline.
  6. The Poller Component is required to configure how often the various endpoints will interrogate their respective input channels for messages.

To implement the pipeline shown above using the SI framework, we need to
  1. implement the various end points.
  2. configure the pipeline in an xml file (Shop.xml) - identifying the various channels and endpoints and how they wire up together.
At this point I should mention that SI offers 2 approach to configuring your process pipeline, annotations based and xml. In this article I'll be using the latter.

Let's start to look at some code. We'll consider each stage described above and show the java implementation of the endpoint and xml configuration required to wire up the components.

Step 1 - Gateway

To begin with, we need to implement the Client that will invoke the Gateway component to place the Order. The client (OnlineShop.java) is shown below,

public class OnlineShop {
 
 public static void main(String[] args) {

  AbstractApplicationContext context =
   new ClassPathXmlApplicationContext("/META-INF/com/prodcod/shop.xml", OnlineShop.class);

  Shop shop = (Shop) context.getBean("shop");
  
  final Order order = createOrder();
  
  shop.placeOrder(order);
  
  context.close();
 }


The logic here is quite simple. The client creates a dummy Order and passes this as an argument when it invokes the placeOrder() method on the gateway component. The gateway  component referred here as Shop is injected by Spring.

The Gateway component looks like:

// Gateway component
public interface Shop {

 @Gateway(requestChannel="ordersChannel")
 void placeOrder(Order order);

}


As you can see, this is simply an interface, whose implementation will be provided by Spring when it is injected into the client application. This is achieved by the use of the @Gateway annotation which informs Spring that this is a Gateway component and it needs to provide the implementation. Additionally the annotation accepts an attribute, requestChannel which defines the channel on which the Order instance will be placed. The framework does this by simply wrapping our instance of Order within a Message instance and placing it in the channel, 'ordersChannel'.

The Gateway component and the 'ordersChannel' are declared as follows in the file shop.xml



 
 
 

Step 2 - Splitter

The next end point is the Splitter component. Appropriately named, it's role is to take a single message containing a payload of a collection of items and splitting it into a number of messages, each of which contains a single element from the collection. In our case, we want to decompose the Order into it's constituent OrderItem instances. It does this by taking a Message containing the payload of Order from 'ordersChannel' and then processing it before sending messages (each containing an OrderItem instance) to the 'orderItemsChannel'.  Our implementation of the splitter is called OrderSplitter and is defined as below,

public class OrderSplitter extends AbstractMessageSplitter{

 @Override
 protected Object splitMessage(Message message) { 
  return ((Order)message.getPayload()).getOrderItems();
 }

}

Implementing a splitter is quite easy and involves extending the AbstractMessageSplitter class and overriding the splitMessage() method. This simply takes a message containing the payload of Order and returns it's collection of OrderItems.


Step 3 - Router

Having decomposed the Order into it's constituent OrderItems, we now need to separate them into groups of Books, MusicCD, and Software. This is achieved using a router. Our implementation of the Router looks like,

public class OrderItemRouter {

 public String routeOrder(OrderItem orderItem) {
  
  String channel = "";
  if(isBook(orderItem)) {
   channel = "bookItemsChannel";
  }
  else if(isMusic(orderItem)) {
   channel = "musicItemsChannel";
  }
  else if(isSoftware(orderItem)) {
   channel = "softwareItemsChannel";
  }

  return channel;
  }
 
 .....................
 .....................

 }

Nothing too complicated here. For each OrderItem, the method routeOrder() will determine it's item type and return the name of the channel that this message should be sent to. The channel name is returned by the method. Spring will then ensure that the message containing the OrderItem is relayed to the named channel.

The configuration for OrderItemRouter looks like,

 
 


The config identifies that the class OrderItemRouter is a Router component which will consume messages from the orderItemsChannel. Further Spring needs to invoke the method routeOrder() which contains the logic to perform the routing.

The channels for each item type are declared as follows
 

  



  



  

Step 4 - ServiceActivator

The next step is to calculate the discounted price for each item type and this is performed by a ServiceActivator component. This is implemented as follows

public class Shopkeeper {

 private static final BigDecimal BOOK_DISCOUNT = new BigDecimal(0.05);
 private static final BigDecimal MUSIC_DISCOUNT = new BigDecimal(0.10);
 private static final BigDecimal SOFTWARE_DISCOUNT = new BigDecimal(0.15);

 /**
  * Performs discount on books
  * @param bookOrderItem OrderItem comprising of a book item
  * @return OrderItem with discount price newly calculated
  */
 public OrderItem processBooks(OrderItem bookOrderItem){  

  final BigDecimal finalPrice = calculateDiscountedPrice(bookOrderItem, BOOK_DISCOUNT);
    
  bookOrderItem.setDiscountedPrice(finalPrice);

  return bookOrderItem;
 }
 
 /**
  * Performs discount on music
  * @param musicOrderItem OrderItem comprising of a music item
  * @return OrderItem with discount price newly calculated
  */
 public  OrderItem processMusic(OrderItem musicOrderItem){  

  final BigDecimal finalPrice = calculateDiscountedPrice(musicOrderItem, MUSIC_DISCOUNT);

  musicOrderItem.setDiscountedPrice(finalPrice);
   
  return musicOrderItem;
 }

 /**
  * Performs discount on software
  * @param softwareOrderItem OrderItem comprising of a book item
  * @return OrderItem with discount price newly calculated
  */
 public  OrderItem processSoftware(OrderItem softwareOrderItem){  

  final BigDecimal finalPrice = calculateDiscountedPrice(softwareOrderItem, SOFTWARE_DISCOUNT);
  
  softwareOrderItem.setDiscountedPrice(finalPrice);
  
  return softwareOrderItem;
 }
}

This class exposes 3 methods to compute the new discounted price for each item type. Each method returns the OrderItem instance with the new price. The ServiceActivator is configured as follows:
 

 

 

 


This tells Spring that the Shopkeeper class is a ServiceActivator and will consume messages from any of the 3 channels defined in the input-channel attribute. When a message appears in one of these channels, Spring will invoke the appropriate method on the ServiceActivator class as specfied by the attribute method. Anything returned from all three methods will be placed in the processedItems channel, ready for the next step of the processing pipeline.

Step 5 - Aggregator

The final stage is to take the individual OrderItems with their newly computed discounted prices and reconstruct the Order. This is achieved using an aggregator. Our implementation of an aggregator is listed below

public class OrderCompleter {
 
  public Order prepareDelivery(List orderItems) {
         final Order order = new Order();
         order.setOrderItems(orderItems);  
         return order;
  }
}

The aggregator exposes a method that takes a collection of OrderItem objects. These will come from the processedItems channel declared as
 

Recall this is the output channel for the service activator class as discussed above. The aggregator is configured in the xml file as

 



The configuration tells Spring that the aggregator component will consume messages from the processedItems channel. These will be processed by the method prepareDelivery on the class OrderCompleter. Any output from this class will be relayed to the channel-adaptor deliveries, which is declared as
  



The stdout-channel-adapter component writes to the systems STDOUT output stream.

Step 6 - Poller

To complete the setup we have to configure a poller component. This is required to enable the channels to work correctly.  All our channels are of a queue type and so their respective consumers need to know when to query them. This is achieved using a poller mechanism. It is configured in the following way

  


In this case,  we have declared a global poller (as indicated by the default attribute). This will be used by the various end points to determine when they should interrogate their respective input-channels for messages. The second attribute fixed-delay is used to configure the polling interval.

Running the Application


Building and running the app shows the following output:


The logging shows that the Customer submitted an Order for 3 items, one of each type. All items cost £100 each. The Order was then split into 3 OrderItems each of which was routed to the correct processing channel based on the item type. The ServiceActivator (Shopkeeper) then calculated the discount for each item and this was set on the OrderItem instance. The OrderItems were then aggregated using the OrderCompleter class which displays the final discounted price of £270 to be paid by the Customer. Note that the messages are logged to be in different stages of the processing pipeline despite starting off in the same order.

This completes the tutorial on the Spring Integration Framework. Any comments relating to corrections, omissions, etc are welcome.

Monday, 23 June 2014

AngularJS - Developing a Sample Application (with a RESTful service)

Introduction

AngularJS is a MVC framework for building dynamic web apps. This means your web application is comprised of Models, Views and Controllers. Models are typically javascript objects storing your application data, Views are html pages providing a visual representation of said data, and Controllers are javascript functions that handle data (i.e. retrieving from server; make it available to the view) and respond to events. AngularJS offers a number of benefits including but not limited to:

  • Easy to get started within minutes. You can knock up a simple AngularJS application very quickly by executing a small number of steps.
  • 2 way data-binding. The Model and View are kept in sync without having to write wrappers, getters/setters. This is done automatically so you don't have to do anything.
  • Dependency Injection. The Angular injector module is responsible for creating components, resolving their dependencies and providing them to other components when requested.
  • Extends html through the use of directives. This offers a lot of power by triggering new behaviour based on newly created syntax that you write.
  • Simplifies calls to the server via REST. In a single line you can invoke a call to the server.
  • Easy to test.


To better acquaint myself with angular, I built a very simple 4 page application, flights 'R' us, which enables a user to book a return flight to various destinations in Europe. 

Figure 1: Form to specify Customer requirements

Figure 1 shows the first page. It presents a form to capture basic information such as destination and departure locations, dates for the flights and number of passengers. Note that the drop downs for Destination and Departure are chained, so that selecting a specific destination will ensure that the Departure drop down is populated with valid locations. Hitting the 'Submit' button causes the form to be submitted and takes the user to page 2, shown below.


Figure 2: List of possible flights

Page 2 shows a list of possible flights to the required destination from the specified departure airport. The list is generated by querying a RESTful service when the form on page 1 is submitted. The user makes a selection by hitting the 'Select' button in the appropriate row. This leads to the next page as shown in figure 3.




Figure 3: Flight Summary, Personal & Payment details form


Figure 3 shows summary details for the selected flight and presents a form to capture personal and payment details.


Figure 4: Order Confirmation Page


Figure 4 shows the final page, once the user has submitted the form on page 3 by hitting the 'Book Now' button.

The following sections will provide a discussion on how this application was built using AngularJS. This will not provide a step-by-step account on how to build the application, but rather an autopsy to highlight key elements of an AngularJS application.

Developing a Sample Application

The sample application, flights'R'us was built as 2 projects, one to provide the UI and the other a RESTful service. The UI project was developed using AngularJS (1.3.0) and Bootstrap (3.1.1) to make it more visually appealing. The RESTful service was developed using RESTeasy 3.0.5, java 1.6 and was deployed under JBOSS AS 7.3. The source code for both are available here. The discussion in this post focusses mainly on the AngularJS application and does not rely much on knowing REST.

As part of the learning experience of building an AngularJS application from scratch, I managed to identify key points which I felt are important in developing such an application. This list is by no means complete but should provide enough understanding to help you (hopefully) with your projects. The key steps are detailed in the following sections.

Bootstrapping

One of the most attractive features of AngularJS, is just how quickly you can knock up a sample application with very little effort. The flights'R'us application comprises of a single javascript file (app.js) and a number of html files, the main one being FlightsRus.html. This file defines the main layout for the application and looks something like this,

//FlightsRus.html
< html ng-app="myApp">

  
  
< /head>

< body>
   
   

Flights 'R' Us

Number 1 in Flight booking
< /body> < /html>

The main things to note here are,
  1. The use of 'ng-app' directive. This identifies the application as being an AngularJS application and makes available all resources and services provided by AngularJS. 
  2. The declaration to import the AngularJS library (angular.min.js) and a javascript file (app.js) containing all our code.
  3. The use of 'ng-view' directive. This is used to inject html templates at this location. We can use this in conjunction with the ng-routes module (more on this later) to replicate a multi-page application.
The ng-app directive mentioned above specifies a value of 'myApp'. This is a reference to the root module of our application. A module is effectively a container for the different components of our application such as controllers, services, directives etc. It offers many benefits, including,
  • providing a declarative way to bootstrap an application. Typically most applications have a main method that is responsible for wiring up all dependencies. With AngularJS you have more flexibility.
  • a way to package code as reusable units.
  • ability to load modules in any order.
  • faster testing since tests only need to load relevant modules.
The 'myApp' module is declared in the app.js file and is defined as follows

var app = angular.module('myApp', []);

The module constructor can take 3 arguments. In this instance we supply 2 arguments, the name of the module ('myApp'), and a list of modules upon which the myApp module depends on. This has been left empty for now but will be populated with relevant entries as we explain various aspects of the application in later sections.

One thing to note about the module constructor (from the docs):
When passed two or more arguments, a new module is created. If passed only one argument, an existing module (the name passed as the first argument to module) is retrieved.

DataBinding - Introducing $scope

A common problem with web applications involves binding data captured in html forms to domain objects. With many frameworks you have to write extra code to handle this. Fortunately AngularJS offers a simple but effective mechanism, the $scope object,  for binding data objects to form fields. To help explain this, I'm going to focus on the text field to capture the number of Adult passengers in the form shown in figure 1.

The View is defined as,
      

This looks like a typical HTML form except that the input field has an extra attribute, ng-model which is assigned a value of "formDetails.numAdults". AngularJS will ensure that any text entered in to the input field is stored in the numAdults property of the object literal formDetails. This data object is defined within the controller managing this view, which is defined as,

app.controller('FlightsFormController', ['$scope', function($scope) {
   console.log('Form Details # adults: ' + $scope.formDetails.numAdults);
}

The .controller() method configures a controller for the module. It takes a number of arguments, the first of which specifies the name of the controller. The following array of values include a list of services to be injected into the controller ($scope in the present case) and a function defining the implementation of the controller. $scope is an object that refers to the application model and enables objects and functions to be shared between the controller and view. In this instance, I want to share the formDetails object literal (and all it's properties) between my Controller and View. For now I'm not doing anything with the numAdults field other than printing it's value to the console log.

Calling the Server - $http

Staying with figure 1, notice the 2 drop down boxes for Destination and Departure. As expected, these are populated with Destination and Departure values. There are 2 points to be made here. Firstly the app is data driven so these values are retrieved from a server. Secondly they form a chained select control, so that making a selection on the Destination drop down, will cause the values on the Departure drop down to change accordingly.

To populate the drop downs we're going to have to make a call to a RESTful service. Again with AngularJS, this is so easy. Looking inside the FlightsFormController definition, we find

   
$http.get('http://localhost:8080/RESTflightsRus/flightsRusService/allroutes').
  success(function(data) {
    $scope.destinations = data;
    console.log('allRoutes: ' + data);
 });

This statement uses the $http service provided by AngularJS to invoke a HTTP GET request to my dummy RESTful service (deployed at the specified URL). It provides 2 callback functions, success() and error(). Only the former is shown. These are invoked when the Server returns a response. In the event everything is ok, the success() function is executed and conversely if something goes wrong, the error() function will be invoked. In this instance, if the server successfully returns our data, we assign the results to the destinations property which is attached to the $scope object and therefore available to our views. The data is in json format and looks something like:


[
  { "name" : "Majorca",
    "departures" : [{"name" : "London"}] 
  },
  {
     "name" : "Algarve",
     "departures" : [{"name" : "Newcastle"}]
  },
  {
     "name" : "Costa Del Sol",
    "departures" : [{"name" : "Birmingham"}]
  },
  {
     "name" : "Barcelona",
    "departures" : [{"name" : "East Midlands"},{"name" : "Bristol"}]
  },
  {
     "name" : "Tenerife",
    "departures" : [{"name" : "London"},{"name" : "Newcastle"},{"name":"East Midlands"}]  }
]

To access the $http service, we need to get AngularJS to inject it into the controller. This is done by modifying the controller declaration as follows:

app.controller('FlightsFormController', ['$scope', '$http', function($scope, $http) {

It's clear from this example, that Angular is also very efficient since it injects only those services that we require in the current context rather than bloating our code with a whole bunch of unnecessary dependencies.

To populate the Destination drop down in the view, we implement the select control in the following way
 


In this example, the select control displays a list of options dynamically generated by the ng-options attribute which contains the statement:
c.name for c in destinations

Recall that destinations was previously retrieved from our RESTful service as discussed above and subsequently attached to the $scope parameter thus making it available to the view. The expression involves iterating through the destinations array and extracting the name property for each entry. The resulting collection is then displayed in the drop-down. When the user selects a value, this will be stored in the property formDetails.destination which is also attached to the $scope object.

In order to populate the second dropdown (Departures) based on the selection of the Destination drop down we do the following:
 


In this instance the ng-options expression is
p.name for p in formDetails.destination.departures
The expression takes the value selected by the user in the first drop-down (destination) and loops through it's corresponding set of departure values. For each entry it simply extracts the name of the departure location. The resulting collection of departure values are then displayed in the drop down. The user's selection is stored in the variable, formDetails.departure.

One final point before we move onto the remaining pages of the application. The date fields, fromDate and toDate will render a popup calendar if the application is viewed in Chrome, but fail to materialise in FF. This is because FF does not support the input fields of type 'date', hence it reverts to behaving like a regular text field.

Multiple Pages - ngRoute

Although AngularJS is often referred to as a Single Page Application (SPA), it is still possible to develop a multi page application. This is done using the <ng-view> directive mentioned above and the ngRoute service provided by AngularJS.

Before we can use the ngRoute module, we need to declare the dependency in the declaration for the module,

var app = angular.module('myApp', ['ngRoute']);

The ngRoute module makes available a service object, $routeProvider which enables us to wire together controllers and views and map them to the URL location. Inspecting the app.js file, you'll find the following lines of code,

//configure routing
app.config(function($routeProvider) {
 $routeProvider.when("/",
   {
    templateUrl: 'FlightForm.html',
    controller: 'FlightsFormController'
   }
 )
 .when("/flightOptions",
   {
    templateUrl: 'FlightOptionsList.html',
    controller: 'flightOptionsController'
   }
 ) 
 .when("/order",
   {
    templateUrl: 'FlightOrder.html',
    controller: 'flightOrderController'
   }
 ) 
 .when("/confirmation",
   {
    templateUrl: 'OrderConfirmation.html',
    controller: 'OrderConfirmationController'
   }
 ); 

});


This snippet shows a chained set of when() methods being invoked on the $routeProvider object. Each when() method links the URL to it's corresponding pair of View template and Controller.

To force a page change, we use the $location service and invoke it's path(URL) method, i.e.
$location.path('/flightOptions');

When the .path(URL) method is invoked, the $routeProvider uses the URL to work out which pair of controller & view components need to be deployed. The template is then rendered inside the main layout (FlightsRus.html) file using the <ng-view> directive mentioned previously. In this way each time the URL changes, the included view changes with it based on the configuration of the $routeProvider object.

The $location service is accessed by getting AngularJS to inject it into the Controller. This is achieved by modifying the controller declaration to:

app.controller('FlightsFormController', ['$scope', '$http',  '$location', function($scope, $http, $location) {


Sharing Data between controllers - .factory()

A common problem in web application development is sharing data across widgets and pages. AngularJS offers a very simple but effective mechanism to achieve this in the form of Services. A Service is an encapsulation of methods that relate to a specific function. In our case, we want our service to cache data between pages.

The simplest way to create a service is to use the module.factory() method. Let's illustrate this with some code. At the top of the app.js file, you will find the following declaration:

//configure service for passing data between controllers
app.factory('dataService', function() {

 var flightOptions = [];

 var addFlights = function(newObj) {
  flightOptions = newObj;

 };

 var getFlights= function() {
  return flightOptions;
 };

 return {
  addFlights : addFlights,
  getFlights : getFlights,
 };
});


Here we present a simplified version of the code. We pass 2 arguments into the factory method, the first being the name of the service followed by it's implementation. In this instance our service declares an array literal and exposes methods to add/retrieve entries from that literal. Once this service is available, we can push and pull data from this common data store at different points in our application. By defining the Service in this way, we have registered it with the AngularJS compiler so that it can reference it and load it as a dependency at runtime.

To demonstrate how this service is employed, we focus on the switch between pages one (figure 1) and two (figure 2) of the application. On page one, the user fills in a form specifying trip details. On hitting the submit button, the managing controller (FlightsFormController) calls the RESTful service for a list of possible flights as shown below.

//define controller for main form
app.controller('FlightsFormController', ['$scope', '$http', 'dataService', '$location', function($scope, $http, dataService, $location) {
 .................
 .................

     $scope.submit = function() {

     $http.get("http://localhost:8080/RESTflightsRus/flightsRusService/flightoptions/?" + "departure=" + $scope.formDetails.departure.name +
                "&destination="+$scope.formDetails.destination.name+
                "&fromDate="   +$scope.formDetails.fromDate+
                "&toDate="     +$scope.formDetails.toDate+     
                "&numAdults="     +$scope.formDetails.numAdults+     
                "&numChildren="     +$scope.formDetails.numChildren).     
                success(function(data) {
                     dataService.addFlights(data);
                     $location.path('/flightOptions');
              });

 .................
 .................

 };
}

The RESTful service replies by returning a list of all possible flights. At this point, we want to cache the results of the call to the RESTful service. This is achieved by injecting the 'dataService' object into the controller as seen in line 2. The data is then added to the cache by invoking the addFlights() method on 'dataService' (line 15). The form submission process completes by navigating to page 2 (/flightOptions) where the list of all possible flights is to be displayed.

Page two is managed by the 'flightOptionsController' as declared below.

//define controller for flightOptions
app.controller('flightOptionsController', ['$scope', 'dataService', '$location', function ($scope, dataService, $location) {

 $scope.dataService = dataService;

 $scope.flightOptions = dataService.getFlights();

 $scope.selectedFlight = function(flightDetails) {
  dataService.setFlightDetails(flightDetails);
  $location.path('/order');
 };

}]);


As before, we have to tell AngularJS to inject in our 'dataService'. Then within the body of declaration, we simply invoke the getter method on 'dataService' to retrieve the cached data and set this in $scope variable, enabling the View to access the data.

The View subsequently displays this data using the <ng-repeat> directive as shown below,
 
  <tr ng-repeat='flightOption in flightOptions'>
      <td> {{flightOption.flightNumber}} 
       ...........................................
       ...........................................
  </tr>    



Validation

Another key requirement for any form based web application is to provide client side validation. Fortunately with AngularJS, it is possible to create forms that are interactive and immediately responsive leading to enhanced usability.

The implementation of any form begins with the <form> declaration:
 

The tag has 2 attributes, name and novalidate. The latter is required to disable the browser's native form validation. The former in conjunction with the name attribute on form elements is required to enable AngularJS to correctly bind validation messages to their parent form fields.

AngularJS offers 2 levels of validation, out-of-the-box and custom. In the first case, an input element can be configured to validate a number of things,

  
    

The attributes ng-minlength, and ng-maxlength specify the minimum and maximum lengths respectively of any value entered into this field. If the user enters a value that does not meet these criteria they will be prompted with an appropriate validation message. The ng-pattern attribute forces the input field to raise a validation error if the entered value does not match the REGEX expression provided. Lastly the required field indicates to AngularJS that this is a mandatory field and requires a value. Note that this input field is specified as having a type 'text'. It is possible to define other types such as date and email. In the latter case, AngularJS will perform the check that the entered value resembles the format expected from an email address and will display a validation message if it is not.

Before we go any further, it's helpful to point out that input fields in AngularJS can occupy any one of the following states based on user interaction:
  • $valid : The value entered into the input field is valid
  • $invalid : The value entered into the input field is not valid
  • $pristine: no value has been entered into the input field.
  • $dirty : Indicates if the user has interacted with the input field
  • $touched : The user has focussed on the input element and then shifted focus away from the element.
Note that each state is represented by a boolean value.

The next step is to configure how the validation messages will be displayed and this has been facilitated by the introduction of the ng-messages module in the latest release of Angular. To use this package, we have to identify it as a dependency module by adding another entry to the module declaration like so,

var app = angular.module('myApp', ['ngRoute', 'ngMessages']);

Following this, we have to attach the validation messages to each input field. To illustrate this, we'll focus on the email field (emailInput),

 

* required
invalid email

The main points to note from this snippet is that the input field has an ancestor div that can be styled to highlight validation problems (e.g. adding a red border around the element)  and a sibling div which holds the validation messages. Let's discuss these in turn, beginning with the ancestor div.

The outermost div has an attribute ng-class, which allows us to dynamically apply a style based on the state of the input field. In this instance we apply the class 'has-error' (a bootstrap style) if the statement

personalDetailsForm.emailInput.$invalid && personalDetailsForm.emailInput.$dirty

evaluates to true. Here we are testing two conditions. The first of these checks whether the value entered into the input field has rendered it in an invalid state. The second conditional tests if the email Input field has been modified in anyway; this ensures that a validation message is not displayed until after the User has interacted with it. The end result is that the User is not presented with misleading validation messages even before they've had a chance to fill in the form.

Now let's move on to discussing the sibling div containing the validation messages. This div has an attribute ng-messages which takes the value

personalDetailsForm.emailInput.$error.

The value is formed by appending the names of the form (personalDetailsForm) and input field (emailInput) to the state of the field ($error). AngularJS uses the value assigned to the ng-messages attribute to correctly link Validation messages with their parent field(s) when a validation error occurs.

This div contains a number of other divs, each of which relates to an individual validation error. The child divs have content which forms the validation message and an ng-message attribute that identifies the type of validation error.

 For example, in our case we have 2 possible error states,
  1. When the user fails to provide an email (required). In this case AngularJS will display the message '* required'. 
  2. User provides an email that does not conform to the expected format (email). If this error state is triggered, AngularJS will display the message 'invalid email'.
If the set of validation checks listed is not sufficient, it is always possible to roll your own Validation checks using the directive feature of AngularJS.

Building a custom validator is reasonably straightforward. The first step is to create a directive. This is essentially an AngularJS construct that allows us to extend html. The following shows the custom validator built for the mobile phone field. The restriction on this field is an imaginary one and revolves around constraining phone numbers to only those with a prefix of '0781'.  Note that even though the validation performed by the custom validator is simple and could have been implemented using the ng-pattern attribute, we use it here simply to demonstrate the power of directives.

//create directive to perform custom validation
var MOBILE_REGEXP = /^0781/;
app.directive('mobile', function() {
  return {
    require: 'ngModel',
    link: function(scope, elm, attrs, ctrl) {
      ctrl.$parsers.unshift(function(inputValue) {
        if (MOBILE_REGEXP.test(inputValue)) {
          // it is valid
          ctrl.$setValidity('mobile', true);
          return inputValue;
        } else {
          // it is invalid
          ctrl.$setValidity('mobile', false);
          return undefined;
        }
      });
    }
  };
});

In this case we are defining a directive, 'mobile' which will be used as an attribute on the input field. This directive performs a test on the value entered into the input field (inputValue) against the regex expression defined by MOBILE_REGEXP. The outcome of the test, whether successful or not is used to set the validity of the field (via  $setValidity()) and to notify the form of this.

To use the new validator, simply add it as an attribute to the relevant input field,
 


The corresponding validation message can be declared in the following way.
 
Needs to start with 0781

On a final note, AngularJS offers a way to disable form submission until all validation issues have been resolved by the user. This is achieved using the ng-disabled attribute as show below
  

The ng-click attribute will ensure that AngularJS invokes the submit() method defined in the parent controller when the button is clicked. The ng-disabled attribute will disable the button if the form with the name personalDetailsForm is rendered in an invalid state. Once the user has corrected any erroneous entries, the form will be in a valid state and the button will resume an active state.

This completes the discussion on building a sample AngularJS application.

Conclusion

In this post, I've covered some salient points around developing a sample application using AngularJS. There are many other topics I could have included such as filters, project structure, etc. but lack of time prevents this. My initial impressions of AngularJS are favourable. Some of the key-points are

  • Databinding. I love not having to write extra code to ensure the data is sync'ed between View and Controller
  • Dependency Injection. It's great to be able to inject your dependencies in a declarative manner.
  • Access to services such as $http. This removes the need to roll your own.
  • The basic core features and functionality make it so easy and such a pleasure to work with.
  • Everything seems so intuitive.

Any comments relating to corrections, omissions, etc are welcome.