vlingo/http

Last updated 2 months ago

Reactive REST using vlingo/http.

Setting up vlingo/http

Using Maven

<repositories>
<repository>
<id>jcenter</id>
<url>https://jcenter.bintray.com/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>io.vlingo</groupId>
<artifactId>vlingo-http</artifactId>
<version>0.7.9</version>
<scope>compile</scope>
</dependency>
</dependencies>

Using Gradle

Groovy DSL
Kotlin DSL
dependencies {
compile 'io.vlingo:vlingo-http:0.7.9'
}
repositories {
jcenter()
}
compile(group = "io.vlingo", name = "vlingo-http", version = "0.7.9")

Hello World

We will start with the minimum code to create an endpoint that returns Hello World. I will be using the Java code as reference but you will have Kotlin example available as well.

Create a new project with your favorite Tool and create the Bootstrap class with the following content.

Java
Kotlin
Bootstrap.java
import io.vlingo.actors.World;
import io.vlingo.common.Completes;
import io.vlingo.http.Response;
import io.vlingo.http.resource.Configuration.Sizing;
import io.vlingo.http.resource.Configuration.Timing;
import io.vlingo.http.resource.Resource;
import io.vlingo.http.resource.Resources;
import io.vlingo.http.resource.Server;
import static io.vlingo.http.resource.ResourceBuilder.get;
import static io.vlingo.http.resource.ResourceBuilder.resource;
public class Bootstrap {
private final static int PORT = 8080;
private static Bootstrap instance;
public final Server server;
public final World world;
private Bootstrap() {
this.world = World.startWithDefaults("hello world example java");
final Resources resources = Resources.are(helloWorldResource());
this.server = Server.startWith(world.stage(),
resources,
PORT,
Sizing.define(),
Timing.define());
}
private Resource helloWorldResource() {
return resource("hello world",
get("/helloworld")
.handle(() -> withSuccess(of(Ok, "Hello World")))
);
}
public static final Bootstrap instance() {
if (instance == null) instance = new Bootstrap();
return instance;
}
public static void main(final String[] args) throws Exception {
System.out.println("=========================================");
System.out.println("service: started at http://localhost:" + Bootstrap.PORT);
System.out.println("check out http://localhost:" + Bootstrap.PORT + "/helloworld");
System.out.println("=========================================");
Bootstrap.instance();
}
}
Bootstrap.kt
import io.vlingo.actors.World
import io.vlingo.common.Completes.withSuccess
import io.vlingo.http.Response.of
import io.vlingo.http.Response.Status.Ok
import io.vlingo.http.resource.Configuration.Sizing
import io.vlingo.http.resource.Configuration.Timing
import io.vlingo.http.resource.Resource
import io.vlingo.http.resource.ResourceBuilder.get
import io.vlingo.http.resource.ResourceBuilder.resource
import io.vlingo.http.resource.Resources
import io.vlingo.http.resource.Server
class Bootstrap {
private val world = World.startWithDefaults("hello world example kotlin")
private val server: Server
init {
val resources = Resources.are(helloWorldResource())
server = Server.startWith(world.stage(),
resources,
PORT,
Sizing.define(),
Timing.define())
}
private fun helloWorldResource(): Resource<*> {
return resource("hello world resource",
get("/helloworld")
.handle { withSuccess(of(Ok, "Hello World")) })
}
companion object {
const val PORT = 8080
}
}
fun main(args: Array<String>) {
println("=========================================")
println("service: started at http://localhost:" + Bootstrap.PORT)
println("check out http://localhost:" + Bootstrap.PORT + "/helloworld")
println("=========================================")
Bootstrap()
}

Check the result doing

curl http://localhost:8080/helloworld

Server uses the World Logs configuration.

The Server class (24) is where the Resources live, Resources(22) is the group of HTTP endpoints. To start a Server you just need an Stage and the Resources, when it's created, it starts listening for HTTP Requests.

Sizing (27) is the configuration parameter with the processor pool size, dispatcher pool size , max buffer pool size and max message size. Timing (28) is the configuration with the timeout parameters. For now, we will use the default configuration.

The next sections uses the previous code as starting point.

Defining resources

vlingo-http provides a Fluent API to define HTTP endpoints and its method handlers. You have seen the first methods in the previous example, and here will see them in detail.

ResourceBuilder.resource(final String name, RequestHandler... requestHandlers) it returns a Resource. A set of Resource is what the Server needs to handle HTTP requests and response them.

HTTP Methods

The Fluent API supports the next HTTP methods

  • ResourceBuilder.get(final String uri)

  • ResourceBuilder.post(final String uri)

  • ResourceBuilder.put(final String uri)

  • ResourceBuilder.delete(final String uri)

  • ResourceBuilder.patch(final String uri)

  • ResourceBuilder.head(final String uri)

  • ResourceBuilder.options(final String uri)

  • ResourceBuilder.trace(final String uri)

  • ResourceBuilder.connect(final String uri)

All methods return a RequestHandler .

Request Handler

The Request Handler enforces type safety on the handler function method definition though your parameters. Let see them in action.

Path parameters

Java
Kotlin
get("/user/{userId}")
.path(String.class)
.handler((userId) -> /* */);

userId has the String type because of path(String.class). You can specify type you would like of:

  • String

  • Long

  • Integer

  • Float

  • Double

  • Boolean

  • Short

  • Character

path method needs to be defined before any other, otherwise it will throw an error when Server starts.

When using path , be sure you have the the same path variable in the URI between brackets {<variable>} as path methods has been used.

Body parameter

Java
Kotlin
post("/user")
.body(NameData.class)
.handler((nameData) -> /* */);

The body method maps the HTTP Body into the type you specify.

Query parameter

curl http://localhost:8080/user?page=5
Java
Kotlin
get("/user")
.query("page")
.handler((page) -> /* */);
get("/user")
.query("page", Integer.class)
.handler((page) -> /* */);
get("/user")
.query("page", Integer.class, 0 /* default value */)
.handler((page) -> /* */);
get("/user")
.query("page")
.handler((page) -> /* */);

By default, the type of the query parameter is String. When the query parameter isn't present, the value is null. It's a good practice to specify always a default value for query parameters to avoid unexpected behavior.

Headers parameters

Java
Kotlin
get("/user")
.header("Location")
.handler((location) -> /* */);

Combining them all

Java
Kotlin
post("/user/{userId}")
.param(String.class)
.body(UserData.class)
.header("Location")
.handler((userId, userData, location) -> {
// Perform some action
return Completes.withSuccess(Response.of(Ok, serialized(userData)));
});

The order of the parameters matters. Try changing the order of body and header, you will see that the type of userData becomes a Header type and location know has the UserData type.

Check the frontservice at vlingo/vlingo-examples for a working example.

Known problems

  • Only up to 5 handler function argument. If you need more than 5, please open an issue here.

  • The body mapper just uses the JSON mapper.

Would you like to contribute to vlingo-http? Check vlingo/vlingo-http, check the issues and we will be glad to help you in the on-boarding.