I have a Ring app that through deploys to production as an uberwar
thing; myservice.war. In production the WAR file gets tossed into Jetty where it runs in a context that follows its name
$ curl -i -X GET http://myservice.qa1.example.com:8080/myservice/healthz
HTTP/1.1 200 OK
...
When I run locally through lein ring, I need it to run in the same context; myservice.
$lein ring server-headless
2015-10-14 14:04:03,457 level=INFO [main] Server:271 - jetty-7.6.13.v20130916
2015-10-14 14:04:03,482 level=INFO [main] AbstractConnector:338 - Started [email protected]:10313
Started server on port 10313
But the same curl goes all 404 on me locally.
$ curl -i -X GET http://localhost:10313/myservice/healthz
HTTP/1.1 404 Not Found
...
The lein ring thing deployed it onto the root context.
$ curl -i -X GET http://localhost:10313/healthz
HTTP/1.1 200 OK
...
Whats up with that? How do I direct lein ring to deploy into a context name of my choosing? I need curl -i -X GET http://localhost:10313/myservice/healthz
to work from lein ring
One way to work around this issue is to create the second (standalone) set of routes for your app. You also create the second handler for the standalone case. Then you can use Leiningen profiles to specify different handlers for the standalone case and the uberwar case. The default profile is used when running the app standalone. The :uberjar
profile is used when the uberwar is created. As a result, your standalone handler going to be used with lein ring server-headless
and your regular handler is going to be used when the war is deployed into a container.
Not much additional code needed to create the second set of routes. You can just wrap the existing routes in a context of your choosing. Suppose the following are your routes and ring handler:
(defroutes app-routes
(GET "/healthz" [] "Hello World")
(route/not-found "Not Found"))
(def app
(wrap-defaults app-routes site-defaults))
Additional routes and handler for the standalone case would look like this:
(defroutes standalone-routes
(context "/myservice" req app-routes)
(route/not-found "Not Found"))
(def standalone-app
(wrap-defaults standalone-routes site-defaults))
Now, onto lein-ring
configuration in project.clj
. We want the default ring handler to point to standalone-app
. The ring handler for the uberwar should point to app
. The :ring
entry in the project map in project.clj
should look like this (adjust for your actual namespace):
:ring {:handler myservice.handler/standalone-app}
Also, merge the following into your :profiles
map in project.clj
:
:uberjar {:ring {:handler myservice.handler/app}}
Please be sure to use the latest version of the lein-ring
plugin. Version 0.9.7 worked for me. Earlier versions, like 0.8.3, did not work because they did not use the :uberjar
profile when running the uberwar
task.
If you do all this, and assuming your war file is called myservice.war, the context part of the URI is going to be the same whether your app is started with lein ring server-headless
or if the war file is deployed in Jetty.
$ curl http://localhost:[port]/myservice/healthz
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With