{"id":11764,"date":"2014-02-24T09:00:00","date_gmt":"2014-02-24T08:00:00","guid":{"rendered":"http:\/\/pjagielski.github.com\/2014\/02\/24\/microservices-jvm-clojure"},"modified":"2022-08-02T14:39:45","modified_gmt":"2022-08-02T12:39:45","slug":"micro-services-on-the-jvm-part-1-clojure","status":"publish","type":"post","link":"https:\/\/touk.pl\/blog\/2014\/02\/24\/micro-services-on-the-jvm-part-1-clojure\/","title":{"rendered":"Micro services on the JVM part 1 &#8211; Clojure"},"content":{"rendered":"<p>Micro services could be a buzzword of 2014 for me. Few months ago I was curious to try <a href=\"http:\/\/www.dropwizard.io\/\">Dropwizard<\/a> framework as a separate backend, but didn\u2019t get the whole idea yet. But then I watched a mind-blowing <a href=\"http:\/\/www.youtube.com\/watch?v=2rKEveL55TY\">\u201cMicro-Services Architecture\u201d<\/a> talk by Fred George. Also, the 4.0 release notes of <strong>Spring<\/strong> <a href=\"https:\/\/spring.io\/blog\/2013\/12\/12\/announcing-spring-framework-4-0-ga-release\">covers microservices<\/a> as an important rising trend as well. After 10 years of having SOA in mind, but still developing monoliths, it\u2019s a really tempting idea to try to decouple systems into a set of independently developed and deployed RESTful services.<\/p>\n<p>So when I decided to write a simple API for my <a href=\"http:\/\/devrates.com\/\">DevRates.com<\/a> website, instead of adding some code to existing codebase, I wanted to build a separate tiny app. But what\u2019s the best stack for micro-services? In this series of posts I\u2019ll try to compare various JVM technology stacks for this approach.<\/p>\n<p>Here is my list of must-have features for the stack:<\/p>\n<ul>\n<li>declarative REST support (no manual URL parsing)<\/li>\n<li>native JSON support (bidirectional JSON-object mapping)<\/li>\n<li>single \u201cfat\u201d jar packaging, no web container needed<\/li>\n<li>fast development feedback loop (eg. runtime code reloading)<\/li>\n<li><a href=\"https:\/\/github.com\/wordnik\/swagger-core\">Swagger<\/a> and <a href=\"http:\/\/metrics.codahale.com\/\">Metrics<\/a> integration<\/li>\n<\/ul>\n<p>In this post I\u2019ll try to cover <strong>Clojure<\/strong> with <a href=\"https:\/\/github.com\/ring-clojure\/ring\">Ring<\/a> and <a href=\"https:\/\/github.com\/weavejester\/compojure\">Compojure<\/a>.<\/p>\n<h2 id=\"tldr\">TL;DR<\/h2>\n<p>You can find all the covered concepts in the following GitHub examples:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/pjagielski\/microservices-jvm\/tree\/master\/compojure-rest\">compojure-rest<\/a> &#8211; basic <strong>Compojure<\/strong> app with main class<\/li>\n<li><a href=\"https:\/\/github.com\/pjagielski\/microservices-jvm\/tree\/master\/compojure-swag\">compojure-swag<\/a> &#8211; <strong>Swagger<\/strong> and <strong>Metrics<\/strong> integration<\/li>\n<li><a href=\"http:\/\/github.com\/pjagielski\/clorates\">clorates<\/a> &#8211; complete implementation of <a href=\"http:\/\/devrates.com\/api\/swagger\/index.html\">DevRates.com API<\/a><\/li>\n<\/ul>\n<h2 id=\"basic-setup\">Basic setup<\/h2>\n<p>There is an excellent <a href=\"http:\/\/zaiste.net\/2014\/02\/web_applications_in_clojure_all_the_way_with_compojure_and_om\/\">Zaiste\u2019s tutorial<\/a> showing how to kickstart REST app with <strong>Compojure<\/strong>, just follow these few simple steps (the rest of the post assumes <code>compojure-rest<\/code> as the app name).<\/p>\n<p>My sample route from <code>handler.clj<\/code>:<\/p>\n<div class=\"highlight\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">(defroutes app-routes (GET \"\/messages\/:name\" [name] {:body {:message (str \"Hello World\" \" \" name)}}) (route\/resources \"\/\") (route\/not-found \"Not Found\"))<\/pre>\n<\/div>\n<h2 id=\"fat-jar\">Fat jar<\/h2>\n<p>In a simple setup, <strong>Compojure<\/strong> app is being run through lein ring plugin. To enable running it as a standalone command-line app, you have to write a main method which starts <strong>Jetty<\/strong> server.<\/p>\n<p><code>project.clj<\/code><\/p>\n<div class=\"highlight\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">:dependencies ... [ring\/ring-jetty-adapter \"1.2.0\"] .. :main compojure-rest.handler<\/pre>\n<\/div>\n<p><code>handler.clj<\/code><\/p>\n<div class=\"highlight\"><\/div>\n<p>To build a single \u201cfat\u201d jar just run <code>lein uberjar<\/code>, and then <code>java -jar target\/compojure-rest-0.1.0-SNAPSHOT-standalone.jar<\/code> runs the app.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">(ns compojure-rest.handler ... (:require ... [ring.adapter.jetty :refer (run-jetty)]) (:gen-class)) ... (defn -main [&amp; args] (run-jetty app {:port 3000 :join? false }))<\/pre>\n<h2 id=\"swagger\">Swagger<\/h2>\n<p>The nice thing about <strong>Compojure<\/strong> is that you can easy expose Swagger documentation by using <a href=\"https:\/\/github.com\/narkisr\/swag\">swag<\/a> library. There are some conflicts between swag and ring lein plugin, so just look at the <a href=\"https:\/\/github.com\/pjagielski\/microservices-jvm\/tree\/master\/compojure-swag\">compojure-swag<\/a> for a working example.<\/p>\n<p>Here is a typical snippet from <code>handler.clj<\/code>:<\/p>\n<div class=\"highlight\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">(set-base \"http:\/\/localhost:3000\") (defroutes- messages {:path \"\/messages\" :description \"Messages management\"} (GET- \"\/messages\/:name\" [^:string name] {:nickname \"getMessages\" :summary \"Get message\"} {:body {:message (str \"Hello World\" \" \" name)}}) (route\/resources \"\/\") (route\/not-found \"Not Found\"))<\/pre>\n<\/div>\n<p>So, <code>swag<\/code> introduces <code>defroutes-<\/code>, <code>GET-<\/code>, <code>POST-<\/code> which take additional metadata as parameters to generate Swagger docs. If you\u2019re little scared with this <code>^:string<\/code> fragment &#8211; check <a href=\"http:\/\/clojure.org\/metadata\">metadata<\/a> section from Clojure manual. Swagger-compatible definition should be available at <code>http:\/\/localhost:3000\/api-docs.json<\/code> after running the app.<\/p>\n<h2 id=\"metrics\">Metrics<\/h2>\n<p>To expose basic metrics of your REST API calls just use Ring-compatible <code>metrics-clojure-ring<\/code> library.<\/p>\n<p><code>project.clj<\/code><\/p>\n<div class=\"highlight\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">:dependencies ... [metrics-clojure-ring \"1.0.1\"] ...<\/pre>\n<\/div>\n<p><code>handler.clj<\/code><\/p>\n<div class=\"highlight\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">(ns compojure-rest.handler ... (:require ... [metrics.ring.expose :refer [expose-metrics-as-json]] [metrics.ring.instrument :refer [instrument]])) ... (def app (expose-metrics-as-json (instrument app) \"\/stats\/\"))<\/pre>\n<\/div>\n<p>After generating some load by eg. <a href=\"https:\/\/github.com\/wg\/wrk\">wrk<\/a>, you can check the collected stats by visiting <code>http:\/\/localhost:3000\/stats\/<\/code>.<\/p>\n<div class=\"highlight\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">ring.requests.rate.GET: { type: \"meter\", rates: { 1: 189.5836593065824, 5: 39.21602480726734, 15: 13.146759983907245 } }<\/pre>\n<\/div>\n<h2 id=\"some-random-clojure-thoughts\">Some random Clojure thoughts<\/h2>\n<ul>\n<li>The best newbie guide to Clojure is Kyle Kingsbury\u2019s <a href=\"http:\/\/aphyr.com\/tags\/Clojure-from-the-ground-up\">\u201cClojure from the ground up\u201d<\/a> series.<\/li>\n<li>Leiningen is probably the best build tool for the JVM. Easy to install, fast, simple, no XML &#8211; just doing it right. And the \u201cnew\u201d project templates is what\u2019s Maven been missing from ages (anyone using archetypes?).<\/li>\n<li>Lighttable is great! I\u2019m really impressed with the fast feedback loop by just ctrl+entering the expressions.<\/li>\n<li>Also, live reloading with <code>ring server<\/code> works fine. Just change the change code and see the changes immediately. Rapid!<\/li>\n<li>Unlike other recently popular languages, Clojure has no killer-framework. Rails, Play\/Akka, Grails\/Gradle &#8211; all of these are key parts of Ruby, Scala and Groovy ecosystems. What about Clojure? A collection of small (micro?) libraries doing one thing well and working great together &#8211; just like Unix commands.<\/li>\n<li>It may be true that Clojure is not good for large projects. With all the complex contructs (meta or ) and no control of the visibility, it could be hard to maintain large codebase. But it\u2019s not a first-class problem in a micro-services world..<\/li>\n<\/ul>\n<h2 id=\"resources\">Resources<\/h2>\n<ul>\n<li><a href=\"https:\/\/www.youtube.com\/watch?v=2rKEveL55TY\">Talk by Fred George<\/a><\/li>\n<li><a href=\"http:\/\/www.infoq.com\/presentations\/Micro-Services\">Java, the Unix Way &#8211; James Lewis from ThoughtWorks<\/a><\/li>\n<li><a href=\"http:\/\/yobriefca.se\/blog\/2013\/04\/29\/micro-service-architecture\/\">Micro Service Architecture &#8211; nice article<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"\nMicro services could be a buzzword of 2014 for me. Few months ago I was curious to try Dropwizard framework as a separate backend, but didn\u2019t get the whole idea yet. But then I watched a mind-blowing \u201cMicro-Services Architecture\u201d talk by Fred George. Also, the 4.0 release notes of Spring covers microservices as an important rising trend as well. After 10 years of having SOA in mind, but still developing monoliths, it\u2019s a really tempting idea to try to decouple systems into a set of independently developed and deployed RESTful services.\n\nMicro services could be a buzzword of 2014 for me. Few months ago I was curious to try Dropwizard framework as a separate backend, but didn\u2019t get the whole idea yet. But then I watched a mind-blowing \u201cMicro-Services Architecture\u201d talk by Fred George. Also, the 4.0 release notes of Spring covers microservices as an important rising trend as well. After 10 years of having SOA in mind, but still developing monoliths, it\u2019s a really tempting idea to try to decouple systems into a set of independently developed and deployed RESTful services.\n\n","protected":false},"author":5,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[637,491],"class_list":{"0":"post-11764","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-development-design","7":"tag-architecture","8":"tag-clojure"},"_links":{"self":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/11764","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/comments?post=11764"}],"version-history":[{"count":8,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/11764\/revisions"}],"predecessor-version":[{"id":14859,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/11764\/revisions\/14859"}],"wp:attachment":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/media?parent=11764"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/categories?post=11764"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/tags?post=11764"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}