Eclipse Vert.x 3.7.0 released!

We are ex­tremely pleased to an­nounce that the Eclipse Vert.x ver­sion 3.7.0 has been re­leased.

It is an ex­cit­ing mile­stone for a cou­ple of rea­sons:

  1. it comes with great new fea­tures like the GraphQL ex­ten­sion for Vert.x Web.
  2. this is the last minor ver­sion be­fore Vert.x 4!

Be­fore we go throught the most no­table new fea­tures, we would like to thank all the con­trib­u­tors. Your par­tic­i­pa­tion has been es­sen­tial to this achieve­ment.

Vert.x Web GraphQL

Vert.x Web GraphQL ex­tends Vert.x Web with the GraphQL-​Java li­brary so that you can build a GraphQL server.

To use this new mod­ule, add the fol­low­ing to the de­pen­den­cies sec­tion of your Maven POM file:

<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-web-graphql</artifactId>
  <version>3.7.0</version>
</dependency>

Or, if you use Gra­dle:

compile 'io.vertx:vertx-web-graphql:3.7.0'

Then cre­ate a Vert.x Web Route and a GraphQLHandler for it:

// Setup the GraphQL-Java object
GraphQL graphQL = setupGraphQLJava();
// Use it to handle requests on a Vert.x Web route 
router.route("/graphql").handler(GraphQLHandler.create(graphQL));

The GraphQL han­dler sup­ports out of the box:

  • query con­text cus­tomiza­tion
  • GraphQL-​Java data load­ers
  • batch­ing on POST re­quests (com­pat­i­ble with the apollo-link-batch-http trans­port)

For de­tailed usage in­struc­tions, please refer to the Vert.x Web GraphQL doc­u­men­ta­tion.

Vert.x Cassandra Client

Object mapper support

Vert.x Cas­san­dra Client now sup­ports the cassandra-​driver-mapping mod­ule.

To en­able this fea­ture, you need to up­date your class­path by adding:

<dependency>
  <groupId>com.datastax.cassandra</groupId>
  <artifactId>cassandra-driver-mapping</artifactId>
  <version>3.7.1</version>
</dependency>

Then for a given en­tity:

@Table(keyspace = "test", name = "users")
class User {
  @PartitionKey String name;
  // ... other fields and methods 
}

You can re­trieve a map­per and ex­e­cute CRUD op­er­a­tions:

VertxMappingManager manager = VertxMappingManager.create(cassandraClient);
VertxMapper<User> mapper = manager.mapper(User.class, vertx);
mapper.save(new User("john", hander -> {}));

Collector API

The fea­ture al­lows to use Java col­lec­tors for query re­sults:

// Create a collector projecting a row set to a string in the form (last_name_1,last_name_2,...)
Collector<Row, ?, String> collector = Collectors.mapping(
    row -> row.getString("last_name"),
    Collectors.joining(",", "(", ")")
);

// Run the query with the collector
client.execute("SELECT * FROM users", collector, ar -> {
  if (ar.succeeded()) {
    // Result in the form (last_name_1,last_name_2,...)
    String result = ar.result();
  } else {
    System.out.println("Failure: " + ar.cause().getMessage());
  }
});

Cursor API

The ResultSet ob­ject has been en­hanced with ResultSet#several method, al­low­ing you to ob­tain sev­eral rows at once:

resultSet.several(30, ar -> {
  if (ar.succeeded()) {
    List<Row> result = ar.result();
  } else {
    System.out.println("Failure: " + ar.cause().getMessage());
  }
});

A very use­ful fea­ture for re­sult batch it­er­a­tions with­out re­sort­ing to stream­ing or fetch­ing all rows in mem­ory.

Client lifecyle

The client life­cyle has been re­vis­ited in 3.7.

Pre­vi­ously users ex­pected to connect man­u­ally be­fore send­ing re­quests. It was also pos­si­ble to disconnect a shared client thus fail­ing re­quests sent from an­other ver­ti­cle or part of the ap­pli­ca­tion.

Now it is no longer re­quired to man­u­ally con­nect a client (in fact, the method has been re­moved).

As soon as you re­trieve an in­stance you can start using it, the life­cyle is au­to­mat­i­cally man­aged:

CassandraClientOptions options = new CassandraClientOptions()
  .addContactPoint("node1.address")
  .addContactPoint("node2.address")
  .addContactPoint("node3.address")
  .setKeyspace("my_keyspace");
CassandraClient sharedClient = CassandraClient.createShared(vertx, "sharedClientName", options);
// Start sending requests to Cassandra with the client instance

Sim­i­larly, when the new close method is in­voked on a shared client, only the last ac­tive in­stance will ac­tu­ally dis­con­nect from Cas­san­dra:

// Disconnects only if this is the last running instance of the shared client
sharedClient.close();

Vert.x Redis Client

The Vert.x Redis client has been re­worked in­ter­nally and pro­vides now a new (more evo­lu­tion friendly) API.

The cur­rent API had the lim­i­ta­tion of being man­u­ally crafted after the redis API and in­volved many non con­tro­lable fea­tures such as auto re­con­nect, un­lim­ited buffer­ing of re­quests, etc… The new API of­fers a more vert.x-y ex­pe­ri­ence.

It just ex­poses the base client:

Redis
  .createClient(vertx, inetSocketAddress(7006, "127.0.0.1"))
  .connect(create -> {
    final Redis redis = create.result();

    redis.send(Request.cmd(Command.PING), send -> {
      // ... should reply with PONG
    });
  });

This has the ben­e­fits that you can now con­nect to Redis in any of it’s op­er­a­tion modes:

  • Sin­gle server
  • HA mode
  • Clus­ter mode

The API is de­cou­pled from the hand­crafted com­mands, which means that you can use new fea­tures such as:

A gen­er­ated helper RedisAPI is avail­able that can wrap the client to pro­vide a sim­i­lar ex­pe­ri­ence to the old API.

The main dif­fer­ence is that this new wrap­per is gen­er­ated from the COM­MAND com­mand, so the cor­rect API it al­ways ex­posed:

RedisAPI redis = RedisAPI.api(client);

redis.set(Arrays.asList("key1", "value1"), set -> {
  // ...
});

Vert.x AMQP Client

The Vert.x AMQP client al­lows re­ceiv­ing and send­ing AMQP mes­sages. It su­per­sedes the cur­rent AMQP bridge and pro­vide an API more flex­i­ble and very much user-​friendly.

The Vert.x AMQP client al­lows:

  • Con­nect­ing to an AMQP bro­ker or router - SASL and TLS con­nec­tions are sup­ported
  • Con­sum­ing mes­sage from a queue or a topic
  • Send­ing mes­sages to a queue or a topic
  • Check­ing ac­knowl­edge­ment for sent mes­sages

The AMQP 1.0 pro­to­col sup­port durable sub­scrip­tions, per­sis­tence, se­cu­rity, con­ver­sa­tions, so­phis­ti­cated rout­ing… More de­tails on the pro­to­col can be found on the AMQP home­page.

The Vert.x AMQP client is based on Vert.x Pro­ton. If you need fine-​grain con­trol, we rec­om­mend using Vert.x Pro­ton di­rectly.

To use this new mod­ule, add the fol­low­ing to the de­pen­den­cies sec­tion of your Maven POM file:

<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-amqp-client</artifactId>
  <version>3.7.0</version>
</dependency>

Or, if you use Gra­dle:

compile 'io.vertx:vertx-amqp-client:3.7.0'

Then, you can con­nect to an AMQP bro­ker:

AmqpClientOptions options = new AmqpClientOptions()
      .setHost("localhost")
      .setPort(5672)
      .setUsername("user")
      .setPassword("secret");
    
AmqpClient client = AmqpClient.create(vertx, options);

client.connect(ar -> {
  if (ar.failed()) {
    System.out.println("Unable to connect to the broker");
  } else {
    System.out.println("Connection succeeded");
    AmqpConnection connection = ar.result();

    // You can create receivers and senders
    connection.createReceiver("my-queue",
      msg -> {
        // called on every received messages
        System.out.println("Received " + msg.bodyAsString());
      },
      done -> {
        if (done.failed()) {
          System.out.println("Unable to create receiver");
        } else {
          AmqpReceiver receiver = done.result();
        }
      }
    );

    connection.createSender("my-queue", done -> {
      if (done.failed()) {
        System.out.println("Unable to create a sender");
      } else {
        AmqpSender sender = done.result();
        sender.send(AmqpMessage.create().withBody("hello").build());
      }
    });

  }
});

Stream pipes

When it comes to stream­ing, back-​pressure is some­thing you need to care about.

You have very much likely heard or used the Vert.x Pump API to trans­fer data from a read stream to a write stream while re­spect­ing the write stream back-​pressure.

The Pipe a new API su­per­sed­ing the Pump to achieve the same ef­fect and even more, it acts like a pump and han­dles for you

  • read stream pause/re­sume
  • write stream ter­mi­na­tion
  • stream fail­ures han­dling
  • asyn­chro­nous re­sult upon stream­ing com­ple­tion

You can trans­fer a read stream to a write stream sim­ply, the write stream will be ended upon com­ple­tion of the stream

readStream.pipeTo(writeStream);

You can also be no­ti­fied when the pipe com­pletes:

readStream.pipeTo(writeStream, ar -> {
  if (ar.succeeded()) {
    System.out.println("done");
  } else {
    System.out.println("failed " + ar.cause());
  }
});

Cre­at­ing and using an asyn­chro­nous pipe is easy

// The read stream will be paused until the pipe is used
Pipe<Buffer> pipe = readStream.pipe();
getAsyncPipe(ar -> {
  if (ar.succeeded()) {
    pipe.to(writeStream);
  } else {
    pipe.close();
  }
});

Kafka admin client

The new ver­sion brings a Vert.x based first im­ple­men­ta­tion of the na­tive Kafka Admin Client API which are in Java, in­stead of Scala used in the pre­vi­ous ver­sion.

The AdminUtils is now dep­re­cated and the new KafkaAdminClient is avail­able in­stead. It al­lows to re­move the last Scala ar­ti­fact de­pen­dency.

While the AdminUtils im­ple­men­ta­tion needs to con­nect to Zookeeper for ad­min­is­tra­tion pur­poses, the KafkaAdminClient only uses the Kafka boot­strap bro­kers con­nec­tion.

Properties config = new Properties();
config.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, "my-kafka-broker:9092");

KafkaAdminClient adminClient = KafkaAdminClient.create(vertx, config);

The fea­tures cur­rently sup­ported are:

  • cre­ate and delete top­ics
  • list all the top­ics
  • de­scribe top­ics for get­ting in­for­ma­tion about leader par­ti­tion, fol­lower repli­cas and ISR (in-​sync repli­cas) list
  • alter top­ics con­fig­u­ra­tion
  • list all con­sumer groups
  • de­scribe con­sumer groups for get­ting in­for­ma­tion like the state, the co­or­di­na­tor host, con­sumers per top­ics and so on

If you are using the AdminUtils today, con­sider mi­grate to the new KafkaAdminClient be­cause the for­mer will be re­moved in Vert.x 4.0.

And more…

Here are some other im­por­tant im­prove­ments you can find in this re­lease:

  • Shared data struc­tures avail­able in local-​only mode even when Vert.x is clus­tered
  • JSON de­cod­ing with­out prior knowl­edge of the struc­ture (ob­ject, array, string, …etc)
  • In­fin­is­pan Clus­ter Man­ager up­graded to In­fin­is­pan 9.4.10.Final
  • And ob­vi­ously we have the usual bug fixes!

Finally

The 3.7.0 re­lease notes can be found on the wiki, as well as the list of dep­re­ca­tions and break­ing changes

Docker im­ages are avail­able on Docker Hub.

The Vert.x dis­tri­b­u­tion can be down­loaded on the web­site but is also avail­able from SD­KMan and Home­Brew.

The event bus client using the SockJS bridge is avail­able from:

The re­lease ar­ti­facts have been de­ployed to Maven Cen­tral and you can get the dis­tri­b­u­tion on Bin­tray.

That’s it! Happy cod­ing and see you soon on our user or dev chan­nels.

Next post

Eclipse Vert.x 3.7.1

We have just released Vert.x 3.7.1, a bug fix release of Vert.x 3.7.x and a few small features.

Read more
Previous post

Eclipse Vert.x 3.6.3

We have just released Vert.x 3.6.3, a bug fix release of Vert.x 3.6.x.

Read more
Related posts

Building services and APIs with AMQP 1.0

Microservices and APIs are everywhere. Everyone talks about them, presentation slides are full of them ... some people are actually even building them.

Read more

Eclipse Vert.x 4 milestone 5 released!

We are extremely pleased to announce the fifth 4.0 milestone release of Eclipse Vert.x. This release aims to provide a reliable distribution of the current development of Vert.x 4.

Read more

Some Rest with Vert.x

This post is part of the Introduction to Vert.x series. Let’s go a bit further this time and develop a CRUD-ish application

Read more