Angular.js + Vert.x-web Rest Services -with NetBeans-8

Madanasekaran.P

Angular.js the most popular open-source client side JavaScript MVC framework sponsored and maintained by Google; it was seen in a number of articles. Vertx-web is an extension to Vert.x that makes the development of Vert.x- based web applications easier. It comes with some templates-Jade, Handlebar, MVEL etc. But you can use any view technology with it. We will use Angular.js, which has been used in some of the largest and most complex web applications. As mentioned earlier, Angular.js just enhances HTML through directives and confers on HTML tags new capabilities and does not use any other template technology. We will see some more aspects of Angular.js, before seeing Vert.x Web, which is. In AngularJS 1.2 and later, there is a new syntax, the controllerAs” syntax, which allows us to define the variables on the controller instance using the “this” keyword, and refer to them through the controller from the HTML. This has some advantage of over “$scope”, which can be also used as a glue between controller and view. The new approach makes it explicit in the HTML which variable or function is provided by which controller and which instance of the controller. So with a complicated, nested UI, it becomes immediately obvious because the controller instance is present in the HTML. Another discussion in Angular.js circles is on the advantages / disadvantages of using a simple $http request to a server versus using a “ngResource” object. As we saw in our earlier examples, for a RESTful interface “ngResource”, being a higher abstraction, cuts down a lot of boiler-plate. But the $http requests, being low level, are very flexible and configurable. We can attach callback functions to the promise returned by http using “then”. The function to handle “error” can be attached and it can be very useful. This will make our code more verbose when compared to the code using “ngResource”; but for a small application like ours one can put up with some verbosity for gaining “error-handling”.

Vertx-web:

Vert.x documentation describes it as a Swiss Army Knife for building modern, scalable, web apps. It is inspired by Express in the Node.js world, which in turn was inspired by Sinatra in the Ruby world. You can use Vert.x-Web to create any type of web applications. Vertx-web contains all the things one would expect from an advanced web framework- cookies and session handling, pluggable auth, templates, web-sockets, support for SockJS, content negotiation and many, many more features. It's a great fit for whatever kind of web application, whether a 'traditional' server rendered web application, an HTTP/REST micro-service/self-contained service, or a client rendered web application, or a real-time server push web app.  As we will see in our sample, Vert.x-Web is a great fit for writing RESTful HTTP micro-services. Tim Fox explainedthat micro-services” as a reaction against and the opposite of the JEE model of having a monolithic server sitting somewhere on the network into which you deploy your application packaged as a jar or an ear. He said “From day one Vert.x has always been about writing your code as self contained services, in whatever language you want and running them wherever you want without having to first have an "infrastructure" or "appserver" pre-deployed there”. Node was created in 2008 and Vert.x in 2011. In 2014 there was a paper on Micro-services by Martin Fowler. After that, the services provided by the above frameworks are categorized as self-contained services. So to satisfy new definition of micro-services, new modules have been introduced in Vertx and we will see about them later.

Sample. We will create the sample in NetBeans-8.This will save us from the trouble of manually creating the directory structure required by Maven. The help of the IDE’s editor is also available through tips and error checking.  So we can use the following steps:

File-> New Project->Maven->Project from Archetype.

The New Project Wizard will appear.

Figure-1

Choose “vertx-java-archetype”.It will appear as in Figure-1.Click Next.In the Wizard that follows give a project name and accept default for others. If you click “Finish”, a minimal project will be generated.

 The generated “pom.xml” has to be modified. Otherwise if you “Clean and Build” you may see the following error:

Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.3.2:exec (default) on project mvnVertx: The parameters 'executable' for goal org.codehaus.mojo:exec-maven-plugin:1.3.2:exec are missing or invalid -> [Help 1]
To see the full stack trace of the errors, re-run Maven with the -e switch.
Re-run Maven using the -X switch to enable full debug logging.
For more information about the errors and possible solutions, please read the following articles:

In the “pom.xml” delete the following portion”

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
……………
………..
………….
<arguments>
<argument>run</argument>
<argument>io/vertx/mvnvertx/Main.java</argument>
<!--                  <argument>-cluster</argument>
<argument>-cluster-host</argument>
<argument>127.0.0.1</argument>-->
</arguments>
</configuration>
</plugin>

If you “Clean and Build” now, there will be no error.
To run the project, insert a main() as under:

public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
vertx.deployVerticle(new Main());  // the verticle is deployed in main()
}

Right Click on the Project and choose “properties” and in the wizard that appears choose “Run” and it will change as Figure-2 as under:

Figure-2

Fill up the Main class with full package name. In my case it is “io.vertx.mvnvertx.Main”. If you “Run” the project now you may see the following output

Building mvnVertx 1.0-SNAPSHOT
--------------------------------------------
--- exec-maven-plugin:1.2.1:exec (default-cli) @ mvnVertx ---
Periodic event triggered.
Periodic event triggered.
Periodic event triggered.
Periodic event triggered.
Periodic event triggered.

This is a working Vertx-Web app generated by Maven. We only deleted from “pom.xml” certain portion relating to generation of main() and manually added one to get a working application.

This can be modified to make it a REST service created with Vertx-web. Now we will store and retrieve data from a HashMap. In a later sample we will use a database –MongoDB.

Main.java   The code for the  file may be modified as below:

io/vertx/mvnvertx/Main.java

package io.vertx.sample.ang;
import io.vertx.core.AbstractVerticle;    //-----1) & 2)
import io.vertx.core.Future;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.Json;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.StaticHandler;
import java.util.LinkedHashMap;
import java.util.Map;
public class Main extends AbstractVerticle {
private Map<Integer, Book> products = new LinkedHashMap<>();
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();  // vertx object obtained
vertx.deployVerticle(new Main()); //it is used to deploy the Verticle
}
/**
This method start() is called when the verticle is deployed. It creates a HTTP server and registers a simple request handler. To the `listen` method port number is passed */
@Override
public void start() {
// we need some data and we call the method that puts some data into the Map “products”
createSomeData();  
/** Create a router object which is the cornerstone of Vert.x Web. This object is responsible for dispatching the HTTP requests to the right handler. --  3)  */
Router router = Router.router(vertx);
// Bind "/" to our hello message.
router.route("/").handler(routingContext -> {    //----- 4)
HttpServerResponse response = routingContext.response();
response
.putHeader("content-type", "text/html")
.end("<h1>Hello from my first Vert.x 3 application</h1>");
});
router.route("/assets/*").handler(StaticHandler.create("assets")); //----5)
router.get("/api/books").handler(this::getAll);  //------6)
router.route("/api/books*").handler(BodyHandler.create()); //----7)
router.post("/api/books").handler(this::addOne);   //--------8)
// Create the HTTP server using vertx object and pass the "accept" method to the request handler.
vertx
.createHttpServer()
.requestHandler(router::accept)
.listen(8080);
}
private void addOne(RoutingContext routingContext) {
// Read the request's content and create an instance of Book.
final Book book = Json.decodeValue(routingContext.getBodyAsString(), Book.class);
// Add it to the backend map
products.put(book.getId(), book);
// Return the created book as JSON
routingContext.response()
.setStatusCode(201)
.putHeader("content-type", "application/json; charset=utf-8")
.end(Json.encodePrettily(book));
}
private void getAll(RoutingContext routingContext) {
/**Write the HTTP response. The response is in JSON using the utf-8 encoding. It returns the list of books */
routingContext.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(Json.encodePrettily(products.values())); //------9)
  }
/** initial data */
private void createSomeData() {
Book book1 = new Book("Easy Vertx", "Ramasamy");
products.put(book1.getId(), book1);
Book book2 = new Book("Easy Angular", "Madhan");
products.put(book2.getId(), book2);
}
}

  • You can see most of the imports are from Vert.x Core. They are used to code the Verticle, create the HttpServer and send the HttpResponse. They provide the basic functionalities.
  • The classes imported from Vert.x-web are i) Router ii) RoutingContext  iii) BodyHandler iv) StaticHandler. All these are used to define various routes for matching different types of requests and fine tune the basic functionalities provided by the Core classes.
  • A Router is one of the core concepts of Vert.x-Web. This object is responsible for dispatching the HTTP requests to the right handler. It’s an object which maintains zero or more Routes .A router takes an HTTP request and finds the first matching route for that request, and passes the request to that route. The route can have a handler associated with it, which then receives the request. Handlers are the actual action processing the requests and writing the result, but invoked asynchronously.
  •  Here we have created a simple route with no matching criteria and it will match all requests that arrive on the server. Its handler will be called for all requests that arrive on the server and send a “hello” as response. Processing the request and writing the result is the main job of a handler. The handler is passed a RoutingContext - this contains the standard Vert.x HttpServerRequest and HttpServerResponse but also various other useful stuff that makes working with Vert.x-Web simpler. For every request that is routed there is a unique routing context instance, and the same instance is available to all handlers for that request.

Handler for static files; recall “static” middleware in Express.js.

Handler for HTTP GET. See the method reference syntax in Java-8. In its place, you can use lambda expression “this à this.getAll()”

This is BodyHandler, similar to BodyParser in Express to parse body in POST requests.

Here you can see there are routes and handlers for HTTP GET and HTTP POST. If you want routes and handlers also for PUT and Delete, please refer to the blog “Some Rest with Vert.x”.

Vertx defines two classes to make handling JSON in your Vert.x applications a bit easier. Here you see one of them JSON. The method encodePrettily() defined in that class is passed Book Java objects(values in the map products) and the conversion of them into JSON is handled by it.

Data:

You know “Jackson” is a popular library for converting Java objects into JSON and vice versa. As mentioned above, Vertx builds JSON and JsonObject classes on top of the above library. As in any other Java Program our data can be a POJO and can be just passed to the methods in those classes. Our data comprises of Book objects and the code for the POJO Book is given below:

Book.java

package io.vertx.sample.ang;
import java.util.concurrent.atomic.AtomicInteger;

public class Book {
private static final AtomicInteger COUNTER = new AtomicInteger();
private final int id;
private String title;
private String author;
public Book(String title, String author) {
this.id = COUNTER.getAndIncrement();
this.title = title;
this.author = author;
}

  public Book() {
this.id = COUNTER.getAndIncrement();
}

  public String getTitle() {
return title;
}

  public String getAuthor() {
return author;
}

  public int getId() {
return id;
}

  public void setTitle(String title) {
this.title = title;
}

  public void setAuthor(String author) {
this.author = author;
}
}

Index.html
The server can serve the page composed on the server from HTTP Response and the static file index.html or serve static file “index.html” and HTTP response as JSON separately. Angular.js, which is a SPA, as mentioned in the earlier articles on Angular, takes over from the server and composes the page in the Browser from the static files and data received from the server. For Rest Services SPAs are better fits for clients. Right click on “Other Sources/src/main/resources. Choose New à Folder. Give the folder name as “assets”. Now right click on assets and create a HTML file “index.html” The code for index.html is can be modified as given below. As mentioned in the introduction, there are some changes in our Angular.js code, when compared to the earlier ones.

resources/assets/index.html

<html ng-app="booksApp">

<head>
<title>Vertx-Angular </title>
<style>
.item {
padding: 10px;
}
</style>
</head>

<body ng-controller="MainCtrl as mainCtrl">     00000//-----1)
<h1>Angular-vertx-App!</h1>
<div ng-repeat="book in mainCtrl.items"
class="item">
<div><span ng-bind="book.title"></span></div>   //----2)
<div><span ng-bind="book.author"></span></div>
</div>

  <div>
<form name="addForm"
ng-submit="mainCtrl.add()">
<input type="text"
placeholder="Title"
ng-model="mainCtrl.newBook.title"  //-------3)
required>
<input type="text"
placeholder="Author"
ng-model="mainCtrl.newBook.author"
required>
<input type="submit"
value="Add"
ng-disabled="addForm.$invalid">
</form>
</div>

<script
src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.11/angular.js">
</script>
<script>
angular.module('booksApp', [])
.controller('MainCtrl', ['$http', function($http) {
var self = this;
self.items = [];
self.newBook = {};
var fetchBooks = function() {
return $http.get('/api/books').then( //  ----4)  & 5)
function(response) {
self.items = response.data;
}, function(errResponse) {
console.error('Error while fetching ');
});
};

fetchBooks();

self.add = function() {
$http.post('/api/books', self.newBook)
.then(fetchBooks)
.then(function(response) {
self.newBook = {};
});
};

    }]);
</script>
</body>
</html>

  • this is the new syntax referred above in use.
  • In place of {{}} , ng-bind directive is used.
  • The Json object “newBook” created in Controller and attached to “this” is available in HTML. For various reasons “self” is used within the controller as a proxy for “this”.
  • Uri is passed to http.get().
  • As mentioned above, the return value of the function $http()is a promise instance. So, you can attach then() to it and pass success/error callbacks that'll be called appropriately

Build and Run

We can build the project in the IDE by right clicking and choosing “Clean and Build”  When you get “Build Success” message, you go to the project folder\target and see within it a fat.jar file. You can distribute it and it can be run from anywhere if Java-8 is available. For example you can copy the jar to “F:” directory and execute
“java –jar VertxWeb-1.0-SNAPSHot-fat.jar” and see the result.

Now We choose to “Run” the jar from the IDE. When you get “Succeeded in deploying verticle”, you can go to the Browser and navigate to “localhost:8080”.You will get a “hello” message. Add “assets” to navigation bar. The Browser will navigate to index.html. After adding a Book it may look as in Figure-3.

Figure-3

Conclusion

The advantage of using Angualr.js as a view technology for HTTP Rest services have been covered in many articles. Being an SPA it composes the web-page from the static files and HTTPReponse received from the server. Its two-way data binding simplifies our code .We used the IDE to avoid manually creating a directory structure and folders and files required by Maven. We can build a fat.jar from the IDE. The fat.jar can be run from anywhere, if Java-8 is available on the machine. This is a self-contained service and there is no need for any other web server.  Vertx is not particular about any view technology. Earlier to a number of such web services-JEE, ASP Net Web API and Node.js  - we saw Angular.js clients. So now also we used an Angular.js client. However we preferred “http module” to the sub-project “angular-resource”, as we can chain success and error callbacks to the methods in “http service”. In the process some verbosity has been introduced but the gain is “error-handling”. We also used “controller as” syntax, which was introduced in the later versions of Angular, in place of “$scope”. The new syntax has some advantages over $scope especially if the UI is complex and nested. Now the resource for the REST service was a Map in the server itself. But later on with minimal changes to the code, we can replace the Map with MongoDB. We will show how to do it in the next article. Vertx makes use of Sock.js for real time applications. As we have seen use of this tool also with Node.js, we will also see how Vertx uses this to “bridge” its Event-bus to JavaScript clients.

This article is written by P Madanasekaran. For more information you can email at sekaran.madhan@gmail.com








}