using dropwizard to server web, dynamically mapping custom urls to endpoints

1,855 views
Skip to first unread message

S Ahmed

unread,
Oct 14, 2012, 11:03:07 PM10/14/12
to dropwiz...@googlegroups.com
I'm thinking of using dropwizard to server http content (as a replacement for a spring application).

I'm not sure if my dynamic url mapping is possible so I want your opinions.

So i'm going to create a resource endpoint that would normally have a url pattern like:

/blog  - list posts
/blog/my-first-post  - show blog post

Normally you would create a resource with Path values like:

@Path("/blog")
@Path("/blog/{title}")

Now say I want to give users the option to choose the name of their blog like:

www.example.com/cats-blog/  or maybe on a subdomain like cats-blog.example.com

Now I need to somehow internally, whenever a request comes for /cats-blog, to map that to the endpoint that would 'normally' respond to /blog

www.example.com/cats-blog/my-first-post would map to /blog/my-first-post endpoint ( @Path("/blog/{title}") )

Note: these values will by created by end users, so it is dynamic in nature and I can't re-start the system or anything...


Ryan Kennedy

unread,
Oct 14, 2012, 11:07:45 PM10/14/12
to dropwiz...@googlegroups.com, dropwiz...@googlegroups.com
You could use a servlet filter to rewrite the request on the way in to normalize all of your requests to either use the URI prefixed by the blog name or to move the blog name from the URI to the Host header. 

Ryan 

Coda Hale

unread,
Oct 14, 2012, 11:27:38 PM10/14/12
to dropwiz...@googlegroups.com
Write an injection provider for the Host header in the requests.

Here's a blog post I wrote a while ago on how to do that: http://codahale.com/what-makes-jersey-interesting-injection-providers/

You're aiming for a resource method which looks like this:

public Whatever showBlog(@Hostname String hostname, @QueryParam("title") String title) {
    // etc
}

You'll have to write the @Hostname annotation, a provider, and an injectable to copy the Host header from the @Context-injected HttpHeaders to a @Hostname-annotated string parameter.

---
Coda Hale
http://codahale.com



On Oct 14, 2012, at 8:03 PM, S Ahmed <sahme...@gmail.com> wrote:

S Ahmed

unread,
Oct 15, 2012, 9:59:16 AM10/15/12
to dropwiz...@googlegroups.com
Great writeup, much appreciated!

S Ahmed

unread,
Oct 15, 2012, 10:57:39 AM10/15/12
to dropwiz...@googlegroups.com
Ok i'm going to re-read things a few more times, but what I still don't understand is how jersey/dropwizard is going to call the correct resource when the URI doesn't match.


And my blog resource has:

@Path("/blog")
or
@Path("/blog/{title}")


What exactly am I looking for in the host-header that I will use to set @Hostname annoation? The 'my-cat-blog' part of the URI?  
Confused why I can't just look at the URL request.getRequestURL(); (or is that only fetched via the host-header and its the same thing).



On Sun, Oct 14, 2012 at 11:27 PM, Coda Hale <coda...@gmail.com> wrote:

Nick Telford

unread,
Oct 15, 2012, 12:13:47 PM10/15/12
to dropwiz...@googlegroups.com
If you want to match on the hostname of the website (e.g. example.com) create an @Hostname Injectable annotation as Coda illustrated.

If you just want to match on a different path prefix, simply include that as a variable in your resource:

@Path("/{blog}/{title}")
public Whatever get(@PathParam("blog") String blog, @PathParam("title") String title) {

}

S Ahmed

unread,
Oct 15, 2012, 12:31:12 PM10/15/12
to dropwiz...@googlegroups.com
Ok let me clarify things a bit, my goal is to be able to do this:


Now all 3 of the above urls are using 3 different resources:


The database will have a table that will tell me that 'my-cats-blog' is a blog, and 'my-articles' is an article.

So I will have 3 different resources that will have all the RESTfull endpoints for each of the different resources like:

@Path("/articles")
@Path("/articles/{articleId}/edit")
@Path("/articles/new")
etc.

The idea is, I have all these various resources like blogs, articles, polls, etc., and when someone sets up a website, they choose a sub-directory and then map it to a resource type (blog/article/poll).  Then when a request comes in, I have to figure out what type of resource it is, then somehow direct the request so the correct resource handles the request and sends the response.

Diego Magalhães

unread,
Oct 15, 2012, 12:53:22 PM10/15/12
to dropwiz...@googlegroups.com

I think you're missing the whole point of uri.

Tatu Saloranta

unread,
Oct 15, 2012, 1:00:45 PM10/15/12
to dropwiz...@googlegroups.com
On Mon, Oct 15, 2012 at 9:31 AM, S Ahmed <sahme...@gmail.com> wrote:
> Ok let me clarify things a bit, my goal is to be able to do this:
>
> www.example.com/my-cats-blog/
> www.example.com/my-articles/
> www.example.com/my-poll/
>
> Now all 3 of the above urls are using 3 different resources:
>
> www.example.com/my-cats-blog/ => blog
> www.example.com/my-articles/ => articles
> www.example.com/my-poll/ => polls
>
> The database will have a table that will tell me that 'my-cats-blog' is a
> blog, and 'my-articles' is an article.
>
> So I will have 3 different resources that will have all the RESTfull
> endpoints for each of the different resources like:
>
> @Path("/articles")
> @Path("/articles/{articleId}/edit")
> @Path("/articles/new")
> etc.
>
> The idea is, I have all these various resources like blogs, articles, polls,
> etc., and when someone sets up a website, they choose a sub-directory and
> then map it to a resource type (blog/article/poll). Then when a request
> comes in, I have to figure out what type of resource it is, then somehow
> direct the request so the correct resource handles the request and sends the
> response.

Just use regular Servlets or Servlet filters. DropWizard lets you do
Old Skool stuff too.
JAX-RS is best when you do have static structures, known at
compile/build time. Trying to handle dynamic things with static
constructs (Annotations) is problematic and complexity increases
faster than functionality.

-+ Tatu +-

Coda Hale

unread,
Oct 15, 2012, 2:28:44 PM10/15/12
to dropwiz...@googlegroups.com
@Path("/{blog-name}-{aspect}/{name}") will parse "/my-cats-blog/so-fluffy" into {blog-name: my-cats, aspect: blog, name: so-fluffy}.

You may want to spend some time reading the Jersey user manual.


---
Coda Hale
http://codahale.com



S Ahmed

unread,
Oct 15, 2012, 3:44:26 PM10/15/12
to dropwiz...@googlegroups.com
I'll keep reading then :)

I want urls w/o the {aspect}, and keep my resources RESTful and not have a single resource handling articles, polls, blogs, etc.

Coda Hale

unread,
Oct 15, 2012, 5:00:46 PM10/15/12
to dropwiz...@googlegroups.com
Ok, then include the -blog in the non-variable part of your URI templates:

  @Path("/{blog-name}-photos/{photo-name}")

---
Coda Hale
http://codahale.com



S Ahmed

unread,
Oct 15, 2012, 7:39:17 PM10/15/12
to dropwiz...@googlegroups.com
The point I'm trying to make is I want the URL to not contain any marker whatsoever :)  100% end-user customizable sub-folder name that maps to a particular resource type (article, poll, blog, etc.)

Diego Magalhães

unread,
Oct 15, 2012, 7:45:40 PM10/15/12
to dropwiz...@googlegroups.com

You're trying to write a dispatcher in the hardest way possible.

Coda Hale

unread,
Oct 15, 2012, 7:47:07 PM10/15/12
to dropwiz...@googlegroups.com
So far you haven't mentioned a URL like that.

What does your ideal URL look like?


---
Coda Hale
http://codahale.com



S Ahmed

unread,
Oct 15, 2012, 7:47:25 PM10/15/12
to dropwiz...@googlegroups.com
if there is an easier way that meet the requirements, please tell me.

sorry i'm still learning and I appreciate all your guidance.

S Ahmed

unread,
Oct 15, 2012, 7:52:59 PM10/15/12
to dropwiz...@googlegroups.com
Coda,

Ah, I'm just looking back at my first post and I noticed I called it 'my-cats-blog', it wasn't my intention to make it seem like 'blog' was anything significant, it was just the name.

Let me start over, I want to make a application that has 'modules' like blogs, polls, forums, etc.
The end user can choose the sub-folder name to be whatever they want, and the database will contain the sub-folder to 'module' mapping, so:

'vacation-posts' => blog module
'business-ideas' => article module
'feedback' => forum module

To keep things restful and well organized, there will be a resource for each 'module', so for example the blog resource will have endpoints for:

/blog => list recent blog posts
/blog/{title} => specific blog entry
/blog/{blogId}/edit  => edit blog
etc.

So ideal blog url will be:

www.example.com/dropwizard-tips-and-tricks   where 'dropwizard-tips-and-tricks' will be the blog name, in the database it would look like:

id                name                                      module_type
123123        'dropwizard-tips-and-tricks'        'blog'

Hope this clears things up.

Diego Magalhães

unread,
Oct 15, 2012, 8:05:52 PM10/15/12
to dropwiz...@googlegroups.com
Ahmed, 

   Create a diff resource for each purpose

@Path("blog") for blogging
@Path("ideas") for articles

etc...

In each resource, write the methods todo your business stuff

Diego Magalhães
http://diegomagalhaes.com
claro @ +55 21 9411 2823

Nick Telford

unread,
Oct 16, 2012, 6:05:32 AM10/16/12
to dropwiz...@googlegroups.com
The important thing here is that you need some way to pass the "site" the user selected through from the request to the DAO so you can look up the appropriate response.

The simplest way to do this is just to make the site a parameter on your resource, which is why we've all been suggesting using either @PathParam or a custom Host-header Injectable to allow your resource to collect the site and do something with it (e.g. pass it to the DAO).

If you don't want an explicit parameter on your resource, you'll need to find some other way to collect and inject this information. This was the idea behind the ServletFilter, which would be able to direct requests at site-specific resources.

I would recommend having a resource class for each module (e.g. BlogResource, ForumResource, etc.) and set a top-level @Path on each class for the site: @Path("/{site}"). Each method will then explicitly require a @PathParam("site") parameter, which it can then use to select a response.

S Ahmed

unread,
Oct 17, 2012, 9:49:03 AM10/17/12
to dropwiz...@googlegroups.com
Diego,

I think you missed the point, I need custom urls (see my previous emails for a description).

Ryan Kennedy

unread,
Oct 17, 2012, 12:13:08 PM10/17/12
to dropwiz...@googlegroups.com
If you want fully custom URLs and don't want to code any path into the @Path annotations then you're going to have to use something like UriInfo…


Set the @Path to be as permissive as you need (/* maybe) and make one of the method parameters a UriInfo. You'll have to perform your own routing at that point.

Alternatively, a custom provider as Coda suggested if you want less ambiguity in the method parameters. However, the custom provider will basically be working against a UriInfo or something very similar.

-- 
Ryan Kennedy

Tatu Saloranta

unread,
Oct 17, 2012, 12:19:41 PM10/17/12
to dropwiz...@googlegroups.com
On Wed, Oct 17, 2012 at 9:13 AM, Ryan Kennedy <rcke...@gmail.com> wrote:
> If you want fully custom URLs and don't want to code any path into the @Path
> annotations then you're going to have to use something like UriInfo…

As I suggested earlier, it might actually make sense to go to raw
Servlets. If one is not to really use any of JAX-RS features, there's
little point to go with resources.

-+ Tatu +-

Ryan Kennedy

unread,
Oct 17, 2012, 12:20:58 PM10/17/12
to dropwiz...@googlegroups.com
Yeah, at the point you drop down to raw UriInfo you're basically writing a Servlet anyway. Just inject HttpServletRequest and call it JAX-Servlet.

-- 
Ryan Kennedy

S Ahmed

unread,
Oct 18, 2012, 12:07:35 PM10/18/12
to dropwiz...@googlegroups.com
so your suggesting use raw servlets, and not use dropwizard at all b/c of the dynamic nature of routing?

Tatu Saloranta

unread,
Oct 18, 2012, 12:11:46 PM10/18/12
to dropwiz...@googlegroups.com
Yes, I would probably go that route.

The other suggestion of using UriInfo injected also works, in case you
do find other features of DropWizard useful here. There is nothing
wrong in doing that either.

Note that you can mix and match these things to some degree as well; I
use Servlets myself for some low-level CRUD pieces, but Resources for
more structured things.
This is one aspect of DW that I like: it gives you convenience, but
does not stand in the way in case you occasionally need to go do
things more manual way.

-+ Tatu +-

Ryan Kennedy

unread,
Oct 18, 2012, 12:42:30 PM10/18/12
to dropwiz...@googlegroups.com
Or use servlets in dropwizard. Nothing about dropwizard prevents you from using bare servlets in lieu of JAX-RS.

-- 
Ryan Kennedy

Tatu Saloranta

unread,
Oct 18, 2012, 1:53:28 PM10/18/12
to dropwiz...@googlegroups.com
Actually, one clarification: what I meant to say "yes, use Servlets,
but no, don't have to leave DropWizard". As Ryan mentioned, DropWizard
makes it easy to also add Servlets for low-level stuff. I find
DropWizard still useful for handling other aspects, GUIs, metrics,
life-cycle handling, that goodness.

-+ Tatu +-
Reply all
Reply to author
Forward
0 new messages