.. | ||
src/vertx | ||
test | ||
.gitignore | ||
deps.edn | ||
LICENSE | ||
mvn-upload.sh | ||
README.md | ||
tools.clj |
vertx-clojure
A lightweight clojure adapter for vertx toolkit.
- STATUS: alpha, in design and prototyping phase.
- AUDIENCE: this is not a vertx documentation, this readme intends to explain only the clojure api
Example code on resources/user.clj
file.
Install
Using deps.edn
:
vertx-clojure/vertx {:mvn/version "0.0.0-SNAPSHOT"}
Using Leiningen:
[vertx-clojure/vertx "0.0.0-SNAPSHOT"]
User Guide
Verticles
Verticles is the basic "unit of execution" in the vertx toolkit. The concept is very simular to actors with the exception that a verticle does not have a inbox, and verticles communicates with other verticles or with the rest of the world using eventbus.
For create a verticle, you will need to create first a system instance
(a name that we give to the Vertx
instance):
(require '[vertx.core :as vc])
(def system (vc/system))
Then, you can proceed to create a verticle. A verticle concist on
three functions: on-start
, on-stop
and on-error
(where the
on-start
is mandatory the rest optional).
Lets define a dummy verticle that just prints hello world on start callback:
(defn on-start
[ctx]
(println "Hello world"))
(def dummy-verticle
(vc/verticle {:on-start on-start}))
The dummy-verticle
is a verticle factory, nothing is running at this
momment. For run the verticle we need to deploy it using the
previously created system
instance:
(vc/deploy! system dummy-verticle)
The deploy!
return value is a CompletionStage
so you can deref it
like a regular Future
or use funcool/promesa for chain more
complex transformations. The return value implements AutoCloseable
that will allow to undeploy the verticle.
The deploy!
function also accepts an additional parameter for
options, and at this momment it only accepts as single option:
:instances
- number of instances to launch of the same verticle.
Event Bus
The eventbus is the central communication system for verticles. It
has different patterns of communication. On this documentation we will
cover the: publish/subscribe
and request/reply
.
Lets define a simple echo verticle:
(require '[vertx.eventbus :as ve])
(defn on-message
[msg]
(:body msg))
(defn on-start
[ctx]
(vc/consumer ctx "test.echo" on-message))
(def echo-verticle
(vc/verticle {:on-start on-start}))
And then, lets deploy 4 instances of it:
(vc/deploy! system echo-verticle {:instances 4})
Now, depending on how you send the messages to the "test.echo" topic, the message will be send to a single instance of will be broadcasted to all verticle instances subscribed to it.
To send a message and expect a response we need to use the
ve/request!
function:
@(ve/request! system {:foo "bar"})
;; => #vertx.eventbus.Msg{:body {:foo "bar"}}
The return value of on-message
callback will be used as a reply and
it can be any plain value or a CompletionStage
.
When you want to send a message but you don't need the return value,
there is the ve/send!
function. And finally, if you want to send a
message to all instances subscribed to a topic, you will need to use
the ve/publish!
function.
Http Server (vertx.http)
STATUS: pre-alpha: experimental & incomplete
This part will explain the low-level api for the http server. It is intended to be used as a building block for a more higher-level api or when you know that you exactly need for a performance sensitive applications.
The vertx.http
exposes two main functions handler
and
server
. Lets start creating a simple "hello world" http server:
(require '[vertx.http :as vh])
(defn hello-world-handler
[req]
{:status 200
:body "Hello world\n"})
(defn on-start
[ctx]
(vh/server {:handler (vh/handler hello-world-handler)
:port 2021}))
(->> (vc/verticle {:on-start on-start})
(vc/deploy! system))
NOTE: you can start the server without creating a verticle but you will loss the advantage of scaling (using verticle instances parameter).
The req
object is a plain map with the following keys:
:method
the HTTP method.:path
the PATH of the requested URI.:headers
a map with string lower-cased keys of headers.:vertx.http/request
the underlying vertx request instance.:vertx.http/response
the underlying vertx response instance.
And the response object to the ring response, it can contain
:status
, :body
and :headers
.
WARNING: at this moment there are no way to obtain directly the body of request using clojure api, this is in design phase and we need to think how to expose it correctly without constraint too much the user code (if you have suggestions, please open an issue).
NOTE: If you want completly bypass the clojure api, pass a vertx
Handler
instance to server instead of using
vertx.http/handler
. There is the vertx.util/fn->handler
helper
that converts a plain clojure function into raw Handler
instance.
Web Server (vertx.web)
STATUS: alpha
This part will explain the higher-level http/web server api. It is a
general purpose with more clojure friendly api. It uses
reitit-core
for the routing and sieppari
for interceptors.
Lets start with a complete example:
(require '[vertx.http :as vh])
(require '[vertx.web :as vw])
(require '[vertx.web.interceptors :as vwi])
(defn hello-world-handler
[req]
{:status 200
:body "Hello world!\n"})
(defn on-start
[ctx]
(let [routes [["/" {:interceptors [(vwi/cookies)]
:all hello-world-handler}]]
handler (vw/handler ctx
(vw/assets "/static/*" {:root "resources/public/static"})
(vw/router routes))]
(vh/server {:handler handler
:port 2022})))
(->> (vc/verticle {:on-start on-start})
(vc/deploy! system))
The routes are defined using reitit-core
and the interceptors are
using sieppari
as underlying implementation. The request object is
very similar to the one explained in vertx.http
.
The main difference with vertx.http
is that the handler is called
when the body is ready to be used and is available under :body
keyword on the request.
All additional features such that reading the query/form params, parse/write cookies, cors and file uploads are provided with interceptors as pluggable pieces:
vertx.web.interceptors/uploads
parses the vertx uploaded file data structure and expose it as clojure maps under:uploads
key.vertx.web.interceptors/params
parses the query string and form params in the body if the content-type is appropriate and exposes them under:params
.vertx.web.interceptors/cors
properly sets the CORS headers.vertx.web.interceptors/cookies
handles the cookies reading from the request and cookies writing from the response.
License
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.