01 April 2016
Using Swagger with embedded Jetty and without magic
There is a curious ailment that appears to afflict great swathes of Java developers: the wiring of an application must never use simple Java! Only reflection-heavy, automagic, confusing configuration is allowed!
Take Jersey as an example, where the vast majority of tutorials showing how to expose your REST service in a Jetty server assumes it is okay to register your class with the framework, and then have the framework instantiate it:
This means you can’t pass dependencies into the constructor. So what should you do? Get dependencies from some global, static, service provider.
For why?!?
It’s sad that this anti-pattern of forcing instantiation of classes, and configuration, is so prevalent among
some of the biggest Java frameworks. It seems the new
keyword is thought to be evil for some reason, and must be
avoided at all costs. Furthermore, classpath-scanning seems to be the holy grail of these
frameworks so that you don’t have to configure anything. This also helps make it extremely difficult to understand
what is happening in what order.
It is possible to avoid all this nonsense by instantiating objects yourself and passing them to a resource config object:
Ahh, that’s better.
Now to the point of this article: getting these manually instantiated REST services registered with Swagger.
Swagger
I have come to love-hate Swagger. The documentation generated is great to use, and I don’t mind the copious amounts of annotation documentation added to the REST services, as the documentation lives with the code in source control and there is no better way to specify it that I can think of. But I what I really dislike is how hard it is to use if you use things like constructor-based dependency injection and want to have control over how it integrates with your embedded web server.
To it’s credit, the docs do show how you can register a package that has your REST resources in it without relying on XML:
Isn’t that just incredibly scary? You create an instance of an object, call some setters, and then let the object
be collected by the garbage collector. Furthermore, the order of the setters matters: setScan
must be called
last because that “setter” is what causes the config to be applied.
I could not abide such an approach
Configuring Swagger explicitly
Here’s what I came up with:
What this does is register only the classes of the REST resources that you have already explicitly registered with the ResourceConfig. There is no classpath scanning, no global variables, and no guessing about what is being registered and what is not.
Sometimes, having more code that is easy to follow is preferable to having no code that requires deep understanding of multiple frameworks to follow what is happening.
Speaking of having lots of code, here are the swagger dependencies:
In this case, swagger.version
is 1.5.8
and with the above the REST schema should be available
as JSON at /swagger.json
Configuring swagger-ui
To actually have the fancy, usable documentation hosted in your web server, you first need to get the swagger-ui HTML into your project. One option is to use the HTML provided by webjars:
Then you can construct a context handler which you can add to your handlers list:
That will expose the docs at /docs
- pass the JSON URL to that to load your REST info: /docs?url=%2Fswagger.json
The code can be seen in context in the App Runner project.