diff --git a/.gitignore b/.gitignore index 249d002..4e77473 100644 --- a/.gitignore +++ b/.gitignore @@ -12,5 +12,6 @@ pom.xml.asc bower_components *.log /kekkonen.iml -/.idea +**/.idea +**/target .classpath \ No newline at end of file diff --git a/examples/get-post/README.md b/examples/get-post/README.md new file mode 100644 index 0000000..04cba59 --- /dev/null +++ b/examples/get-post/README.md @@ -0,0 +1,7 @@ +# get-post + +A Clojure library designed to show examples of extended usage of Kekkonen. + +## Usage + +Use bat files provided \ No newline at end of file diff --git a/examples/get-post/project.clj b/examples/get-post/project.clj new file mode 100644 index 0000000..e6588a7 --- /dev/null +++ b/examples/get-post/project.clj @@ -0,0 +1,9 @@ +(defproject get-post "0.1.0-SNAPSHOT" + :description "Extended examples" + :dependencies [[org.clojure/clojure "1.8.0"] + [http-kit "2.1.19"] + [clj-http "2.2.0"] + [metosin/kekkonen "0.3.0-SNAPSHOT"]] + :main get-post.core + :profiles {:dev {:dependencies [[midje "1.6.3"] + [ring-mock "0.1.5"]]}}) diff --git a/examples/get-post/run.bat b/examples/get-post/run.bat new file mode 100644 index 0000000..0adfca1 --- /dev/null +++ b/examples/get-post/run.bat @@ -0,0 +1 @@ +lein run \ No newline at end of file diff --git a/examples/get-post/run_tests.bat b/examples/get-post/run_tests.bat new file mode 100644 index 0000000..16279e8 --- /dev/null +++ b/examples/get-post/run_tests.bat @@ -0,0 +1,2 @@ +set MIDJE_COLORIZE=true +lein midje \ No newline at end of file diff --git a/examples/get-post/run_tests_auto.bat b/examples/get-post/run_tests_auto.bat new file mode 100644 index 0000000..a6b5a3f --- /dev/null +++ b/examples/get-post/run_tests_auto.bat @@ -0,0 +1,2 @@ +set MIDJE_COLORIZE=true +lein midje :autotest \ No newline at end of file diff --git a/examples/get-post/src/get_post/core.clj b/examples/get-post/src/get_post/core.clj new file mode 100644 index 0000000..bc66992 --- /dev/null +++ b/examples/get-post/src/get_post/core.clj @@ -0,0 +1,85 @@ +(ns get-post.core + (:require [org.httpkit.server :as server] + [clj-http.client :as client] + [plumbing.core :refer [defnk]] + [kekkonen.cqrs :as cqrs] + [kekkonen.core :as k] + [schema.core :as s])) + +(s/defschema GetInput + {:name s/Str + (s/optional-key :description) s/Str}) + +; GET http://localhost:3000/api/get-and-post?name=taras +(s/defn get-handler + "Echoes a GetInput" + [data :- GetInput] + ; here is your handler + (cqrs/success data)) + +(s/defschema PostInput + {:data s/Str}) + +; POST http://localhost:3000/api/get-and-post {"data":"taras"} +(s/defn post-handler + "Echoes a PostInput" + [data :- PostInput] + ; here is your handler + (cqrs/success data)) + +(defnk ^:query simple-get + "handles get" + [data request] + (cqrs/success data)) + +(defnk ^:get-post get-and-post + "handles both requests" + [get-params post-params request] + (if (= (:request-method request) :get) + ; note - with-fn-validation is not thread safe + (s/with-fn-validation (get-handler get-params)) + (s/with-fn-validation (post-handler post-params)))) + +(defn interceptor [ctx] + "logs incoming requests for us" + (let [uri (get-in ctx [:request :uri]) + request-method (name (get-in ctx [:request :request-method]))] + (println (str request-method ": " uri)) + #_(clojure.pprint/pprint (:request ctx)) + ctx)) + +(defn err-handler [ex data req] + "logs exception message and return info to client" + (println (str "ERROR: " (.getMessage ex))) + (cqrs/failure (.getMessage ex))) + +(def app (cqrs/cqrs-api {:core {:handlers {:api [#'get-and-post + #'simple-get]} + :type-resolver (k/type-resolver :get-post :command :query)} + :mw {:exceptions {:handlers {:schema.core/error err-handler}}} + :ring {:types {:get-post {:methods #{:get :post} + ; :query-params comes from Ring https://github.com/ring-clojure/ring/wiki/Parameters + :parameters {[:get-params] [:request :query-params] + [:post-params] [:request :body-params]}}} + :interceptors [interceptor]}})) + +(defonce server (atom nil)) + +(defn stop-server [] + (when-not (nil? @server) + (@server :timeout 100) + (reset! server nil))) + +(defn -main [& args] + (reset! server (server/run-server #'app {:port 3000})) + (println "server running in port 3000") + (client/get "http://localhost:3000/api/simple-get") + (client/get "http://localhost:3000/api/get-and-post?name=taras") + (client/post "http://localhost:3000/api/get-and-post" {:body "{\"data\":\"taras\"}" + :content-type :json}) + (println "Schema validation demonstration:") + (client/get "http://localhost:3000/api/get-and-post?nameWWW=taras")) + +(defn run-server [] + (reset! server (server/run-server #'app {:port 3000})) + (println "server running in port 3000")) \ No newline at end of file diff --git a/examples/get-post/test/get_post/core_test.clj b/examples/get-post/test/get_post/core_test.clj new file mode 100644 index 0000000..a5d4369 --- /dev/null +++ b/examples/get-post/test/get_post/core_test.clj @@ -0,0 +1,16 @@ +(ns get-post.core-test + (:use midje.sweet) + (:require [clojure.test :refer :all] + [get-post.core :refer :all] + [ring.mock.request :as mock] + [kekkonen.cqrs :as cqrs])) + +(facts "About http handling" + (fact "GET works for simple-get" + (app (mock/request :get "/api/simple-get?name=taras")) => cqrs/success?) + (fact "GET works for get-and-post" + (app (mock/request :get "/api/get-and-post?name=taras")) => cqrs/success?) + (fact "POST works for get-and-post" + (let [r (mock/request :post "/api/get-and-post") + rb (assoc r :body-params {:data "taras"})] + (app rb) => cqrs/success?))) \ No newline at end of file