├── README.md └── _config.yml /README.md: -------------------------------------------------------------------------------- 1 | # clojure-spring-guide 2 | Guidelines for using Clojure with Spring Framework 3 | 4 | [Clojure Style Guide](https://goo.gl/WWfjB) 5 | 6 | # Controllers 7 | 8 | * Use [@RestController](https://goo.gl/DpiwnS) 9 | * Use [@GetMapping](https://goo.gl/Y1tX55), [@PostMapping](https://goo.gl/BsajaA) family of annotations over traditional [@RequestMapping](https://goo.gl/naenPG) ones 10 | * Consume and Produce [MediaType.APPLICATION_JSON_UTF8_VALUE](https://goo.gl/US1rUY) 11 | * When returning clojure data structures out of controllers, use [cheshire](https://goo.gl/TCNat) 12 | ```clojure 13 | (ns ... 14 | (:require [cheshire.core :as json])) 15 | ``` 16 | 17 | and then return using 18 | 19 | ```clojure 20 | (json/generate-string {:a 1 :b 2}) 21 | ``` 22 | 23 | * When using annotations like [@PathVariable](https://goo.gl/b5XdMB), [@RequestParam](https://goo.gl/nm7ZiD) etc., specify the `value` attribute as the debugging information is not available. The value attribute can be dash-case. 24 | Otherwise the following error will occur: `Name for argument type [java.lang.String] not available, and parameter name information not found in class file either.` 25 | 26 | * We cannot require another namespace or import a class in `(ns :gen-class )`. The code emitted by ns macro calls `:gen-class` before calling any of the `:require` or `:import`. 27 | Thus the required namespace/class or not compiled when `:gen-class` is called. We can use fully qualified names to solve this, but that would be ugly. 28 | A Better solution is to call `(gen-class ...)` after `(ns ...)` 29 | 30 | * Method arguments types and return types still need to be fully qualified (except java.lang.*) 31 | 32 | * Method names should be camelCase instead of dash-case due to Java restrictions 33 | 34 | * If you prefer, you can return [CompletableFuture](https://goo.gl/QQ6uv2) from the controller method to be asynchronous with the following macro 35 | 36 | ```clojure 37 | (ns ... 38 | (:import (java.util.concurrent CompletableFuture) 39 | (java.util.function Supplier))) 40 | 41 | (defmacro async 42 | "Wraps the given `body` inside a CompletableFuture." 43 | [& body] 44 | `(CompletableFuture/supplyAsync 45 | (reify 46 | Supplier 47 | ~(list 'get '[this] (cons 'do body))))) 48 | ``` 49 | 50 | and then use it like 51 | 52 | ```clojure 53 | (async 54 | (println "Async Controller method") 55 | (+ 3 5)) 56 | ``` 57 | 58 | ## Complete Example 59 | 60 | ```clojure 61 | (ns com.clojurespring.controller 62 | (:require [cheshire.core :as json]) 63 | (:import (org.springframework.web.bind.annotation RestController GetMapping PathVariable))) 64 | 65 | (gen-class 66 | :name ^{RestController {}} com.clojurespring.SampleController 67 | :methods [[^{GetMapping {:value ["/hello"] 68 | :produces ["application/json;charset=UTF-8"}} 69 | hello [^{PathVariable {:value "name"}} String] java.util.concurrent.Future]]) 70 | 71 | (defn -hello 72 | [this name] 73 | (async 74 | (println "Inside async controller...") 75 | (json/generate-string {:a 1 76 | :message (str "Hello " name " from Clojure controller")))) 77 | ``` 78 | ### Request 79 | ```bash 80 | curl -X GET -H "Accept: application/json;charset=UTF-8" "http://server.name/hello/rich" 81 | ``` 82 | 83 | ### Response 84 | ```json 85 | { 86 | "a": 1, 87 | "message": "Hello rich from Clojure controller" 88 | } 89 | ``` 90 | 91 | # Contributing 92 | 93 | Nothing written in this guide is set in stone. It's my desire to work together with everyone interested in Clojure coding style, so that we could ultimately create a resource that will be beneficial to the entire Clojure community. 94 | 95 | Feel free to open tickets or send pull requests with improvements. Thanks in advance for your help! 96 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman --------------------------------------------------------------------------------