PolarSPARC |
Introduction to Vert.x - Part 5
Bhaskar S | 06/07/2019 |
Overview
In Part-4 of this series, we explored the distributed cluster mode of the EventBus using Hazelcast, which allowed Verticle(s) running on different JVMs to communicate with each other. With that, we have covered all the foundational concepts in Vert.x.
In this part, we will use what we learnt thus far to develop and test a REST based microservice. We could have used the HttpServer class from vertx-core. Instead, we will be using vertx-web to build the REST based microservice, since it is much more easier and simpler to implement microservices.
Hands-on with Vert.x - 5
The Vert.x Web extension (vertx-web) uses a router object to dispatch HTTP requests to the appropriate handlers. Request routing could be based on the HTTP method or the URI path. In addition, there are many helper methods that allow for easy manipulation of HTTP headers/cookies, getting access to HTTP request parameters, etc.
The following is the modified listing of the Maven project file pom.xml that includes the additional libraries vertx-web and lombok as dependencies:
In this part, we will develop a very simple REST based Contacts Management microservice that exposes the following capabilities:
Each Contact entity captures the first name, last name, email id, and mobile number of a person.
Our microservice will be very *SIMPLE* and will not handle multiple contacts with the same last name.
The following is the listing for the Contact entity:
Notice that we are using lombok to generate the all-parameter constructor, getters, and setters.
For this use-case, we will keep things simple and persist the contact information in the JVM memory rather than in a database.
We started off in Part-1 by indicating that the current trend is to build loosely-coupled microservices. This implies we should decouple the REST persistence layer from the REST service layer. To do that, we will leverage the messaging layer EventBus to communicate between the persistence layer and the service layer using well-defined COMMANDs.
The following is the listing for the Commands entity that defines all the commands and fields that will be exchanged via messages (in JSON format) between the persistence layer and the service layer:
The following is the listing for the contacts management persistence layer Sample10.java:
Let us explain and understand the code from Sample10 listed above.
The class Sample10 represents the persistence layer. It creates 4 sample contacts and stores it in a Java java.util.HashMap indexed by the last-name (see the method initFakeContacts()).
The verticle com.polarsparc.Vertx.Sample10.CommandConsumerVerticle is the consumer of the command messages from the EventBus. The incoming command messages are in the form:
{"command":"<COMMAND_NAME>" [,"payload":"{<NAME_VALUE_PAIRS>}"]}
Once the command is processed, a reply goes back to the sender (the service layer) in the form:
{"errorcode":"<0|1>" [,"payload":"{<NAME_VALUE_PAIRS>}"]}
The class io.vertx.core.json.JsonObject is the representation of a JSON string as a Java object. One can initialize an object instance from a JSON string.
The method getString(ELEMENT) on an instance of JsonObject allows one to access the value of a JSON ELEMENT.
The method put(ELEMENT, VALUE) on an instance of JsonObject allows one to add a JSON ELEMENT with VALUE.
The static method mapFrom(OBJECT) on the class JsonObject allows one to convert an OBJECT to an instance of type JsonObject.
The method encode() on an instance of JsonObject converts to a JSON string.
The class io.vertx.core.json.JsonArray is the representation of a JSON array as a Java object. One can initialize an object instance from a java.util.List of Java objects.
The following is the listing for the contacts management service layer Sample11.java:
Let us explain and understand the code from Sample11 listed above.
The class Sample11 represents the service layer, which communicates with the persistence layer (Sample10) via message passing through the EventBus.
The class io.vertx.ext.web.Router manages one or more routes (that are based on a HTTP method or a request URI path). It takes the request from the HttpServer and dispatches it to the appropriate handler for that route.
The static method router(Vertx) on the class Router creates an instance of type Router for a given instance of Vertx.
The class io.vertx.ext.web.RoutingContext encapsulates the context for handling a web request from the HttpServer. It provides access to the various pieces of data pertaining to the HTTP request, such as the headers, parameters, cookies, the body, etc.
The class io.vertx.ext.web.handler.BodyHandler is the handler that fetches the request body from the HttpServer and sets it on the instance of RoutingContext .
The static method create() on the class BodyHandler creates an instance of type BodyHandler with default settings. By default, file uploads is enabled for this handler. The method setHandleFileUploads(false) disables file uploads.
The call router.route().handler(BodyHandler.create().setHandleFileUploads(false)) sets the default body handler to fetch the request body for all the routes.
Every request handler method must be of the form void method(RoutingContext) with one method argument of type RoutingContext.
The call router.delete(PATH/:PARAM").handler(T) registers a request handler of type T for the HTTP method DELETE on the PATH with the :PARAM as the user specified parameter. For example, for the route /api/v1/contacts/getByLastName/c3p0, PATH = /api/v1/contacts/getByLastName/ and PARAM = c3p0. The value for the parameter :PARAM can be accessed through the RoutingContext. For our REST based microservice, the DELETE method is used to delete an existing contact.
The call router.get(PATH/:PARAM").handler(T) registers a request handler of type T for the HTTP method GET on the PATH with the :PARAM as the user specified parameter. For our REST based microservice, the GET method is used to fetch an existing contact.
The call router.post(PATH/").handler(T) registers a request handler of type T for the HTTP method POST on the PATH. For our REST based microservice, the POST method is used to create a new contact.
The call router.put(PATH/:PARAM").handler(T) registers a request handler of type T for the HTTP method PUT on the PATH with the :PARAM as the user specified parameter. For our REST based microservice, the PUT method is used to update an existing contact.
The following is the pictorial illustration for one of the services getByLastName (happy path):
The following is the pictorial illustration for the same service getByLastName (exception path):
Since we have added support for REST based services, we need to tweak the shell script called run.sh as shown below:
#!/bin/sh
JARS=""
for f in `ls ./lib/jackson*`
do
JARS=$JARS:$f
done
for f in `ls ./lib/netty*`
do
JARS=$JARS:$f
done
JARS=$JARS:./lib/vertx-core-3.7.0.jar:./lib/vertx-config-3.7.0.jar:./lib/hazelcast-3.10.5.jar:./lib/vertx-hazelcast-3.7.0.jar:./lib/vertx-web-3.7.0.jar
echo $JARS
java -Dvertx.hazelcast.config=./resources/my-cluster.xml -cp ./classes:./resources:$JARS com.polarsparc.Vertx.$1 $2
To start the contacts management persistence layer, open a new Terminal window and execute the following command:
./bin/run.sh Sample10
The following would be the typical output:
:./lib/jackson-annotations-2.9.0.jar:./lib/jackson-core-2.9.8.jar:./lib/jackson-databind-2.9.8.jar:./lib/netty-buffer-4.1.30.Final.jar:./lib/netty-codec-4.1.30.Final.jar:./lib/netty-codec-dns-4.1.30.Final.jar:./lib/netty-codec-http2-4.1.30.Final.jar:./lib/netty-codec-http-4.1.30.Final.jar:./lib/netty-codec-socks-4.1.30.Final.jar:./lib/netty-common-4.1.30.Final.jar:./lib/netty-handler-4.1.30.Final.jar:./lib/netty-handler-proxy-4.1.30.Final.jar:./lib/netty-resolver-4.1.30.Final.jar:./lib/netty-resolver-dns-4.1.30.Final.jar:./lib/netty-transport-4.1.30.Final.jar:./lib/vertx-core-3.7.0.jar:./lib/vertx-config-3.7.0.jar:./lib/hazelcast-3.10.5.jar:./lib/vertx-hazelcast-3.7.0.jar:./lib/vertx-web-3.7.0.jar Jun 07, 2019 8:59:07 PM com.hazelcast.instance.AddressPicker INFO: [LOCAL] [polarsparc] [3.10.5] Interfaces is enabled, trying to pick one address matching to one of: [127.0.0.1] Jun 07, 2019 8:59:08 PM com.hazelcast.instance.AddressPicker INFO: [LOCAL] [polarsparc] [3.10.5] Picked [127.0.0.1]:5701, using socket ServerSocket[addr=/0:0:0:0:0:0:0:0,localport=5701], bind any local is true Jun 07, 2019 8:59:08 PM com.hazelcast.system INFO: [127.0.0.1]:5701 [polarsparc] [3.10.5] Hazelcast 3.10.5 (20180913 - 6ffa2ee) starting at [127.0.0.1]:5701 Jun 07, 2019 8:59:08 PM com.hazelcast.system INFO: [127.0.0.1]:5701 [polarsparc] [3.10.5] Copyright (c) 2008-2018, Hazelcast, Inc. All Rights Reserved. Jun 07, 2019 8:59:08 PM com.hazelcast.system INFO: [127.0.0.1]:5701 [polarsparc] [3.10.5] Configured Hazelcast Serialization version: 1 Jun 07, 2019 8:59:08 PM com.hazelcast.instance.Node INFO: [127.0.0.1]:5701 [polarsparc] [3.10.5] A non-empty group password is configured for the Hazelcast member. Starting with Hazelcast version 3.8.2, members with the same group name, but with different group passwords (that do not use authentication) form a cluster. The group password configuration will be removed completely in a future release. Jun 07, 2019 8:59:08 PM com.hazelcast.spi.impl.operationservice.impl.BackpressureRegulator INFO: [127.0.0.1]:5701 [polarsparc] [3.10.5] Backpressure is disabled Jun 07, 2019 8:59:08 PM com.hazelcast.spi.impl.operationservice.impl.InboundResponseHandlerSupplier INFO: [127.0.0.1]:5701 [polarsparc] [3.10.5] Running with 2 response threads Jun 07, 2019 8:59:08 PM com.hazelcast.instance.Node INFO: [127.0.0.1]:5701 [polarsparc] [3.10.5] Creating TcpIpJoiner Jun 07, 2019 8:59:08 PM com.hazelcast.spi.impl.operationexecutor.impl.OperationExecutorImpl INFO: [127.0.0.1]:5701 [polarsparc] [3.10.5] Starting 16 partition threads and 9 generic threads (1 dedicated for priority tasks) Jun 07, 2019 8:59:08 PM com.hazelcast.internal.diagnostics.Diagnostics INFO: [127.0.0.1]:5701 [polarsparc] [3.10.5] Diagnostics disabled. To enable add -Dhazelcast.diagnostics.enabled=true to the JVM arguments. Jun 07, 2019 8:59:08 PM com.hazelcast.core.LifecycleService INFO: [127.0.0.1]:5701 [polarsparc] [3.10.5] [127.0.0.1]:5701 is STARTING WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by com.hazelcast.internal.networking.nio.SelectorOptimizer (file:/home/bswamina/Downloads/TTT/lib/hazelcast-3.10.5.jar) to field sun.nio.ch.SelectorImpl.selectedKeys WARNING: Please consider reporting this to the maintainers of com.hazelcast.internal.networking.nio.SelectorOptimizer WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release Jun 07, 2019 8:59:08 PM com.hazelcast.nio.tcp.TcpIpConnector INFO: [127.0.0.1]:5701 [polarsparc] [3.10.5] Connecting to /127.0.0.1:5703, timeout: 0, bind-any: true Jun 07, 2019 8:59:08 PM com.hazelcast.nio.tcp.TcpIpConnector INFO: [127.0.0.1]:5701 [polarsparc] [3.10.5] Connecting to /127.0.0.1:5702, timeout: 0, bind-any: true Jun 07, 2019 8:59:08 PM com.hazelcast.nio.tcp.TcpIpConnector INFO: [127.0.0.1]:5701 [polarsparc] [3.10.5] Could not connect to: /127.0.0.1:5702. Reason: SocketException[Connection refused to address /127.0.0.1:5702] Jun 07, 2019 8:59:08 PM com.hazelcast.nio.tcp.TcpIpConnector INFO: [127.0.0.1]:5701 [polarsparc] [3.10.5] Could not connect to: /127.0.0.1:5703. Reason: SocketException[Connection refused to address /127.0.0.1:5703] Jun 07, 2019 8:59:08 PM com.hazelcast.cluster.impl.TcpIpJoiner INFO: [127.0.0.1]:5701 [polarsparc] [3.10.5] [127.0.0.1]:5702 is added to the blacklist. Jun 07, 2019 8:59:08 PM com.hazelcast.cluster.impl.TcpIpJoiner INFO: [127.0.0.1]:5701 [polarsparc] [3.10.5] [127.0.0.1]:5703 is added to the blacklist. Jun 07, 2019 8:59:09 PM com.hazelcast.system INFO: [127.0.0.1]:5701 [polarsparc] [3.10.5] Cluster version set to 3.10 Jun 07, 2019 8:59:09 PM com.hazelcast.internal.cluster.ClusterService INFO: [127.0.0.1]:5701 [polarsparc] [3.10.5] Members {size:1, ver:1} [ Member [127.0.0.1]:5701 - 2e2a1777-ddc3-4489-80cd-1b35c3789bf8 this ] Jun 07, 2019 8:59:09 PM com.hazelcast.core.LifecycleService INFO: [127.0.0.1]:5701 [polarsparc] [3.10.5] [127.0.0.1]:5701 is STARTED Jun 07, 2019 8:59:10 PM com.hazelcast.internal.partition.impl.PartitionStateManager INFO: [127.0.0.1]:5701 [polarsparc] [3.10.5] Initializing cluster partition table arrangement... Jun 07, 2019 8:59:10 PM com.polarsparc.Vertx.Sample10 lambda$1 INFO: Deployed command consumer instance ID: 578f4d29-8863-4e5e-9744-833662a6baaf
To start the contacts management service layer, open a new Terminal window and execute the following command:
./bin/run.sh Sample11
The following would be the typical output:
:./lib/jackson-annotations-2.9.0.jar:./lib/jackson-core-2.9.8.jar:./lib/jackson-databind-2.9.8.jar:./lib/netty-buffer-4.1.30.Final.jar:./lib/netty-codec-4.1.30.Final.jar:./lib/netty-codec-dns-4.1.30.Final.jar:./lib/netty-codec-http2-4.1.30.Final.jar:./lib/netty-codec-http-4.1.30.Final.jar:./lib/netty-codec-socks-4.1.30.Final.jar:./lib/netty-common-4.1.30.Final.jar:./lib/netty-handler-4.1.30.Final.jar:./lib/netty-handler-proxy-4.1.30.Final.jar:./lib/netty-resolver-4.1.30.Final.jar:./lib/netty-resolver-dns-4.1.30.Final.jar:./lib/netty-transport-4.1.30.Final.jar:./lib/vertx-core-3.7.0.jar:./lib/vertx-config-3.7.0.jar:./lib/hazelcast-3.10.5.jar:./lib/vertx-hazelcast-3.7.0.jar:./lib/vertx-web-3.7.0.jar Jun 07, 2019 8:59:13 PM com.hazelcast.instance.AddressPicker INFO: [LOCAL] [polarsparc] [3.10.5] Interfaces is enabled, trying to pick one address matching to one of: [127.0.0.1] Jun 07, 2019 8:59:13 PM com.hazelcast.instance.AddressPicker INFO: [LOCAL] [polarsparc] [3.10.5] Picked [127.0.0.1]:5702, using socket ServerSocket[addr=/0:0:0:0:0:0:0:0,localport=5702], bind any local is true Jun 07, 2019 8:59:13 PM com.hazelcast.system INFO: [127.0.0.1]:5702 [polarsparc] [3.10.5] Hazelcast 3.10.5 (20180913 - 6ffa2ee) starting at [127.0.0.1]:5702 Jun 07, 2019 8:59:13 PM com.hazelcast.system INFO: [127.0.0.1]:5702 [polarsparc] [3.10.5] Copyright (c) 2008-2018, Hazelcast, Inc. All Rights Reserved. Jun 07, 2019 8:59:13 PM com.hazelcast.system INFO: [127.0.0.1]:5702 [polarsparc] [3.10.5] Configured Hazelcast Serialization version: 1 Jun 07, 2019 8:59:13 PM com.hazelcast.instance.Node INFO: [127.0.0.1]:5702 [polarsparc] [3.10.5] A non-empty group password is configured for the Hazelcast member. Starting with Hazelcast version 3.8.2, members with the same group name, but with different group passwords (that do not use authentication) form a cluster. The group password configuration will be removed completely in a future release. Jun 07, 2019 8:59:13 PM com.hazelcast.spi.impl.operationservice.impl.BackpressureRegulator INFO: [127.0.0.1]:5702 [polarsparc] [3.10.5] Backpressure is disabled Jun 07, 2019 8:59:13 PM com.hazelcast.spi.impl.operationservice.impl.InboundResponseHandlerSupplier INFO: [127.0.0.1]:5702 [polarsparc] [3.10.5] Running with 2 response threads Jun 07, 2019 8:59:13 PM com.hazelcast.instance.Node INFO: [127.0.0.1]:5702 [polarsparc] [3.10.5] Creating TcpIpJoiner Jun 07, 2019 8:59:14 PM com.hazelcast.spi.impl.operationexecutor.impl.OperationExecutorImpl INFO: [127.0.0.1]:5702 [polarsparc] [3.10.5] Starting 16 partition threads and 9 generic threads (1 dedicated for priority tasks) Jun 07, 2019 8:59:14 PM com.hazelcast.internal.diagnostics.Diagnostics INFO: [127.0.0.1]:5702 [polarsparc] [3.10.5] Diagnostics disabled. To enable add -Dhazelcast.diagnostics.enabled=true to the JVM arguments. Jun 07, 2019 8:59:14 PM com.hazelcast.core.LifecycleService INFO: [127.0.0.1]:5702 [polarsparc] [3.10.5] [127.0.0.1]:5702 is STARTING WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by com.hazelcast.internal.networking.nio.SelectorOptimizer (file:/home/bswamina/Downloads/TTT/lib/hazelcast-3.10.5.jar) to field sun.nio.ch.SelectorImpl.selectedKeys WARNING: Please consider reporting this to the maintainers of com.hazelcast.internal.networking.nio.SelectorOptimizer WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release Jun 07, 2019 8:59:14 PM com.hazelcast.nio.tcp.TcpIpConnector INFO: [127.0.0.1]:5702 [polarsparc] [3.10.5] Connecting to /127.0.0.1:5703, timeout: 0, bind-any: true Jun 07, 2019 8:59:14 PM com.hazelcast.nio.tcp.TcpIpConnector INFO: [127.0.0.1]:5702 [polarsparc] [3.10.5] Could not connect to: /127.0.0.1:5703. Reason: SocketException[Connection refused to address /127.0.0.1:5703] Jun 07, 2019 8:59:14 PM com.hazelcast.cluster.impl.TcpIpJoiner INFO: [127.0.0.1]:5702 [polarsparc] [3.10.5] [127.0.0.1]:5703 is added to the blacklist. Jun 07, 2019 8:59:14 PM com.hazelcast.nio.tcp.TcpIpConnector INFO: [127.0.0.1]:5702 [polarsparc] [3.10.5] Connecting to /127.0.0.1:5701, timeout: 0, bind-any: true Jun 07, 2019 8:59:14 PM com.hazelcast.nio.tcp.TcpIpConnectionManager INFO: [127.0.0.1]:5702 [polarsparc] [3.10.5] Established socket connection between /127.0.0.1:35785 and /127.0.0.1:5701 Jun 07, 2019 8:59:15 PM com.hazelcast.system INFO: [127.0.0.1]:5702 [polarsparc] [3.10.5] Cluster version set to 3.10 Jun 07, 2019 8:59:15 PM com.hazelcast.internal.cluster.ClusterService INFO: [127.0.0.1]:5702 [polarsparc] [3.10.5] Members {size:2, ver:2} [ Member [127.0.0.1]:5701 - 2e2a1777-ddc3-4489-80cd-1b35c3789bf8 Member [127.0.0.1]:5702 - 0e9c8e93-4aea-4eb6-a309-fb53c576ddd3 this ] Jun 07, 2019 8:59:16 PM com.hazelcast.core.LifecycleService INFO: [127.0.0.1]:5702 [polarsparc] [3.10.5] [127.0.0.1]:5702 is STARTED Jun 07, 2019 8:59:16 PM io.vertx.config.impl.ConfigRetrieverImpl INFO: Config file path: conf/config.json, format:json Jun 07, 2019 8:59:16 PM com.polarsparc.Vertx.Sample11$ContactsServiceVerticle lambda$0 INFO: Configured server port: 8080 Jun 07, 2019 8:59:16 PM com.polarsparc.Vertx.Sample11$ContactsServiceVerticle lambda$6 INFO: Started contacts service on localhost:8080... Jun 07, 2019 8:59:16 PM com.polarsparc.Vertx.Sample11 lambda$2 INFO: Deployed contacts service instance ID: 1eccf68f-c228-4aad-8a49-cabb5880d30c
To test the contacts management microservice, we will use the Linux curl command.
Open a new Terminal window and execute the following command to fetch all the contacts:
curl -v http://localhost:8080/api/contacts/v1/getAll
The following would be the typical output:
* Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 8080 (#0) > GET /api/contacts/v1/getAll HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.64.1 > Accept: */* > < HTTP/1.1 200 OK < content-type: application/json < content-length: 475 < * Connection #0 to host localhost left intact {"errcode":0,"payload":"[{\"firstName\":\"Dummy\",\"lastName\":\"Cracker\",\"emailId\":\"dummy@cracker.org\",\"mobile\":\"000-000-0000\"},{\"firstName\":\"Alice\",\"lastName\":\"Earthling\",\"emailId\":\"alice@earth.io\",\"mobile\":\"123-456-1100\"},{\"firstName\":\"Bob\",\"lastName\":\"Martian\",\"emailId\":\"bob@mars.co\",\"mobile\":\"789-123-1080\"},{\"firstName\":\"Charlie\",\"lastName\":\"Drummer\",\"emailId\":\"charlie@musician.org\",\"mobile\":\"666-777-9006\"}]"} * Closing connection 0
Next, execute the following command to fetch the contact for the person with the last-name Martian:
curl -v http://localhost:8080/api/contacts/v1/getByLastName/Martian
The following would be the typical output:
* Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 8080 (#0) > GET /api/contacts/v1/getByLastName/Martian HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.64.1 > Accept: */* > < HTTP/1.1 200 OK < content-type: application/json < content-length: 130 < * Connection #0 to host localhost left intact {"errcode":0,"payload":"{\"firstName\":\"Bob\",\"lastName\":\"Martian\",\"emailId\":\"bob@mars.co\",\"mobile\":\"789-123-1080\"}"} * Closing connection 0
Now, execute the following command to fetch the contact for the person with the last-name Jupiter:
curl -v http://localhost:8080/api/contacts/v1/getByLastName/Jupiter
The following would be the typical output:
* Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 8080 (#0) > GET /api/contacts/v1/getByLastName/Jupiter HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.64.1 > Accept: */* > < HTTP/1.1 200 OK < content-type: application/json < content-length: 13 < * Connection #0 to host localhost left intact {"errcode":1} * Closing connection 0
Next, execute the following command to update the contact for the person with the last-name Drummer:
curl -v -d "{\"mobile\":\"300-111-2222\"}" -X PUT http://localhost:8080/api/contacts/v1/updateByLastName/Drummer
The following would be the typical output:
* Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 8080 (#0) > PUT /api/contacts/v1/updateByLastName/Drummer HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.64.1 > Accept: */* > Content-Length: 25 > Content-Type: application/x-www-form-urlencoded > * upload completely sent off: 25 out of 25 bytes < HTTP/1.1 200 OK < content-type: application/json < content-length: 143 < * Connection #0 to host localhost left intact {"errcode":0,"payload":"{\"firstName\":\"Charlie\",\"lastName\":\"Drummer\",\"emailId\":\"charlie@musician.org\",\"mobile\":\"300-111-2222\"}"} * Closing connection 0
Now, execute the following command to delete the contact for the person with the last-name Cracker:
curl -v -X DELETE http://localhost:8080/api/contacts/v1/deleteByLastName/Cracker
The following would be the typical output:
* Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 8080 (#0) > DELETE /api/contacts/v1/deleteByLastName/Cracker HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.64.1 > Accept: */* > < HTTP/1.1 200 OK < content-type: application/json < content-length: 138 < * Connection #0 to host localhost left intact {"errcode":0,"payload":"{\"firstName\":\"Dummy\",\"lastName\":\"Cracker\",\"emailId\":\"dummy@cracker.org\",\"mobile\":\"000-000-0000\"}"} * Closing connection 0
Finally, execute the following command to add a new contact:
curl -v -d "{\"fname\":\"Frank\",\"lname\":\"Polymer\",\"email\":\"frank_p@spacelab.io\",\"mobile\":\"777-888-9999\"}" -X POST http://localhost:8080/api/contacts/v1/addContact
The following would be the typical output:
* Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 8080 (#0) > POST /api/contacts/v1/addContact HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.64.1 > Accept: */* > Content-Length: 89 > Content-Type: application/x-www-form-urlencoded > * upload completely sent off: 89 out of 89 bytes < HTTP/1.1 200 OK < content-type: application/json < content-length: 140 < * Connection #0 to host localhost left intact {"errcode":0,"payload":"{\"firstName\":\"Frank\",\"lastName\":\"Polymer\",\"emailId\":\"frank_p@spacelab.io\",\"mobile\":\"777-888-9999\"}"} * Closing connection 0
More to be covered in the next and final part of this series ... 😎
References
[1] Introduction to Vert.x - Part-1
[2] Introduction to Vert.x - Part-2
[3] Introduction to Vert.x - Part-3