2017-02-06

Vert.x And Callback Hell

One thing which some developers may not find appealing in Vert.x is the use of callbacks. Specifically when you have all sorts of nested Lambda/Closure blocks in your code, it can make your code harder to understand and much harder to test. In this post, I will demonstrate a way of writing your code so that the impact of callback hell is minimized and testing options are improved.

Let's look at an example of a simple Vert.x Web Verticle:


import io.vertx.core.json.JsonObject;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.AbstractVerticle;

public class REST extends AbstractVerticle {

    public void start() {
        Router router = Router.router(vertx);
        router.get("/v1/customer/:id").handler(ctx -> {
            vertx.eventBus().send("some.processor", ctx.params(), reply -> {
                // How do we test the logic inside of this Lambda?!?!
            });
        });
    }
}

How would you be able to perform an isolated test of the logic contained in either of the lambdas? Well, the simple answer is that you can't. You could do an integration test, but in many cases that is overkill and also won't let you manipulate the code so that you can cover all cases. The good news is that there is an answer, and it works in all of the Vert.x language implementations I have used. Let's modify the example above and see if we can make it easier to read AND easier to test:


import io.vertx.core.json.JsonObject;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.AbstractVerticle;

public class REST extends AbstractVerticle {

    public void start() {
        Router router = Router.router(vertx);
        router.get("/v1/customer/:id").handler(this::handleCustomerById);
    }

    void handleCustomerById(final RoutingContext ctx) {
        vertx.eventBus().send("some.processor", ctx.params(), reply -> { handleCustomerReply(ctx, reply); });
    }

    void handleCustomerReply(RoutingContext ctx, AsyncResult<Message<JSONObject>> reply) {
        if (reply.succeeded()) {
            ctx.response().setStatusCode(200).setStatusMessage("OK").end(reply.result().encodePrettily());
        } else {
            ctx.response().setStatusCode(404).setStatusMessage("NOT FOUND").end();
        }
    }
}

By splitting out the logic into separate methods, we can now easily inject Mock objects into the methods for testing. Additionally, we have increased readability by giving those methods meaningful names. This opens up a lot of options for unit and integration testing while improving maintainability. You'll also note that I left off the public/private modifiers on the methods so that they can be easily tested using test suites using the same package name.

Overall, this is a quick and simple way to overcome a lot of frustration experienced by developers who deal with callback hell, so I hope that you can leverage this option in your code in the near future!

2017-02-03

Vert.x Web And Request Routing

In yesterday's post, we started looking at handlers; but we only showed how to set up a handler for ALL HTTP requests. It would be nice if there were an easy way to attach a handler to SPECIFIC HTTP requests. There is, and it's called Vert.x Web. Vert.x Web has a number of additional features above and beyond the Core features:

  • Session Handling
  • Authentication Hooks
  • Static Content Handling
  • Localization
  • Cookies Handling
  • Websocket Extensions
  • Error Handlers
  • Timeout Handlers
  • HTML Templating Hooks
  • Cross-Origin Request Handling
  • Virtual Hosts (Both HTTP AND HTTPS)
  • OAuth Hooks

But most importantly, Vert.x Web has a component called a Router. That will be the focus of today's post.

Using Routers

So far, we have seen that we can add a requestHandler() to an HTTP server, but what if we want to have a number of different paths which do different things in our web application? This is where the Vert.x Web module comes in. It gives us a new features like Router and RoutingContext.

Exercise.groovy
import io.vertx.lang.groovy.GroovyVerticle
import io.vertx.groovy.ext.web.Router
import io.vertx.groovy.ext.web.RoutingContext
import io.vertx.core.json.JsonObject

class Exercise extends GroovyVerticle {

    void start() {
        def router = Router.router(vertx)

        router.get('/')              .handler(this.&rootHandler)
        router.get('/something/else').handler(this.&otherHandler)

        vertx.createHttpServer()             // Create a new HttpServer
             .requestHandler(router.&accept) // Register a request handler
             .listen(8080, '127.0.0.1')      // Listen on 127.0.0.1:8080
    }

    void rootHandler(RoutingContext ctx) {
        ctx.response().end(new JsonObject([ok: true, path: ctx.request().path()]).encode())
    }

    void otherHandler(RoutingContext ctx) {
        ctx.response().end(new JsonObject([ok: false, message: 'Something Else']).encode())
    }
}
  1. You see that we added 2 different routes to the Router instance
  2. Each route has a separate handler set via a method reference
  3. Finally, we pass the Router’s accept method via a method reference as a handler for the HttpServer’s requestHandler() method.

Routes with Path Parameters

In the previous example, we saw that we could specify different paths with different handlers, but what about if we want to capture information FROM the path in a programmatic manner?

Exercise.groovy
import io.vertx.lang.groovy.GroovyVerticle
import io.vertx.groovy.ext.web.Router
import io.vertx.groovy.ext.web.RoutingContext
import io.vertx.core.json.JsonObject

class Exercise5 extends GroovyVerticle {

    void start() {
        def router = Router.router(vertx)

        router.get('/')            .handler(this.&rootHandler)
        router.get('/customer/:id').handler(this.&custHandler)

        vertx.createHttpServer()            // Create a new HttpServer
            .requestHandler(router.&accept) // Register a request handler
            .listen(8080, '127.0.0.1')      // Listen on 127.0.0.1:8080
    }

    void rootHandler(RoutingContext ctx) {
        ctx.response().end(new JsonObject([ok: true, path: ctx.request().path()]).encode())
    }

    void custHandler(RoutingContext ctx) {
        ctx.response().end(new JsonObject([
           ok: false,
           custID: ctx.request().getParam('id')
        ]).encode())
    }
}
  1. Modify the example above to have a new route which had multiple path parameters
  2. Modify the example above to use a route with regular expressions
  3. Modify the example to add a new HTTP POST endpoint which consumes JSON and produces the POSTed JSON
That should give you a pretty good start on using the Router in Vert.x Web. Tune in tomorrow for even more Vert.x goodness!

2017-02-02

Vert.x Handlers

Let's do an exercise to better understand Handlers in Vert.x

Handlers

A handler in Vert.x is a form of Callback. Handlers are passed as arguments to some Vert.x methods so that the callback can be executed once a particular asynchronous operation has been completed. Handlers for Vert.x can be written in Groovy in several ways:
Exercise 1: Handler classes

The basic Handler in Vert.x is any class which implements the Handler interface. For example:

Exercise1.groovy
import io.vertx.lang.groovy.GroovyVerticle
import io.vertx.core.json.JsonObject

class Exercise1 extends GroovyVerticle {

    private class RequestHandler implements Handler {
        void handle(HttpServerRequest req) {
            def response = new JsonObject([ok: true]).encode()
            req.response().end(response)
        }
    }

    void start() {
        // Create a JSON response
        def response = new JsonObject([ok: true]).encode()

        vertx.createHttpServer()         // Create a new HttpServer
             .requestHandler(new RequestHandler())
             .listen(8080, '127.0.0.1')  // Listen on port 8080 and interface `127.0.0.1`
    }
}
As you can see, we pass an instance of the RequestHandler class to the requestHandler() method on the HttpServer object and that instance will handle the HTTP requests.
Exercise 2: Method References

Another way to implement handlers removes some of the boiler-plate of having a separate hanlder class for each Callback we want to register. It’s called a Method Reference. A method reference is a way of assigning a method to behave as a callback without having to implement a Handler interface on a new class.

Exercise2.groovy
import io.vertx.groovy.core.http.HttpServerRequest
import io.vertx.lang.groovy.GroovyVerticle
import io.vertx.core.json.JsonObject

class Exercise2 extends GroovyVerticle {

    /**
     * Handle HttpServerRequests
     */
    void handleRequest(HttpServerRequest req) {
        def response = new JsonObject([ok: true]).encode()
        req.response().end(response)
    }

    void start() {
        // Create a JSON response
        def response = new JsonObject([ok: true]).encode()

        vertx.createHttpServer()         // Create a new HttpServer
             .requestHandler(this.&handleRequest) // Register a request handler
             .listen(8080, '127.0.0.1')  // Listen on port 8080 and interface `127.0.0.1`
    }
}

Exercise 3: Closures

Finally, in Groovy we can use Closures. Closures are a way of writing a bit of code which can be passed as a value . . . in-line…

Exercise3.groovy

import io.vertx.lang.groovy.GroovyVerticle
import io.vertx.core.json.JsonObject

class HelloWorld extends GroovyVerticle {

    void start() {
        // Create a JSON response
        def response = new JsonObject([ok: true]).encode()

        vertx.createHttpServer()         // Create a new HttpServer
             .requestHandler({ req ->    // Register a request handler
                 req.response().end(response)
             })
             .listen(8080, '127.0.0.1')  // Listen on port 8080 and interface `127.0.0.1`
    }
}
An alternate way of declaring that closure would be to assign the closure to a variable and then pass the variable into the requestHandler() method as shown below:

Exercise3_1.groovy
import io.vertx.core.json.JsonObject
import io.vertx.groovy.core.http.HttpServerRequest
import io.vertx.lang.groovy.GroovyVerticle

class Exercise3_1 extends GroovyVerticle {

    void start() {

        def reqHandler = { HttpServerRequest req ->
            // Create a JSON response
            def response = new JsonObject([ok: true]).encode()
            req.response().end(response)
        }

        vertx.createHttpServer()         // Create a new HttpServer
             .requestHandler(reqHandler) // Register a request handler
             .listen(8080, '127.0.0.1')  // Listen on port 8080 and interface `127.0.0.1`
    }
}
Next Steps: (see HttpServerRequest)


Modify the example above to include the requested path as an item in the JSON response body


Modify the example above to include the request headers as a nested JSON object within the response body

If you want to skip ahead, there are more of these exercises available HERE

2017-02-01

Hello Vert.x World!

From out previous 2 posts, we had been explaining a bit of background and preparation to be able to start writing Vert.x code. In this post, we will actually start to write some Vert.x code and examine some of it's features.

Our First Vert.x Application

Get The Vert.x Runtime

Vert.x has a command-line runtime for deploying purely Vert.x applications. It can be downloaded from the Vert.x web site:

Using the Vert.x runtime, you can launch simple Vert.x applications like the ones in this chapter by simply running:

vertx run Verticle.(java|js|groovy|rb|scala|ceylon|py|kt)

Once you have downloaded the Vert.x runtime and extracted it, you will need to ensure that the bin/ directory is in your execution path.

Writing Our First Verticle

Without further delay, let’s write some code.

HelloWorld.java
import io.vertx.core.AbstractVerticle;

public class HelloWorld extends AbstractVerticle {

    @Override
    public void start() {
        int period = 100;
        vertx.setPeriodic(
                period,                                 (1)
                t -> System.out.println("Hello World")  (2)
        );
    }
}
1 The period of the repeating task in milliseconds
2 A Lambda which will be executed

This is about the simplest example of a Vert.x application that I can demonstrate. This is a single Verticle which sets up a timer which executes a Callback every period milliseconds. The callback prints out the words “Hello World” to the console. We see in the code above that the setPeriodic method takes 2 arguments: A period in milliseconds, and a callback to be executed on that period. In this case, the callback is in the form of a Lambda.

Taking It To The Web

The first example was pretty easy, so let’s make it a little more challenging. Let’s create a web server which returns “Hello World” every time we make a request.

HelloWebWorld.java
import io.vertx.core.AbstractVerticle;

class HelloWebWorld extends AbstractVerticle {

    @Override
    public void start() {
        int period = 100;
        vertx.createHttpServer().requestHandler(req -> { (1)
          req.response()
             .putHeader("Content-Type", "text/plain")
             .setStatusCode(200)
             .setStatusMessage("OK")
             .end("Hello Web World");  (2)
        }).listen(8080, "0.0.0.0");
    }
}
1 Create a Lambda which will be called each time an HTTP request is received by our server
2 The response is not actually sent UNTIL end() is called.

Something to take particular note of in this example is that all of the response methods are chained together using what is called a Fluent API. Each method returns the original object, with it’s state modified, so that more methods on that same object can be called instead of having to make separate statements for each method.

That's a great start. We're already handling web requests in a reactive, non-blocking, event-driven manner! Tune in tomorrow when we take the next step into using network sockets over TCP and UDP!

2017-01-31

Vert.x Basics

In part 1, we discussed some of the ideas behind Vert.x. In this, the second post in the series, we will discuss some more details and coding conventions used in Vert.x. Vert.x is pretty easy to get started with. The most difficult part is getting used to the asynchronous nature of the code. Let’s begin a little by talking about callbacks, what they look like, and how they are used.


Callbacks

A Callback is defined by Wikipedia as “a piece of executable code that is passed as an argument to other code, which is expected to call back (execute) the argument at some convenient time”. A simple way to think about this is perhaps like a text message you send via your cell phone. You send the message asking your friend to call you and let you know when the pizza arrives. You may get a return call from your friend immediately (the pizza is already there) or some other time later (after the pizza arrives). Callbacks in programming work in a similar fashion. You submit a task to be completed and along with that task you provide a callback Lambda which the underlying system will execute once the requested task is complete, sometimes providing the results of that task to the callback. Let’s see an example:

Callbacks.java
import io.vertx.core.AbstractVerticle;
import io.vertx.core.AsyncResult;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;

public class Callbacks extends AbstractVerticle {

    private static final Logger LOG = LoggerFactory.getLogger(Callbacks.class);

    public void readFileHandler(AsyncResult<Buffer> res) { (1)
        if (res.succeeded()) {
            Buffer fileContents = res.result();
            // Do something with the file contents
        } else {
            // Handle the error
            LOG.error("Error reading file", res.cause());
        }
    }

    @Override
    public void start() {
        vertx.fileSystem().readFile("/path/to/file.txt", this::readFileHandler); (2)
    }
}
1 The callback function to be passed
2 The functional call which accepts the callback as a parameter

In our example above, we pass the callback as a parameter to the readFile method, and the API is designed such that
when the file has been read completely it will call that method/function with the results of the file read.

Verticles

One of the key components of Vert.x is a Verticle. Verticles in Vert.x are roughly equivalent to Actors that would you see in Erlang or Akka. A simple way to think about actors is that they are individual single-purpose programs which have a specific function and which are communicated with via message passing. This has a distinct advantage: Since actors are only accessible via message passing, there is no shared state, and there are no concurrency issues. Let’s use another analogy.

Tom has gathered a group of contractors to build a house. He could hand a copy of the blueprints to each contractor and tell them to go and start, but there is a good chance that they will get in each other’s way. Instead, Tom breaks down the plans into individual tasks which the contractors specialize in. Jeff is a framer, so when Tom needs frames built a message is passed to Jeff with details about where and what sort of frame to build and Jeff proceeds. Wes is a mason, so Tom sends Wes messages about when and where he needs foundations built and Wes proceeds. Austyn is a roofer, so she gets messages about where and what sorts of roofing get built. Tom acts as a broker, sending messages to each contractor (Actor) to fulfill individual tasks. When those tasks are complete, the Actor will either sit idle and wait for the next message or they will send a message back to Tom to let him know that the task is complete. Sometimes the needs of each contractor have coordination, so it is also possible for individual contractors to send messages to each other in order to coordinate their work.

Verticles work in a simlar fashion. A Verticle SHOULD be built with a single task in mind and it should be communicated with via messages. This gives us the advantage that each of the Actors/Verticles/Contractors can work in parallel without causing problems with other Actors/Verticles/Contractors.

The Event Bus

We have discussed that Actors/Verticles communicate via messages, and the Event Bus is how those messages are passed in Vert.x. The Event Bus provides a standard way for messages to be sent between Verticles inside a single Vert.x application AND between Vert.x applications. In addition, the Vert.x Event Bus can take advantage of the Clustering capabilities inherent in Vert.x to send messages across multiple nodes. The Event Bus is also fairly flexible in that messages can be sent in multiple ways:

  1. Publish - A Message is sent and ALL consumers recieve a copy (throughout a cluster even)
  2. Send - A Message is sent and ONLY ONE consumer recieves a copy (Determined by the Vert.x Event Bus and availability)
  3. Send And Expect Response - The same as send, but the consumer is able to send a response with success/fail and a result.

In addition, message consumers can work in multiple ways:

  1. Consumer - Listens for messages from anywhere in a Cluster
  2. Local Consumer - Only accepts messages for the Vert.x node it operates within

Clustering

In the previous section Clustering was mentioned, and it should be clarified that Clustering is a capability designed in from the beginning in Vert.x. There are a number of Cluster Manager implementations available and we will discuss them in more depth later in this book. For now, realize that Vert.x applications are easily scaled horizontally by using the built-in clustering capabilities which Vert.x provides. And more than just facilitating the Event Bus, the cluster managers are capable of organizing shared data throughout a cluster in a way which is safe for multiple concurrent nodes.

Come back tommorrow, when we will start to write actual Vert.x code, starting with a simple series of HelloWorld examples.