Using QBit to create Java RESTful microservices

posted Apr 20, 2015, 12:36 PM by Rick Hightower

QBit Restful Microservices

Before we delve into QBit restful services, let's cover what we get from gradle's application plugin. In order to be a microservice, a service needs to run in a standalone process or a related group of standalone processes.
... (Read full article at Creating Java RESTful Microservices)
...

Creating a simple RestFul Microservice

Let's create a simple HTTP service that responsds with pong when we send it a ping as follows.

Service that responds to this curl command

$ curl http://localhost:9090/services/pongservice/ping
"pong"
First let's import the qbit lib. We are using the SNAPSHOT but hopefully by the time you read this the release will be available.
Add the following to your gradle build.

Adding QBit to your gradle build

apply plugin: 'java'
apply plugin:'application'

sourceCompatibility = 1.8
version = '1.0'
mainClassName = "io.advantageous.examples.Main"

repositories {
    mavenLocal()
    mavenCentral()
}

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.11'
    compile group: 'io.advantageous.qbit', name: 'qbit-vertx', version: '0.7.3-SNAPSHOT'
}
Define a service as follows:

QBit service

package io.advantageous.examples;


import io.advantageous.qbit.annotation.RequestMapping;

@RequestMapping
public class PongService {


    @RequestMapping
    public String ping() {
        return "pong";
    }

}
The @RequestMapping defines the service as one that responsds to an HTTP call. If you do not specify the path, then the lower case name of the class and the lower case name of the method becomes the path. Thus PongService.ping() becomes /pongservice/ping. To bind this service to a port we use a service server. A service server is a server that hosts services like our pong service.
Change the Main class to use the ServiceServer as follows:

Using main class to bind in service to a port

package io.advantageous.examples;

import io.advantageous.qbit.server.ServiceServer;
import io.advantageous.qbit.server.ServiceServerBuilder;

public class Main {

    public static void main(String... args) {
        final ServiceServer serviceServer = ServiceServerBuilder
                .serviceServerBuilder()
                .setPort(9090).build();
        serviceServer.initServices(new PongService());
        serviceServer.startServer();
    }
}
Notice we pass an instance of the PongService to the initServices of the service server. If we want to change the root address from "services" to something else we could do this:

Changing the root URI of the service server

       final ServiceServer serviceServer = ServiceServerBuilder
                .serviceServerBuilder()
                .setUri("/main")
                .setPort(9090).build();
        serviceServer.initServices(new PongService());
        serviceServer.startServer();
Now we can call this using curl as follows:

Use the curl command to invoke service via /main/pongservice/ping

$ curl http://localhost:9090/main/pongservice/ping
"pong"
QBit uses builders to make it easy to integrate QBit with frameworks like Spring or Guice or to just use standalone.

Adding a service that takes request params

Taking request parameters

package io.advantageous.examples;


import io.advantageous.qbit.annotation.RequestMapping;
import io.advantageous.qbit.annotation.RequestParam;

@RequestMapping("/my/service")
public class SimpleService {

    @RequestMapping("/add")
    public int add(@RequestParam("a") int a,
                   @RequestParam("b") int b) {

        return a + b;
    }


}
Notice the above uses @RequestParam this allows you to pull the requests params as arguments to the method. If we pass a URL like: http://localhost:9090/main/my/service/add?a=1&b=2. QBit will use 1 for argument a and 2 for argument b.

Adding the new service to Main

package io.advantageous.examples;

import io.advantageous.qbit.server.ServiceServer;
import io.advantageous.qbit.server.ServiceServerBuilder;

public class Main {

    public static void main(String... args) {
        final ServiceServer serviceServer = ServiceServerBuilder
                .serviceServerBuilder()
                .setUri("/main")
                .setPort(9090).build();
        serviceServer.initServices(
                new PongService(),
                new SimpleService());
        serviceServer.startServer();
    }
}
When we load this URL:
http://localhost:9090/main/my/service/add?a=1&b=2
We get this response.
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 1

3

Working with URI params

Many think that URLs without request parameters are more search engine friendly or you can list things under a context which make it more RESTful. This is open to debate. I don't care about debate, but here is an example of using URI params.

Working with URI params example

package io.advantageous.examples;


import io.advantageous.qbit.annotation.PathVariable;
import io.advantageous.qbit.annotation.RequestMapping;
import io.advantageous.qbit.annotation.RequestParam;

@RequestMapping("/my/service")
public class SimpleService {
...
...
    @RequestMapping("/add2/{a}/{b}")
    public int add2( @PathVariable("a") int a,
                     @PathVariable("b") int b) {

        return a + b;
    }


}
Now we can pass arguments which are part of the URL path. We do this by using the@PathVariable annotation. Thus the following URL:
http://localhost:9090/main/my/service/add2/1/4
The 1 is correlates to the "a" argument to the method and the 4 correlates to the "b" arguments.
We would get the following response when we load this URL.

Working with URI params output

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 1

5
You can mix and match URI params and request params.

Working with URI params and request params example

package io.advantageous.examples;


import io.advantageous.qbit.annotation.PathVariable;
import io.advantageous.qbit.annotation.RequestMapping;
import io.advantageous.qbit.annotation.RequestParam;

@RequestMapping("/my/service")
public class SimpleService {
...
...
    @RequestMapping("/add3/{a}/")
    public int add3( @PathVariable("a") int a,
                     @RequestParam("b") int b) {

        return a + b;
    }

}
This allows us to mix URI params and request params as follows:
http://localhost:9090/main/my/service/add3/1?b=8
Now we get this response:

Working with URI params and request params example

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 1

9

Fuller RESTful example

Comments