Introducing YOKE a middleware framework for Vert.x

3,970 views
Skip to first unread message

Paulo Lopes

unread,
Apr 19, 2013, 5:26:49 AM4/19/13
to ve...@googlegroups.com
Yoke

Yoke is a project that I've been working on for the last couple of weeks.

The purpose of Yoke is to provide a easy way to build web applications or web frameworks on top of Vert.x with a simple API.

Yoke has no external dependencies, however it is meant to be extended.

Yoke is a chain executor framework for Vert.x, it was modeled after Connect (see http://www.senchalabs.org/connect/) and right now is bundled with 12 middleware components and if you are interested you can write 3rd party middlewares to be added to the project.

Usage

The usage at the moment is Java only and I am planning to create bindings for other languages that run on Vert.x.

import com.jetdrone.vertx.yoke.middleware.*;
import org.vertx.java.core.Handler;
import org.vertx.java.core.http.HttpServerRequest;
import org.vertx.java.platform.Verticle;

public class Tester extends Verticle {

    @Override
    public void start() {
        Yoke yoke = new Yoke(vertx);

        yoke.use(new Static("public"));
        yoke.use(new Router() {{
            all("/hello", new Handler<HttpServerRequest>() {
                @Override
                public void handle(HttpServerRequest request) {
                    request.response().end("Hello World!");
                }
            });
        }});

        yoke.listen(3000);
    }
}

The API is quite simple, you start a chain (Yoke) with the Vertx instance. This Vertx instance is the shared by all middleware (Yoke will make sure of this) you you don't need to pass it to all middleware constructors.

Then you chain Middleware with the method use(), in this case I chain the static file server and a the custom router middleware (which works in a similar way to the RouteMatcher).

When running this verticle all requests will first try to find a matching file on the file system under the "public" directory if that fails the router will try to match the request path to "/hello" and run that handler, if that fails and error is raised.

Installation

Just pull the jar to your module lib. I am in the process of uploading the artifact to maven central.

Bundled Middleware

  • BasicAuth - basic http authentication
  • BodyParser - extensible request body parser, internally it will parse the request body and populate the field body on the HttpServerRequest object with either:
    • JsonObject if content-type was application/json
    • Map<String, Object> if content-type was application/x-www-form-urlencoded
    • Map<String, Object> plus field files (Map<String, UploadFile>) if content-type was multipart/form-data
  • CookieParser - populates the field cookies on the request and verifies if they are signed
  • ErrorHandler - Pretty error messages either in html/json/text
  • Favicon - generate a proper favicon.ico for your app
  • Limit - Limit the request body to a specific amount of bytes
  • MethodOverride - faux HTTP method support
  • ResponseTime - calculates response-time and exposes via X-Response-Time
  • Router - Route Matcher like Vertx one but allows also responses to be chainable
  • Static - static file server (with proper caching headers) and optional directory listing
  • Timeout - request timeouts do not allow long running requests
  • Vhosts - virtual host sub-domain mapping middleware

Links


Message has been deleted

spriet2000

unread,
Apr 20, 2013, 6:49:09 AM4/20/13
to ve...@googlegroups.com
Nice implementation of the connect like api!

Paulo Lopes

unread,
Apr 20, 2013, 3:06:41 PM4/20/13
to ve...@googlegroups.com
Yes that was my main goal. I am still creating the documentation site, it will take some time.

For now I am stabilizing the API. I have it reduced to 4 classes:

  • Yoke - The main class
  • Middleware - abstract class that all middleware extends
  • Engine - abstract class for template engines
  • MimeType - mime type identifier
After that I have 2 extra helper classes:

  • YokeHttpServerRequest - implements the HttpServerRequest and extends Map<String, Object> so we can add properties to the request like on node.js plus some helper accessors to cookies, uploaded files etc...
  • YokeHttpServerResponse - implements HttpServerResponse and adds methods for the rendering engines to allow response.render(template_file)

Tim Fox

unread,
Apr 21, 2013, 4:25:29 AM4/21/13
to ve...@googlegroups.com
Nice.

Is this Java only? Any plans to support other langs?
--
You received this message because you are subscribed to the Google Groups "vert.x" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vertx+un...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Paulo Lopes

unread,
Apr 21, 2013, 5:09:53 AM4/21/13
to ve...@googlegroups.com
I plan to support other languages too. I will implement a groovy extension using closures to make it more productive to groovy developers but unfortunately I've no experience with writing bindings for other languages such as jython, jruby and javascript. If someone can share some help it would be appreciated.

But this project is done on my spare time, so i cannot promise any time-frame for this.

The planning now is to complete the API site which is has lots of incomplete links, and then start with the groovy bindings.

Daryl Teo

unread,
Apr 21, 2013, 8:34:58 AM4/21/13
to ve...@googlegroups.com
Nice work.

I've been working on mine for a long time but unfortunately work has kept me occupied :(

No point doubling effort. I do not believe I can continue working on mine in the long term so will possibly contribute to yours.

Daryl

Sebastien Blanc

unread,
Apr 21, 2013, 3:06:36 PM4/21/13
to ve...@googlegroups.com
Speaking about reinventing the wheel ... I'm also working on a Web Framework, based on the Rails and Grails concepts, for now based based on Groovy with a lot of configuration over Configuration, Keep it simple and don't repeat yourself : KISS DRY COC
Hope to publish a first version into 2 weeks ...
Seb

froz3n

unread,
Apr 21, 2013, 10:38:46 PM4/21/13
to ve...@googlegroups.com
Nice work Paulo!

I did not know "Connect" but does seem to have a nice API. Will definitely git it a try.
Is this for 1.3 or 2.0? Or supporting both?

Paulo Lopes

unread,
Apr 22, 2013, 4:07:35 AM4/22/13
to ve...@googlegroups.com
Hi Daryl,

Indeed I tried to check your github project but all I saw as a Promisses library. As I stated, my goal is not to build a full web framework but a modular component library to easy the build of such a project.

The reason behind this, is that in my opinion building a full web framework is a complex task for just one person, there are just to many things to implement. So I decided to use the old approach of divide and conquer, by first creating a chain executor (Yoke) and the implement common tasks, e.g.: server static files, generate error pages, parse request bodies, parse cookies, handle file uploads, serve favicons, delegate to other server if the host header matches a regular expression, timeout a request if it takes too long...

Although these are tasks that a web framework should have, there are tons of others missing (this is where you could help :))

I've a interface for rendering engines, but no rendering engine, say you want to generate JSPs then you register the JSP engine with Yoke and in your response object you can call request.response().render("path to jsp file"), maybe JSP is crap, maybe something like jade? or mustache, or whatever...

As you can imagine there is lots of things that can be done, here are some more examples:
  • session management
  • response compression
  • logging (say something like apache logs....)
  • Cross Site Request Forgery security
  • OAuth implementation...
My goal is to have as many middleware as possible but each one of them as simple as possible.

Once there is a decent amount of middleware it is possible to make a selection and tag it as a basic web framework, in the same way expressjs is a webframework on top of connect.

Paulo Lopes

unread,
Apr 22, 2013, 4:10:48 AM4/22/13
to ve...@googlegroups.com
At the moment it is Vert.x 2.x only because of the API changes but i think it could be backported to 1.3x series without much of an hassle.
I am planning to support 2.x for now since I only work on it on my free time, If there is a need I can port it to the 1.3.

Cheers,
Paulo

Finn Bock

unread,
Apr 22, 2013, 5:14:47 PM4/22/13
to ve...@googlegroups.com
It look very nice.

I tried it and found a small problem on windows where the code
   Favicon.class.getResource("favicon.ico").getPath()
does not return an actual filesystem path but instead a value like.

/D:/vertx/test-yoke/mods/com.jetdrone~yoke~1.0.0-SNAPSHOT/com/jetdrone/vertx/yoke/middleware/favicon.ico

where the initial "/" char means the path can not by opened with the fileSystem() classes.

Paulo Lopes

unread,
Apr 23, 2013, 5:44:10 AM4/23/13
to ve...@googlegroups.com
Thanks for noting that, i've created a issue on github and will look into it.

Paulo Lopes

unread,
Apr 23, 2013, 7:38:05 AM4/23/13
to ve...@googlegroups.com
Hi everyone,

In the latest git push I added an example of a CMS application build with Yoke.


The example is based on kitcms (http://kitcms.com/). In fact the admin panel is a shame copy paste from that project, however the server backend is done with Yoke and Vert.x and as you can see you can have a CMS backed by Redis written in less than 500 lines of code (including a template engine for Mustache, Config handling and Redis communication).

The core code lives in the file:


And is less than 250 lines.

Also, I've introduced some initial support for Groovy but this hasn't been tested at all yet.

Feel free to comment and report issues on github:


Thanks!

Bastian

unread,
Apr 23, 2013, 7:51:50 AM4/23/13
to ve...@googlegroups.com
Hey Paulo, very nice work.

Seems as if there are several people working on a Connect like framework for vertx - including me. But as Daryl says there is no point doubling efforts, so I'll see what I can contribute to Yoke.


On Tuesday, April 23, 2013 11:44:10 AM UTC+2, Paulo Lopes wrote:

Paulo Lopes

unread,
Apr 23, 2013, 7:59:21 AM4/23/13
to ve...@googlegroups.com
All contributions are welcome :)

I've put the code available on github and clarified the license as Apache Software License 2.0 (like Vert.x).

Cheers,
Paulo

Paulo Lopes

unread,
Apr 25, 2013, 5:42:33 AM4/25/13
to ve...@googlegroups.com
Some very basic support for Groovy is included now with one example:

So basically it uses the groovy lang module and Closures instead of Handlers:

import com.jetdrone.vertx.yoke.*
import com.jetdrone.vertx.yoke.middleware.*

def yoke = new GYoke(vertx)

yoke.use(new ErrorHandler(true))

yoke.use() { request, next ->
    if (request.path() == '/hello') {
        request.response().end('Hi there!')
    } else {
        next.handle('You did not say hello! go to /hello')
    }
}

yoke.listen(8080)

closures can have one or 2 parameters, the first one is the request object and the second the handler for the next in chain middleware.

Tim Yates

unread,
Apr 25, 2013, 5:47:14 AM4/25/13
to ve...@googlegroups.com
Just from an ideomatic groovy POV, it might be better if instead of path() and response() you supply getPath and getResponse methods, then you can write:


import com.jetdrone.vertx.yoke.*
import com.jetdrone.vertx.yoke.middleware.*

def yoke = new GYoke(vertx)

yoke.use( new ErrorHandler(true) )

yoke.use { request, next ->
    if (request.path == '/hello') {
        request.response.end( 'Hi there!' )

Tim Yates

unread,
Apr 25, 2013, 5:48:59 AM4/25/13
to ve...@googlegroups.com
Ahhh...just looked a the code, and I see you do this already...

Ignore me ;-)

Tim Fox

unread,
Apr 25, 2013, 5:50:37 AM4/25/13
to ve...@googlegroups.com
Great! I think it would be great to have good Groovy support.

Btw, have you seen https://github.com/ratpack/ratpack ?

Paulo Lopes

unread,
Apr 25, 2013, 10:54:12 AM4/25/13
to ve...@googlegroups.com
I didn't know about ratpack.

Well it looks like the API is somehow close.

I am not planning to build something like ratpack, however if someone invests some time building say:

  • render engines
  • session middleware
  • more stuff missing...
The current middleware list can do most of the tasks ratpack can.

One feature that RatPack has is template engine, to demonstrate how Yoke can be extended in that area, I implemented a simple render engine that does property placeholder replacement.

Given the template: "Hello ${name}!" and a map {name: "world"} it renders to "Hello world!"

It is even smart to do interpolation such as: "Hello ${na${me}}!" and {name: "world", me: "me"} it renders "Hello world!"

The render engine is also used in the example application (KitCMS) for everyone interested in knowing how to use it.

About groovy support i cannot guarantee that it is good enough since I do not have much experience with the language, I created the basic bindings but if there is someone with better knowledge of the language, feel free to refactor the whole thing :)

Bruno Santos

unread,
Apr 25, 2013, 12:34:09 PM4/25/13
to ve...@googlegroups.com
Talking about templates, it would be a nicety to have a template engine similar to what Play2 has, either as a vertx module or as part of yoke (or any other vertx based midware).



--
You received this message because you are subscribed to a topic in the Google Groups "vert.x" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/vertx/2DrXx-E8Zso/unsubscribe?hl=en-GB.
To unsubscribe from this group and all of its topics, send an email to vertx+un...@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Bruno Santos
mailto:bmros...@gmail.com
 
"Treat people as they ought to be, and you will help them
become what they are capable of being." - Goethe

Paulo Lopes

unread,
Apr 26, 2013, 8:42:09 AM4/26/13
to ve...@googlegroups.com
So I've been working on the groovy side of Yoke, it now has proper dot notation for accessing fields and a TEMPLATE ENGINE!!! :)

So the new example is like this:

import com.jetdrone.vertx.yoke.middleware.*
import com.jetdrone.vertx.yoke.GYoke
import com.jetdrone.vertx.yoke.engine.GroovyTemplateEngine

def yoke = new GYoke(vertx)

yoke.engine('html', new GroovyTemplateEngine())

yoke.chain(new ErrorHandler(true))

yoke.chain {request ->
    request.put('session', [id: '1'])
    request.response.render 'template.html'
}

yoke.listen(8080)

Note that instead of "use" the method is called "chain". Why? because for some reason my Groovy classes get some static method called use, which is kind of annoying but unless someone knows how to override those the api signature will be different.

The closure can have 1 or 2 arguments, one as illustrated above, two when there is a next if you want to chain to the next middleware.

You can add any property to the request with the method put(String, Object) this is the context for your render engine. If you are on Groovy I've created a render engine based on the Groovy template engine API. Here is the template the example is calling:

<!DOCTYPE html>
<html>
<body>
  <% 3.times { %>
    Hello World!
  <% } %>
  <br>
  <% if (session != null) { %>
    My session id is ${session.id}
  <% } else println "No session created." %>
</body>
</html>

And Tada there you go! :)

Paulo Lopes

unread,
Apr 26, 2013, 9:16:21 AM4/26/13
to ve...@googlegroups.com
Another feature for Groovy that i did not mentioned was, that you can now define routes with closure syntax instead of handlers:

import com.jetdrone.vertx.yoke.middleware.*
import com.jetdrone.vertx.yoke.GYoke
import com.jetdrone.vertx.yoke.engine.GroovyTemplateEngine

def yoke = new GYoke(vertx)

yoke.engine('html', new GroovyTemplateEngine())

yoke.chain(new ErrorHandler(true))
yoke.chain(new GRouter() {{
    get("/hello") { request ->
        request.response.end "Hello World!"
    }
    get("/template") { request ->
        request.put('session', [id: '1'])
        request.response.render 'template.html'
    }
}})

yoke.chain {request ->
    request.response.end "maybe you should go to /hello or /template!"
}

yoke.listen(8080)

The first argument can also be a regular expression!!!

Pid

unread,
Apr 27, 2013, 7:22:31 AM4/27/13
to ve...@googlegroups.com
On 25/04/2013 17:34, Bruno Santos wrote:
> Talking about templates, it would be a nicety to have a template engine
> similar to what Play2 has, either as a vertx module or as part of yoke
> (or any other vertx based midware).
> http://www.playframework.com/documentation/2.0/ScalaTemplates

As another option for 2.0 I've put together a Thymeleaf based template
engine:

https://github.com/swilliams-vmw/mod-thymeleaf

Module name (currently in OSS Sonatype Maven Snapshot repo):

io.vertx~mod-thymeleaf~1.0.0-SNAPSHOT


p

> On Thu, Apr 25, 2013 at 10:54 AM, Paulo Lopes <pml...@gmail.com
> <mailto:pml...@gmail.com>> wrote:
>
> I didn't know about ratpack.
>
> Well it looks like the API is somehow close.
>
> I am not planning to build something like ratpack, however if
> someone invests some time building say:
>
> * render engines
> * session middleware
> * more stuff missing...
>
> The current middleware list can do most of the tasks ratpack can.
>
> One feature that RatPack has is template engine, to demonstrate how
> Yoke can be extended in that area, I implemented a simple render
> engine that does property placeholder replacement.
>
> Given the template: /"Hello ${name}!"/ and a map /{name: "world"}/
> it renders to /"Hello world!"/
>
> It is even smart to do interpolation such as: /"Hello ${na${me}}!"/
> and /{name: "world", me: "me"}/ it renders /"Hello world!"/
>
> The render engine is also used in the example application (KitCMS)
> for everyone interested in knowing how to use it.
>
> About groovy support i cannot guarantee that it is good enough since
> I do not have much experience with the language, I created the basic
> bindings but if there is someone with better knowledge of the
> language, feel free to refactor the whole thing :)
>
> On Thursday, April 25, 2013 11:50:37 AM UTC+2, Tim Fox wrote:
>
> Great! I think it would be great to have good Groovy support.
>
> Btw, have you seen https://github.com/ratpack/__ratpack
> <https://github.com/ratpack/ratpack> ?
>
> On 25/04/13 10:42, Paulo Lopes wrote:
>> Some very basic support for Groovy is included now with one
>> example:
>> https://github.com/pmlopes/__yoke/tree/master/example/__groovy
>> <https://github.com/pmlopes/yoke/tree/master/example/groovy>
>>
>> So basically it uses the groovy lang module and Closures
>> instead of Handlers:
>>
>> import com.jetdrone.vertx.yoke.*
>>
>> import com.jetdrone.vertx.yoke.__middleware.*
>> def yoke = new GYoke(vertx)
>>
>> yoke.use(new ErrorHandler(true))
>>
>> yoke.use() { request, next ->
>>
>> if (request.path() == '/hello') {
>>
>> request.response().end__('Hi there!')
>> Favicon.class.getResource("__favicon.ico").getPath()
>>
>> does not return an actual filesystem path but
>> instead a value like.
>>
>> /D:/vertx/test-yoke/mods/com.__jetdrone~yoke~1.0.0-SNAPSHOT/__com/jetdrone/vertx/yoke/__middleware/favicon.ico
>>
>> where the initial "/" char means the path can
>> not by opened with the fileSystem() classes.
>>
>>
>>
>>
>>
>> Den fredag den 19. april 2013 11.26.49
>> <tel:2013%2011.26.49> UTC+2 skrev Paulo Lopes:
>>
>> *Yoke*
>>
>> Yoke is a project that I've been working
>> on for the last couple of weeks.
>>
>> The purpose of Yoke is to provide a easy
>> way to build web applications or web
>> frameworks on top of Vert.x with a simple API.
>>
>> Yoke has no external dependencies, however
>> it is meant to be extended.
>>
>> Yoke is a chain executor framework for
>> Vert.x, it was modeled after Connect (see
>> http://www.senchalabs.org/__connect/
>> <http://www.senchalabs.org/connect/>) and
>> right now is bundled with 12 middleware
>> components and if you are interested you
>> can write 3rd party middlewares to be
>> added to the project.
>>
>> *Usage*
>>
>> The usage at the moment is Java only and I
>> am planning to create bindings for other
>> languages that run on Vert.x.
>>
>> import com.jetdrone.vertx.yoke.__middleware.*;
>> import org.vertx.java.core.Handler;
>> import
>> org.vertx.java.core.http.__HttpServerRequest;
>> import org.vertx.java.platform.__Verticle;
>> *Installation*
>>
>> Just pull the jar to your module lib. I am
>> in the process of uploading the artifact
>> to maven central.
>>
>> *Bundled Middleware*
>>
>> * *BasicAuth* - basic http authentication
>> * *BodyParser* - extensible request body
>> parser, internally it will parse the
>> request body and populate the field
>> body on the HttpServerRequest object
>> with either:
>> o *JsonObject* if content-type was
>> application/json
>> o *Map<String, Object>* if
>> content-type was
>> application/x-www-form-__urlencoded
>> o *Map<String, Object>* plus field
>> files (Map<String, UploadFile>) if
>> content-type was multipart/form-data
>> * *CookieParser* - populates the field
>> cookies on the request and verifies if
>> they are signed
>> * *ErrorHandler* - Pretty error messages
>> either in html/json/text
>> * *Favicon* - generate a proper
>> favicon.ico for your app
>> * *Limit* - Limit the request body to a
>> specific amount of bytes
>> * *MethodOverride* - faux HTTP method
>> support
>> * *ResponseTime* - calculates
>> response-time and exposes via
>> X-Response-Time
>> * *Router* - Route Matcher like Vertx
>> one but allows also responses to be
>> chainable
>> * *Static* - static file server (with
>> proper caching headers) and optional
>> directory listing
>> * *Timeout* - request timeouts do not
>> allow long running requests
>> * *Vhosts* - virtual host sub-domain
>> mapping middleware
>>
>>
>> *Links*
>>
>> * github -
>> https://github.com/pmlopes/__yoke
>> <https://github.com/pmlopes/yoke>
>> * lib - http://pmlopes.github.io/yoke
>>
>>
>> --
>> You received this message because you are subscribed to the
>> Google Groups "vert.x" group.
>> To unsubscribe from this group and stop receiving emails from
>> it, send an email to vertx+un...@__googlegroups.com.
>>
>> For more options, visit
>> https://groups.google.com/__groups/opt_out
>> <https://groups.google.com/groups/opt_out>.
>>
>>
>
>
> --
> You received this message because you are subscribed to a topic in
> the Google Groups "vert.x" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/vertx/2DrXx-E8Zso/unsubscribe?hl=en-GB.
> To unsubscribe from this group and all of its topics, send an email
> to vertx+un...@googlegroups.com
> <mailto:vertx%2Bunsu...@googlegroups.com>.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>
>
>
>
>
> --
> Bruno Santos
> mailto:bmros...@gmail.com <mailto:bmros...@gmail.com>
>
> "Treat people as they ought to be, and you will help them
> become what they are capable of being." - Goethe
>
> --
> You received this message because you are subscribed to the Google
> Groups "vert.x" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to vertx+un...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>


--

[key:62590808]

Tim Fox

unread,
Apr 27, 2013, 9:53:20 AM4/27/13
to ve...@googlegroups.com
Nice. The more the merrier :)
>     <mailto:vertx%2Bu...@googlegroups.com>.

Finn Bock

unread,
Apr 27, 2013, 3:11:44 PM4/27/13
to ve...@googlegroups.com
Paulo Lopes:


 If you are on Groovy I've created a render engine based on the Groovy template engine API.

I assume the groovy  template engine can be used independent of yoke's groovy support.

In other web template frameworks there is commonly some predefined variables like: request, response, cookies, locale, cookies, session and whaterver else that makes sense for the framework.

It is also common that the template system support calling functions, either system or user defined.

Do you have any plans for defining a common set of variable and functionality that that template engines are expected to support?

regards,
finn

regards,
Finn

Paulo Lopes

unread,
Apr 27, 2013, 3:55:52 PM4/27/13
to ve...@googlegroups.com
Yes you could use the groovy template from java since the render api only cares about a map as the context. What i did not do was writing code with jsva handlers but with groovy closures. Adding those is a trivial task that takes a couple of minutes.
--
You received this message because you are subscribed to a topic in the Google Groups "vert.x" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/vertx/2DrXx-E8Zso/unsubscribe?hl=en-GB.
To unsubscribe from this group and all of its topics, send an email to vertx+un...@googlegroups.com.

Paulo Lopes

unread,
May 1, 2013, 11:13:24 AM5/1/13
to ve...@googlegroups.com
New small update:

  • Yoke has now a simple Session middleware based on cookies.

As a not so small update there are TESTS :))

  • I've created a simple mock for the whole framework so there is no need to create HttpServers all the time.
My next focus will be JavaScript support
To unsubscribe from this group and all of its topics, send an email to vertx+unsubscribe@googlegroups.com.

bytor99999

unread,
May 1, 2013, 11:47:43 AM5/1/13
to ve...@googlegroups.com
About Templating. It would be nice to have choices. There are so many Templating engines out there and opinions on them. For instance, Thymeleaf has been briought up and it is fantastic, but not everyone wants to use it, or subscribes to how they do their templating. For instance, I like ICanHaz.js built on top of Mustache. Groovy's templating is also just as amazing. So I was just hoping it would end up being a choose whichever templating engine you want.

Thanks

Mark
To unsubscribe from this group and all of its topics, send an email to vertx+un...@googlegroups.com.

bytor99999

unread,
May 1, 2013, 11:48:32 AM5/1/13
to ve...@googlegroups.com
I was also a little bummed we didn't call this Neil or Alex, since Node.js has Geddy. (Rush humor)

Mark

On Friday, April 19, 2013 2:26:49 AM UTC-7, Paulo Lopes wrote:
Yoke

Yoke is a project that I've been working on for the last couple of weeks.

The purpose of Yoke is to provide a easy way to build web applications or web frameworks on top of Vert.x with a simple API.

Yoke has no external dependencies, however it is meant to be extended.

Yoke is a chain executor framework for Vert.x, it was modeled after Connect (see http://www.senchalabs.org/connect/) and right now is bundled with 12 middleware components and if you are interested you can write 3rd party middlewares to be added to the project.

Usage

The usage at the moment is Java only and I am planning to create bindings for other languages that run on Vert.x.

import com.jetdrone.vertx.yoke.middleware.*;
import org.vertx.java.core.Handler;
import org.vertx.java.core.http.HttpServerRequest;
import org.vertx.java.platform.Verticle;

public class Tester extends Verticle {

    @Override
    public void start() {
        Yoke yoke = new Yoke(vertx);

        yoke.use(new Static("public"));
        yoke.use(new Router() {{
            all("/hello", new Handler<HttpServerRequest>() {
                @Override
                public void handle(HttpServerRequest request) {
                    request.response().end("Hello World!");
                }
            });
        }});

        yoke.listen(3000);
    }
}

The API is quite simple, you start a chain (Yoke) with the Vertx instance. This Vertx instance is the shared by all middleware (Yoke will make sure of this) you you don't need to pass it to all middleware constructors.

Then you chain Middleware with the method use(), in this case I chain the static file server and a the custom router middleware (which works in a similar way to the RouteMatcher).

When running this verticle all requests will first try to find a matching file on the file system under the "public" directory if that fails the router will try to match the request path to "/hello" and run that handler, if that fails and error is raised.

Installation

Just pull the jar to your module lib. I am in the process of uploading the artifact to maven central.

Paulo Lopes

unread,
May 1, 2013, 1:58:59 PM5/1/13
to ve...@googlegroups.com


On Wednesday, May 1, 2013 5:47:43 PM UTC+2, bytor99999 wrote:
About Templating. It would be nice to have choices. There are so many Templating engines out there and opinions on them. For instance, Thymeleaf has been briought up and it is fantastic, but not everyone wants to use it, or subscribes to how they do their templating. For instance, I like ICanHaz.js built on top of Mustache. Groovy's templating is also just as amazing. So I was just hoping it would end up being a choose whichever templating engine you want.


I've implemented a Groovy Templace interface and a simple Placeholder replacer, I would like someone to provide the other interfaces, as you can imagine i cannot implement all engines:

  • Thymeleaf
  • ICanHaz
  • Mustache
  • HandleBars
  • etc...
Well i could do that but i am more interested now in getting everything properly tested and supporting Java/Groovy/JavaScript I also would like to have support for other languages:

  • Python
  • Ruby
  • Scala
  • Clojure
  • ...
However you are more than welcome to provide a Thymeleaf engine, just implement the the class :) you only need to write 2 methods :) it is easy :)
 

bytor99999

unread,
May 2, 2013, 4:15:13 PM5/2/13
to ve...@googlegroups.com
I wouldn't implement Thymeleaf. I would look at implementing ICanHaz.js

I like my client side templating engines, not server side. ;)

Paulo Lopes

unread,
May 2, 2013, 4:18:19 PM5/2/13
to ve...@googlegroups.com
Another announcement a very pre pre alpha JavaScript support is in, you can do this:

var Yoke = require('com/jetdrone/vertx/yoke/Yoke');
var Router = require('com/jetdrone/vertx/yoke/middleware/Router');

var yoke = new Yoke();
var router = new Router();

yoke.use(router);
router.get('/hello', function (req) {
    req.response().end('Hello there!');
});
// all other resources are forbidden
yoke.use(function (req, next) {
    next(401);
});

// start server
yoke.listen(8080);

 And more tests have been added fixing a couple of bugs. Still need to implement template support in JS and tests for Groovy and JS

Mark Wienk

unread,
May 6, 2013, 10:30:27 AM5/6/13
to ve...@googlegroups.com
I've written a new Yoke templating engine for Google Closure templates.


As files can hold more than 1 template, the render() method parameter uses a namespace.template.soy syntax, while all the templates in the src/main/resources/templates folder will be parsed.

Paulo Lopes

unread,
May 7, 2013, 4:29:59 AM5/7/13
to ve...@googlegroups.com
Cool, very interesting :)

I am now focusing on documentation. It is nice to see that people like the project and add more features to it :)

I will add links to 3rd party middleware in the documentation.

Cheers,
Paulo

Joern Bernhardt

unread,
May 7, 2013, 6:43:39 PM5/7/13
to ve...@googlegroups.com
Hi Paulo,

the whole project looks quite nice to build webapps with.

I don't really understand it though, probably since I haven't worked with Connect or anything similar before. When I have Middleware objects, they are structured / ordered by my code, right? So if I use a Middleware before another one, the second will have access to stuff that happened in the first Middleware?

I'm also trying to grasp, how/what you do with the session middleware, especially since I've written that session manager module... I can only see you set/get a session id - there is no storage for anything else in the session? How can I share data between the Middleware objects then?

Thanks,
Joern

Paulo Lopes

unread,
May 8, 2013, 3:44:56 AM5/8/13
to ve...@googlegroups.com


On Wednesday, May 8, 2013 12:43:39 AM UTC+2, Joern Bernhardt wrote:
Hi Paulo,

the whole project looks quite nice to build webapps with.

I don't really understand it though, probably since I haven't worked with Connect or anything similar before. When I have Middleware objects, they are structured / ordered by my code, right? So if I use a Middleware before another one, the second will have access to stuff that happened in the first Middleware?

Yes, I need to write documentation :) So let me try to explain simply how all this works.

You don't need to know connect or expressjs, because the concept is quite simple. Yoke is a chain executor, modelled in a way like the Chain-of-responsability pattern (http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern).

You register middleware onto it using the "use" method. "yoke.use(someMiddlewareClass)", you register as many middleware as you want, but keep in mind that the order you used to register is the order that is used to process a request.

The difference between the Middleware abstract class and the pattern is that you don't have to define the "next" on the middleware itself but yoke takes care of it. If your middleware calls next(null) then the next in line is executed, if instead you call next(error) where error is any object that is not null then a special error handler middleware is executed after. If in your middleware you don't call next, then the processing ends.

As an example say that you need an app that receives json documents in the url "/upload", you would start like this (I will write example code in java, but if you want i can rewrite in groovy or js):

new Yoke(vertx)
  .use(new BodyParser())
  .listen(8080);

At this point any request (no matter the url) that contains a json document will be parsed and made available, but nothing else happens. You need now to write the end point of your REST call. You can either use the router middleware or create a middleware that accepts all resources, I will use the router for simplicity:

new Yoke(vertx)
  // parse the http body
  .use(new BodyParser())
  // enable the route matcher
  .use(new Router()
    // match on POST /upload
    .post("/upload", new Handler<YokeRequest>() {
      public void handle(YokeRequest request) {
        System.out.println(request.jsonBody());
        request.response().end();
      }
    })
  ).listen(8080);
 
So where is the magic? Look at the dummy line where i do System.out.println() the request has a method jsonBody() that does not exist on Vertx HttpServerRequest and it is a JsonObject, this is because the BodyParser middleware handled all the upload stuff, detected that it was a json object, parsed it and set it on the request.

However for other middlewares and applications you might want to share objects that are not defined on the YokeRequest and YokeResponse objects, in that case you need to know that the YokeRequest has an internal property called "context", this context is a simple java Map, you can add and get anything by using the methods "get" and "put" on the request, i will do some example for your next question.


I'm also trying to grasp, how/what you do with the session middleware, especially since I've written that session manager module... I can only see you set/get a session id - there is no storage for anything else in the session? How can I share data between the Middleware objects then?

Ok, lets make a pseudo db-backed session manager app:

        // start by creating some signature object (javax.crypto.Mac)
        final Mac hmac = Utils.newHmacSHA256("my super secret signature secret key");
        // create Yoke
        final Yoke yoke = new Yoke(vertx);
        // since sessions are stored in cookies we need to parse then so use the cookie parser middleware
        yoke.use(new CookieParser(hmac));
        // i don't want to bother with session validation so lets use the Session middleware
        yoke.use(new Session(hmac));
        // lets code our app
        yoke.use(new Router()
            // use this path check that the cookies are ok on your browser debugger
            .get("/", new Handler<YokeRequest>() {
                @Override
                public void handle(YokeRequest request) {
                    request.response().end();
                }
            })
            // go here to create a new session
            .get("/new", new Handler<YokeRequest>() {
                @Override
                public void handle(YokeRequest request) {
                    // setting the sessionId informs the session middleware to create a session cookie
                    request.setSessionId("some generated secure id string here");
                    request.response().end();
                }
            })
            // go here to delete the session
            .get("/delete", new Handler<YokeRequest>() {
                @Override
                public void handle(YokeRequest request) {
                    // setting sessionId to null is same as delete session
                    request.setSessionId(null);
                    request.response().end();
                }
            });
        )).listen(8080);

So at this moment you have an application that can do cookie session management but nothing is associated with its id. Lets assume that you have a super database that API is as follows:

DB.get(String key) : Object
DB.put(String key, Object value) : void
DB.delete(String key) : void

So now you need to get data from this DB when session Id is present, of course you could code this in your router but it would be a lot of copy paste and honestly the router concern is not session management. Lets create a new middleware.

Since you need to know the sessionId and the data needs to be available before the router the install location should be obvious in the chain:

...
        // create Yoke
        final Yoke yoke = new Yoke(vertx);
        // since sessions are stored in cookies we need to parse then so use the cookie parser middleware
        yoke.use(new CookieParser(hmac));
        // i don't want to bother with session validation so lets use the Session middleware
        yoke.use(new Session(hmac));
// HERE
        yoke.use(new Middleware() {
          public void handle(final YokeRequest request, final Handler<Object> next) {
            String sessionId = request.getSessionId();
            // if there is a sessionId we can load it from db
            if (sessionId != null) {
              Object sessionObject = DB.get(sessionId);
              // now store it in the request so the next middleware can use it
              request.put("sessionData", sessionObject);
            }
            // tell yoke that it can now execute the next middleware and there was no error
            next.handle(null);
          }
        });
        // lets code our app
        yoke.use(new Router()
...

At this moment in your router you can access the session data like this:

...
            .get("/", new Handler<YokeRequest>() {
                @Override
                public void handle(YokeRequest request) {
                    System.out.println(request.get("sessionData"));
                    request.response().end();
                }
            })
...

Note that you *can* do asynchronous calls in the db loader middleware because the execution of the next middleware is triggered by "next.handle(null)" and not by the end of the method. This means that you could use some asynchronous data access module like my "mod-redis-io" :P (cheap advertisement) and when data is back from redis call "next.handle(null)".

I hope you have now a better insight on Yoke.

Cheers,
Paulo
 
 

Joern Bernhardt

unread,
May 8, 2013, 4:01:44 AM5/8/13
to ve...@googlegroups.com
Wow, thanks for that thorough explanation! That makes much sense now. Hopefully you put that in your documentation, too! :)

Mark Mandel

unread,
May 9, 2013, 4:14:39 AM5/9/13
to ve...@googlegroups.com
Hey guys,

Started to doing some research into Vert.x, and saw this post.

Started to wonder if there is a list somewhere that I couldn't find of frameworks / libraries that work on top of vert.x?

Would be a really cool resource if it does exist :)

Thanks!

Mark

Mikael Karon

unread,
May 9, 2013, 4:46:06 AM5/9/13
to ve...@googlegroups.com

Paulo Lopes

unread,
May 10, 2013, 9:00:17 AM5/10/13
to ve...@googlegroups.com
http://pmlopes.github.io/yoke/Java-Tutorial.html

I hope I covered all the basics, I will "translate" the tutorial now to Groovy and JavaScript

Mark Wienk

unread,
May 14, 2013, 9:50:40 AM5/14/13
to ve...@googlegroups.com
Great stuff on the documentation! I wanted to dive into the Session stuff, but I cannot find any documentation. Is it in the pipeline yet?

Paulo Lopes

unread,
May 14, 2013, 9:55:46 AM5/14/13
to ve...@googlegroups.com
Yes it is in the pipeline, i got "distracted" with the latest changes to the vert.x API which made me to totally refactor the body parser and playing around with code simplification for java development using annotations.

I added some extra goodies for java developers:

@Path("/ws")
public static class TestRouter {
 @GET
  public void get(YokeRequest request) {
    request.response().end("Hello ws!");
  }
}

yoke.use(Router.from(new TestRouter()));

but i am now going to focus again on the documentation :)

Paulo Lopes

unread,
May 15, 2013, 10:01:59 AM5/15/13
to ve...@googlegroups.com
I've made some simple benchmark of Yoke vs ExpressJS and here are the results: http://pmlopes.github.io/yoke/Benchmark.html

Yoke with Vert.x 2.0.0-SNAPSHOT is a clear winner in performance against the same code with ExpressJS!

All benchmark code is on the github reppo as well the script that runs the tests so there is no human interaction between tests.

Leng Sheng Hong

unread,
May 15, 2013, 3:00:04 PM5/15/13
to ve...@googlegroups.com
nice! Update to 2.0.0-beta1 soon?

Paulo Lopes

unread,
May 15, 2013, 3:45:19 PM5/15/13
to ve...@googlegroups.com
I tried to update the gradle to pull the version 2.0.0-beta1 but i could not find anything on sonatype nexus... i think i need to wait for the upload to nexus and then yes beta1 is supported!

Daryl Teo

unread,
May 15, 2013, 5:32:59 PM5/15/13
to ve...@googlegroups.com
Hi Paulo,
 
   I'd like to work closely with you on Yoke. Is there a way we can communicate directly?

I'm GMT +10. G+ hangouts?

Regards,
Daryl

Daryl Teo

unread,
May 15, 2013, 6:50:04 PM5/15/13
to ve...@googlegroups.com
Or find me at #vertx at irc.freenode

廖师虎

unread,
May 15, 2013, 10:41:18 PM5/15/13
to ve...@googlegroups.com
Hello Paulo!
I read your tutorial:http://pmlopes.github.io/yoke/Java-Tutorial.html,and write the HelloWorldVerticle, when I run the command: gradlew runMod,
then report the error:
 F:\Vert.x\yoke-tutorial>gradlew runMod
:compileJava UP-TO-DATE
:compileGroovy UP-TO-DATE
:processResources
:classes
:copyMod
:runMod
Failed to deploy module
java.lang.NoClassDefFoundError: com/jetdrone/vertx/yoke/Yoke
        at com.lshoo.yoke.HelloWorldVerticle.start(HelloWorldVerticle.java:20)
        at org.vertx.java.platform.Verticle.start(Verticle.java:80)
        at org.vertx.java.platform.impl.DefaultPlatformManager$16.run(DefaultPl
tformManager.java:1133)
        at org.vertx.java.core.impl.DefaultContext$2.run(DefaultContext.java:14
)
        at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(Singl
ThreadEventExecutor.java:364)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:326)
        at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThrea
EventExecutor.java:114)
        at java.lang.Thread.run(Thread.java:722)
Caused by: java.lang.ClassNotFoundException: com.jetdrone.vertx.yoke.Yoke
        at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
        at org.vertx.java.platform.impl.ModuleClassLoader.loadClass(ModuleClass
oader.java:113)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
        ... 8 more

BUILD SUCCESSFUL
----------------------

I use thd Idea12 of the ide, the ide don't report error.
Why?
Thanks! 

Paulo Lopes

unread,
May 16, 2013, 3:35:25 AM5/16/13
to ve...@googlegroups.com
I found a couple of bugs in the tutorial that have been fixed. The most important is that i was missing the declaration of mod.json you need to edit the mod.json in the project to have:

{
  "main": "com.jetdrone.vertx.HelloWorldVerticle",
  "includes": "com.jetdrone~yoke~1.0.0-SNAPSHOT"
}

this means that the main verticle is the HelloWorld one and that this module includes the yoke jar. The includes directive tells vert.x to fetch it from the nexus repository and add it to the classpath and this was why you would get no ClassDefFound exceptions.

Paulo Lopes

unread,
May 16, 2013, 3:43:37 AM5/16/13
to ve...@googlegroups.com
Hi my timezone is GMT-1 so... 11h difference you can reach me on G+ or mail me directly.

If you are interested in Yoke let me know what you would like to do and we can go from there. My TODO list is currently:

* documentation
* testing
* profiling
* code reviews

But i am also looking into adding more helpers to the request/response object like expressjs has for content negotiation, language, parsing x-forward-for, etc...

廖师虎

unread,
May 16, 2013, 3:47:15 AM5/16/13
to ve...@googlegroups.com
Thanks Paulo!
I am newbie of Vert.x and Yoke, I want to use Vert.x 2 with scala, Yoke supports Scala too ?

在 2013年5月16日星期四UTC+8下午3时43分37秒,Paulo Lopes写道:

Christian T.

unread,
May 16, 2013, 3:47:50 AM5/16/13
to ve...@googlegroups.com
Had that too.
Change Yoke dependency from provided to compile. 

To be honest, i dont quite understand why, but it works. 

I thought modules would get loaded at runtime by vertx. 

I think it would be very helpful if Tim would document the new module-system, because for me it seems to be the most major change from vertx 1.x to 2.x. And it's the most important and sensible part of the framework. 
--
You received this message because you are subscribed to the Google Groups "vert.x" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vertx+un...@googlegroups.com.

Paulo Lopes

unread,
May 16, 2013, 3:50:56 AM5/16/13
to ve...@googlegroups.com
No, there is no support for scala at the moment, for 2 reasons:

* the scala module is not ready for vert.x 2
* i need to learn scala :P

I would like to have it but i cannot give any time frame for having this implemented.

Paulo Lopes

unread,
May 22, 2013, 5:42:28 AM5/22/13
to ve...@googlegroups.com

Back to the benchmark topic, I've run more tests now with nodeJS clustering versus Vert.x 2.0.0-beta2 and Yoke. The tests are running on a quad core machine and using the 4 cores:

http://pmlopes.github.io/yoke/cluster.png

As it can be seen Vert.x with Yoke beats ExpressJS with node, what is more interesting in my opinion is the lines of code. Express JS example takes 42 lines while Yoke code takes 27 while 11 from these lines are import statements.

The full story is here:
http://pmlopes.github.io/yoke/Benchmark.html#cluster

Nikolai Raitsev

unread,
May 22, 2013, 9:36:56 AM5/22/13
to ve...@googlegroups.com

Hi Paulo,

I'm very new in the thema vert.x and I'm actually searching for a "understandable", "clean codeable" framework to create relatively complex web application with many views, complex business logic, multiple databases/sources and reporting with it. The framework should support internalizations/localization, templating with controller-binding like "managed beans", transaction management and so on..., that performs very well and that doing not so much byte code manipulations.

Now I found, that you have started a middleware projekt for vert.x and actually I'm trying to create a little example application with it, in groovy. I'm now at the point with many questions about how to do some things, started on execution with IDE (eclipse with groovy/gradle plugins), how to combine templating with business logic/routing, how to add websocket/cometD to it, what is the best approach for the understandable architecture without too much "spagetty callback hole"...

Its many questions, maybe it make sense to create a separate group for Yoke?

But back to your benchmark: your example has very extreme deflection by Yoke around 8.000 requests, in all tests. What is the reason for that?

Best regards,

Nikolai
yoke_benchmark_question.png

Paulo Lopes

unread,
May 22, 2013, 10:14:39 AM5/22/13
to ve...@googlegroups.com


On Wednesday, May 22, 2013 3:36:56 PM UTC+2, Nikolai Raitsev wrote:

Hi Paulo,

I'm very new in the thema vert.x and I'm actually searching for a "understandable", "clean codeable" framework to create relatively complex web application with many views, complex business logic, multiple databases/sources and reporting with it. The framework should support internalizations/localization, templating with controller-binding like "managed beans", transaction management and so on..., that performs very well and that doing not so much byte code manipulations.

Yoke is quite basic it does not do most of what you need, as an example:

  • it does **not** do internationalization - but one could write some middleware that parses the accept-language header and do something with it along the request pipeline.
  • it does **not** do templating with bindings
  • no managed beans
  • no transactions
...

sounds like it does not do anything :) and in fact it only runs async middleware in an ordered manner. The whole benefit of this is that if you structure your code as small components (middleware) you can organize it in a way that you don't end up with the "callback hell" http://callbackhell.com/ pattern.


Now I found, that you have started a middleware projekt for vert.x and actually I'm trying to create a little example application with it, in groovy. I'm now at the point with many questions about how to do some things, started on execution with IDE (eclipse with groovy/gradle plugins), how to combine templating with business logic/routing, how to add websocket/cometD to it, what is the best approach for the understandable architecture without too much "spagetty callback hole"...

  • About IDE i personally prefer to develop with IntelliJ Idea and even using the community version i find it quite productive since it can open the gradle project directly and i can run/debug directly from it. I have no experience with gradle and eclipse but i think lots of other users of Vert.x use eclipse might help you better there.
  • To combine logic and routing, well i would sugest you to create a middleware object for the logic and then use the router to map request to the middleware.

As an example, i want an app that sums 2 numbers, I start a middleware object that implements the handle method and there gets 2 request parameters and outputs their sum. Later I bind all together by creating a Yoke object and use the Router middleware, where i set the path "/sum/:arg1/:arg2" to a object reference of the middleware class i just described.

  • To combine websockets and normal code I would suggest you to get started with the vert.x tutorial.

But basically this is how you integrate it with Yoke, you create a HttpServer like you would on vert.x:

HttpServer server = vertx.createHttpServer();

You then set up the websocket handler:

server
.websocketHandler(new Handler<ServerWebSocket>() { public void handle(ServerWebSocket ws) { // A WebSocket has connected! } });

After you create a Yoke Object as normal and add the middleware you need:


Yoke yoke = new Yoke(vertx);
yoke.use(...);

and now the trick is that you now tell yoke to listen on an existing server:

yoke.listen(server);
// i might move this last inside yoke to make the API more concise...
server.listen(8080);

So you can handle both websokets/sockjs and yoke stuff!!!

Finally the 1m dollar question, how to avoid spagetti/callback hell... i cannot really answer that, i would recomment to write small functions, break the functionality, try promisses libraries, rxjava, other language that are more suited to asynchronous programming for example coffeescript... but this are just ideas, i cannot give you any real solution there!



Its many questions, maybe it make sense to create a separate group for Yoke?

But back to your benchmark: your example has very extreme deflection by Yoke around 8.000 requests, in all tests. What is the reason for that?

Honestly I don't really know and since nodejs was giving a similar curve i did not care much about trying to answer that. My wild guess is that (but this is a guess) the jvm is not warm and the initial request take longer to be processed and once the jvm is hot and the optimizations kick in and performance goes up. But this also does not answer why nodejs has a similar curve since i don't know how the v8 jit compares to jvm jit...

 

Paulo Lopes

unread,
May 22, 2013, 10:23:51 AM5/22/13
to ve...@googlegroups.com
As suggested here, a new group is created for questions/answers about yoke, since i don't want to abuse the vert.x group with non vert.x related topics:

https://groups.google.com/forum/?fromgroups=#!forum/yoke-framework

For any yoke related questions, use that group!

Thanks!
Paulo

Nikolai Raitsev

unread,
May 22, 2013, 11:28:53 AM5/22/13
to ve...@googlegroups.com
Hi Paulo,

many thanks for the very detailed answer! I'll post some questions in your new group.

The curve from Yoke is similar, but is more extreme as from node.js. I will try to get your benchmarks running and try to analyze, what is the reason for...

Best regards,

Nikolai

Farzad Pezeshkpour

unread,
Oct 9, 2014, 3:36:38 AM10/9/14
to ve...@googlegroups.com
Just came across Yoke. Awesome work, thank you!

Asher Tarnopolski

unread,
Nov 3, 2014, 5:16:16 AM11/3/14
to ve...@googlegroups.com
paulo, do you have any plans to migrate yoke to vertx3? 
i don't know what , if any, work should be done to support a new routematcher, but i guess jsonrestrouter's
persistance layer should be changed to fir the new way vertx works with mongo..
your mod is great. thanks!

Paulo Lopes

unread,
Nov 3, 2014, 6:00:30 AM11/3/14
to ve...@googlegroups.com
Yes i am porting it to vert.x3 and there are some experimental branches on github for that. I am also trying to port using the codegen but i've found some bugs that only once they are fixed i can make some more progress...

You're welcome to checkout the branches and help :)

Tim Fox

unread,
Nov 3, 2014, 6:08:30 AM11/3/14
to ve...@googlegroups.com
Great, later this week (time permitting - I will be at GOTO Berlin conference for a couple of days), I want to start looking at the new ext-rest stuff for Vert.x 3.0 and bring in ideas from Nico's work here https://github.com/huysamen/vertx-ext-rest and also Yoke, as has been discussed already on this list.

This won't be a replacement for Yoke - it will be more low level, but I think it would be great if Yoke could build on top of that, so we have a consistent user experience - I'm thinking users that want basic REST support may just use ext-rest, but when they want some of the more advanced features in Yoke, they should be able to transition to Yoke without rewriting everything.

I'd like to get you and Nico to contribute to this work if possible, or review it at the least :)
--
You received this message because you are subscribed to the Google Groups "vert.x" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vertx+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Asher Tarnopolski

unread,
Nov 3, 2014, 6:09:05 AM11/3/14
to ve...@googlegroups.com
these are great news. 

Asher Tarnopolski

unread,
Nov 3, 2014, 6:14:31 AM11/3/14
to ve...@googlegroups.com
tim, do you have any estimation when v3 will make it into a release? i just can't make my mind if to start a new project with v3 and keep  upating and refactoring alongside with snapshots or just stay with v2.

Julien Viet

unread,
Nov 3, 2014, 6:21:16 AM11/3/14
to ve...@googlegroups.com, Paulo Lopes
Hi Paulo,

we should sync up with you and Tim to talk about codegen issues, perhaps in a separate thread. Would you mind to make a thread on this list with your pending issues ? I know there is GH tracker but Tim commented on an issue, so I think it would be best to have a real thread on this list.


--
Julien Viet
www.julienviet.com

Tim Fox

unread,
Nov 3, 2014, 6:26:49 AM11/3/14
to ve...@googlegroups.com
On 03/11/14 11:14, Asher Tarnopolski wrote:
tim, do you have any estimation when v3 will make it into a release?

When it's ready :)

I'm loathed to put a firm date on this - there is a lot to do and there aren't many of us, but roughly I am aiming to get something out end of this year / beginning of next.

Tim Fox

unread,
Nov 3, 2014, 12:33:32 PM11/3/14
to ve...@googlegroups.com
I started playing around with some API ideas today, so this is basically routematcher++.

It's similar in some ways to how Yoke already works, and it also borrows some ideas (produces/consumes) from Nico's work and Jersey:

https://github.com/vert-x3/ext/tree/ext-rest/ext-rest/src/main/java/io/vertx/ext/rest

As you can it's very simple.

There's basically a Router class on which you create Routes. The Route itself uses a builider-style pattern to say whether the route is for a specific path, http method or whatever.

The best way to do understand it is by seeing some examples:

https://github.com/vert-x3/ext/blob/ext-rest/ext-rest/src/main/java/io/vertx/ext/rest/Example.java

Comments?

Paulo Lopes

unread,
Nov 4, 2014, 3:31:59 AM11/4/14
to ve...@googlegroups.com
I've been reading the example and the code and my opinion is that it is quite verbose, in order to define a PUT to foo/bar/order that consumes json you need:

router.route().path("foo/bar/order").method(HttpMethod.PUT).consumes("application/json").handler(ctx -> {

I know this is the builder pattern but personally i find it quite verbose and would prefer the old school:

router.put("foo/bar/order", ctx -> { ... })

But this is my opinion...

Now to the important part :)

Assuming that i am ok with the builder pattern, there are some inconsistencies that i think should be fixed:

# Context API

ctx.contextData().put("wibble", 123);

if ctx is a context assuming the duck typing, why a need for contextData(), i read it like:

"from the context, get me the context data and put at wibble the value 123"

I think it should read:

ctx.put("wibble", 123);

"put into the context key wibble the value 123"

# Route management

In Yoke i solve this by using JMX since I asked myself how often do i at runtime need to enable and disable routes? and if i do that, most of the times i introduce unexpected behaviour which might break my application.

Although it makes the API sort of complete, it can introduce problems, and if you use JMX then you really want to tweak your app at runtime and you should know what are you doing...

route.disable();
route
.enable();
 
# Rely on exceptions for reporting errors

One of the issues I face with exceptions is that throwing it requires it to be thrown at the same thread the router is running otherwise you loose the context and the exception handler is not called. So if your handler is doing some async stuff:

router.route().path("/foo/bar").handler(ctx -> {
  someAsyncCall(cb -> {
    if (err) throw new RuntimeException()
...

in this case the router will probably not catch it and there is no way to specify the error, that is why yoke has the argument to the next() call.

Also exceptions like this will force crawl of the stack to generate the stacktrace and some times you don't need that even...

# Integrate with Yoke

In theory it could be done, however this is a quite limited version of Yoke Router, Yoke router does parse path parameters: /api/:arg1, it also does arg validation before calling the handler, so if you register a param "arg1" it can be validated against a regex or even a handler before calling the handler. It exposes control of all routes in JMX and can also use POJOs with annotations like:

class MyRoutes {
  @RegExParam("arg1")
  final Pattern validator = Pattern.compile("\d+);

  @Produces("application/json")
  @Consumes("application/json")
  @PUT("/api/:arg1)
  void apiPut(YokeRequest request, Handler next) {
    ...
  }
}

So in order to use it in yoke either it needs some extension on Yoke side to support all yoke features...



--
You received this message because you are subscribed to a topic in the Google Groups "vert.x" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/vertx/2DrXx-E8Zso/unsubscribe.
To unsubscribe from this group and all its topics, send an email to vertx+un...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Paulo Lopes
www.jetdrone.com

Tim Fox

unread,
Nov 4, 2014, 6:39:04 AM11/4/14
to ve...@googlegroups.com
On 04/11/14 08:31, Paulo Lopes wrote:
I've been reading the example and the code and my opinion is that it is quite verbose, in order to define a PUT to foo/bar/order that consumes json you need:

router.route().path("foo/bar/order").method(HttpMethod.PUT).consumes("application/json").handler(ctx -> {

I know this is the builder pattern but personally i find it quite verbose and would prefer the old school:

router.put("foo/bar/order", ctx -> { ... })

The trouble with using a non builder approach is you will end up with the put method having lots of parameters so the equivalent won't really be less verbose, it will be more like this:

router.put("foo/bar/order", null, "application/json", ctx -> { ... })

or even worse (if you take orders into account).

Plus, what if you want the handler to apply to PUT and GET, then you can't have the method named put any more, so you end up with:

Set<HttpMethod> methods = ....
methods.add(HttpMethod.GET);
methods.add(HttpMethod.PUT);
router.method(methods, "foo/bar/order", null, "application/json", ctx -> { ... })

Which is even worse ;)

You could, of course but everything in an Options class, but that just uses the builder pattern anyway.

And in the future, if we want to add even more variables for matching on the route (e.g. headers) it's easy and we don't have to add even more overloaded methods, or break APIs.



But this is my opinion...

Now to the important part :)

Assuming that i am ok with the builder pattern, there are some inconsistencies that i think should be fixed:

# Context API

ctx.contextData().put("wibble", 123);

if ctx is a context assuming the duck typing, why a need for contextData(), i read it like:

"from the context, get me the context data and put at wibble the value 123"

I think it should read:

ctx.put("wibble", 123);

"put into the context key wibble the value 123"

No objection to that.



# Route management

In Yoke i solve this by using JMX since I asked myself how often do i at runtime need to enable and disable routes? and if i do that, most of the times i introduce unexpected behaviour which might break my application.

Although it makes the API sort of complete, it can introduce problems, and if you use JMX then you really want to tweak your app at runtime and you should know what are you doing...

route.disable();
route
.enable();

I don't really understand how this is related to JMX, can you elaborate?


 
# Rely on exceptions for reporting errors

One of the issues I face with exceptions is that throwing it requires it to be thrown at the same thread the router is running otherwise you loose the context and the exception handler is not called. So if your handler is doing some async stuff:

router.route().path("/foo/bar").handler(ctx -> {
  someAsyncCall(cb -> {
    if (err) throw new RuntimeException()
...

in this case the router will probably not catch it and there is no way to specify the error, that is why yoke has the argument to the next() call.

Also exceptions like this will force crawl of the stack to generate the stacktrace and some times you don't need that even...

In my opinion the exception handling is all about handling *Unhandled exceptions*, i.e. RuntimeExceptions that are thrown unexpectedly from handler code. Anything else you can deal with yourself.



# Integrate with Yoke

In theory it could be done, however this is a quite limited version of Yoke Router, Yoke router does parse path parameters: /api/:arg1, it also does arg validation before calling the handler, so if you register a param "arg1" it can be validated against a regex or even a handler before calling the handler.

None of that will go away. The current routematcher does that too, so you can assume by the time you get the request that will have happened.


It exposes control of all routes in JMX

We can do that too.


and can also use POJOs with annotations like:

class MyRoutes {
  @RegExParam("arg1")
  final Pattern validator = Pattern.compile("\d+);

  @Produces("application/json")
  @Consumes("application/json")
  @PUT("/api/:arg1)
  void apiPut(YokeRequest request, Handler next) {
    ...
  }
}

So in order to use it in yoke either it needs some extension on Yoke side to support all yoke features...

Can you elaborate on "extension"?

Paulo Lopes

unread,
Nov 4, 2014, 11:04:43 AM11/4/14
to ve...@googlegroups.com
Well what i wanted to mean is that: how often do you enable/disable routes at runtime? isn't this a concern of something else than your application? maybe JMX should be more related to perform this kind of actions that code everything... Yes JMX is kind of ugly but monitoring tools use it, it is in the JVM itself so i think it should handle this task.
 

 
# Rely on exceptions for reporting errors

One of the issues I face with exceptions is that throwing it requires it to be thrown at the same thread the router is running otherwise you loose the context and the exception handler is not called. So if your handler is doing some async stuff:

router.route().path("/foo/bar").handler(ctx -> {
  someAsyncCall(cb -> {
    if (err) throw new RuntimeException()
...

in this case the router will probably not catch it and there is no way to specify the error, that is why yoke has the argument to the next() call.

Also exceptions like this will force crawl of the stack to generate the stacktrace and some times you don't need that even...

In my opinion the exception handling is all about handling *Unhandled exceptions*, i.e. RuntimeExceptions that are thrown unexpectedly from handler code. Anything else you can deal with yourself.

That is fine until you call some library and you don't know what is happening inside, then you need to put guards "try catch" everywhere which just hurts me in the eyes :) the catch code would start to be a bunch of copy paste of stuff like if error then send status code 500 plus message, or a external method that does that... and then you notice that you have an exception handler that does exactly the same so why not allow bubbling the error from your handle to the exception handler...



# Integrate with Yoke

In theory it could be done, however this is a quite limited version of Yoke Router, Yoke router does parse path parameters: /api/:arg1, it also does arg validation before calling the handler, so if you register a param "arg1" it can be validated against a regex or even a handler before calling the handler.

None of that will go away. The current routematcher does that too, so you can assume by the time you get the request that will have happened.

What i meant was that yoke router does more that the route matcher, besides side JMX stuff it does validation not just of parameters /api/:id but it can also verify if the id argument is a number or uuid or whatever you wanted and returns status 400 even before reaching your handler if does not pass the validation.

 

It exposes control of all routes in JMX

We can do that too.

and can also use POJOs with annotations like:

class MyRoutes {
  @RegExParam("arg1")
  final Pattern validator = Pattern.compile("\d+);

  @Produces("application/json")
  @Consumes("application/json")
  @PUT("/api/:arg1)
  void apiPut(YokeRequest request, Handler next) {
    ...
  }
}

So in order to use it in yoke either it needs some extension on Yoke side to support all yoke features...

Can you elaborate on "extension"?

In order to support the routematcher++ i need to get atleast the same features i've right now so i would probably need to extend the routematcher interface...

Also if you now introduce the ctx that contains the request and other objects why not use an API like undertow HttpServerExchange where request and response are blended together?





--
Paulo Lopes
www.jetdrone.com

Tim Fox

unread,
Nov 4, 2014, 11:21:22 AM11/4/14
to ve...@googlegroups.com
It's a very simple feature to have, and people do want this kind of thing - there's actually a PR right now for Vert.x 2.x to add ability to add/remove routes at runtime in RouteMatcher



maybe JMX should be more related to perform this kind of actions that code everything... Yes JMX is kind of ugly but monitoring tools use it, it is in the JVM itself so i think it should handle this task.

I still don't see the connection with JMX, it seems pretty orthogonal.


 

 
# Rely on exceptions for reporting errors

One of the issues I face with exceptions is that throwing it requires it to be thrown at the same thread the router is running otherwise you loose the context and the exception handler is not called. So if your handler is doing some async stuff:

router.route().path("/foo/bar").handler(ctx -> {
  someAsyncCall(cb -> {
    if (err) throw new RuntimeException()
...

in this case the router will probably not catch it and there is no way to specify the error, that is why yoke has the argument to the next() call.

Also exceptions like this will force crawl of the stack to generate the stacktrace and some times you don't need that even...

In my opinion the exception handling is all about handling *Unhandled exceptions*, i.e. RuntimeExceptions that are thrown unexpectedly from handler code. Anything else you can deal with yourself.

That is fine until you call some library and you don't know what is happening inside, then you need to put guards "try catch" everywhere which just hurts me in the eyes :) the catch code would start to be a bunch of copy paste of stuff like if error then send status code 500 plus message, or a external method that does that... and then you notice that you have an exception handler that does exactly the same so why not allow bubbling the error from your handle to the exception handler...

I think you've misunderstood - that's exactly what I am suggesting. You can't throw checked exceptions from a handler anyway, so the only ones that will get through are unchecked exceptions.





# Integrate with Yoke

In theory it could be done, however this is a quite limited version of Yoke Router, Yoke router does parse path parameters: /api/:arg1, it also does arg validation before calling the handler, so if you register a param "arg1" it can be validated against a regex or even a handler before calling the handler.

None of that will go away. The current routematcher does that too, so you can assume by the time you get the request that will have happened.

What i meant was that yoke router does more that the route matcher, besides side JMX stuff it does validation not just of parameters /api/:id but it can also verify if the id argument is a number or uuid or whatever you wanted and returns status 400 even before reaching your handler if does not pass the validation.


I don't see anything that precludes that being done in a Handler.



 

It exposes control of all routes in JMX

We can do that too.

and can also use POJOs with annotations like:

class MyRoutes {
  @RegExParam("arg1")
  final Pattern validator = Pattern.compile("\d+);

  @Produces("application/json")
  @Consumes("application/json")
  @PUT("/api/:arg1)
  void apiPut(YokeRequest request, Handler next) {
    ...
  }
}

So in order to use it in yoke either it needs some extension on Yoke side to support all yoke features...

Can you elaborate on "extension"?

In order to support the routematcher++ i need to get atleast the same features i've right now so i would probably need to extend the routematcher interface...

Can you give me a concrete example?



Also if you now introduce the ctx that contains the request and other objects why not use an API like undertow HttpServerExchange where request and response are blended together?

Not sure I'm with you, can you elaborate?
Reply all
Reply to author
Forward
0 new messages