diff options
author | Gabriel A. Giovanini <mail@gabrielgio.me> | 2018-02-17 13:55:55 -0200 |
---|---|---|
committer | Gabriel A. Giovanini <mail@gabrielgio.me> | 2018-02-17 13:55:55 -0200 |
commit | 98056e815a6dcd36d7377d3cd823a4aaf5a3d9fa (patch) | |
tree | 61f453e1b21634e0f2d740ff61091d182e145184 | |
download | queue-api-98056e815a6dcd36d7377d3cd823a4aaf5a3d9fa.tar.gz queue-api-98056e815a6dcd36d7377d3cd823a4aaf5a3d9fa.tar.bz2 queue-api-98056e815a6dcd36d7377d3cd823a4aaf5a3d9fa.zip |
Initial commit
-rw-r--r-- | .gitignore | 18 | ||||
-rw-r--r-- | Dockerfile | 8 | ||||
-rw-r--r-- | README.md | 21 | ||||
-rw-r--r-- | env/dev/clj/queue_api/dev_middleware.clj | 10 | ||||
-rw-r--r-- | env/dev/clj/queue_api/env.clj | 14 | ||||
-rw-r--r-- | env/dev/clj/user.clj | 16 | ||||
-rw-r--r-- | env/dev/resources/config.edn | 4 | ||||
-rw-r--r-- | env/dev/resources/logback.xml | 35 | ||||
-rw-r--r-- | env/prod/clj/queue_api/env.clj | 11 | ||||
-rw-r--r-- | env/prod/resources/config.edn | 2 | ||||
-rw-r--r-- | env/prod/resources/logback.xml | 24 | ||||
-rw-r--r-- | env/test/resources/config.edn | 4 | ||||
-rw-r--r-- | env/test/resources/logback.xml | 35 | ||||
-rw-r--r-- | project.clj | 66 | ||||
-rw-r--r-- | resources/public/favicon.ico | bin | 0 -> 1150 bytes | |||
-rw-r--r-- | src/clj/queue_api/config.clj | 12 | ||||
-rw-r--r-- | src/clj/queue_api/core.clj | 48 | ||||
-rw-r--r-- | src/clj/queue_api/handler.clj | 19 | ||||
-rw-r--r-- | src/clj/queue_api/middleware.clj | 15 | ||||
-rw-r--r-- | src/clj/queue_api/routes/services.clj | 44 | ||||
-rw-r--r-- | test/clj/queue_api/test/handler.clj | 21 |
21 files changed, 427 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d0349ad --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +/target +/lib +/classes +/checkouts +pom.xml +dev-config.edn +test-config.edn +*.jar +*.class +/.lein-* +profiles.clj +/.env +.nrepl-port +/log +Procfile +Capstanfile +.idea/ +*.iml
\ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1580182 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +FROM java:8-alpine +MAINTAINER Your Name <you@example.com> + +ADD target/uberjar/queue-api.jar /queue-api/app.jar + +EXPOSE 3000 + +CMD ["java", "-jar", "/queue-api/app.jar"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..46866b8 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# queue-api + +generated using Luminus version "2.9.12.25" + +FIXME + +## Prerequisites + +You will need [Leiningen][1] 2.0 or above installed. + +[1]: https://github.com/technomancy/leiningen + +## Running + +To start a web server for the application, run: + + lein run + +## License + +Copyright © 2018 FIXME diff --git a/env/dev/clj/queue_api/dev_middleware.clj b/env/dev/clj/queue_api/dev_middleware.clj new file mode 100644 index 0000000..ece7a25 --- /dev/null +++ b/env/dev/clj/queue_api/dev_middleware.clj @@ -0,0 +1,10 @@ +(ns queue-api.dev-middleware + (:require [ring.middleware.reload :refer [wrap-reload]] + [selmer.middleware :refer [wrap-error-page]] + [prone.middleware :refer [wrap-exceptions]])) + +(defn wrap-dev [handler] + (-> handler + wrap-reload + wrap-error-page + wrap-exceptions)) diff --git a/env/dev/clj/queue_api/env.clj b/env/dev/clj/queue_api/env.clj new file mode 100644 index 0000000..1f31ba5 --- /dev/null +++ b/env/dev/clj/queue_api/env.clj @@ -0,0 +1,14 @@ +(ns queue-api.env + (:require [selmer.parser :as parser] + [clojure.tools.logging :as log] + [queue-api.dev-middleware :refer [wrap-dev]])) + +(def defaults + {:init + (fn [] + (parser/cache-off!) + (log/info "\n-=[queue-api started successfully using the development profile]=-")) + :stop + (fn [] + (log/info "\n-=[queue-api has shut down successfully]=-")) + :middleware wrap-dev}) diff --git a/env/dev/clj/user.clj b/env/dev/clj/user.clj new file mode 100644 index 0000000..843b558 --- /dev/null +++ b/env/dev/clj/user.clj @@ -0,0 +1,16 @@ +(ns user + (:require + [mount.core :as mount] + [queue-api.core :refer [start-app]])) + +(defn start [] + (mount/start-without #'queue-api.core/repl-server)) + +(defn stop [] + (mount/stop-except #'queue-api.core/repl-server)) + +(defn restart [] + (stop) + (start)) + + diff --git a/env/dev/resources/config.edn b/env/dev/resources/config.edn new file mode 100644 index 0000000..6f14c22 --- /dev/null +++ b/env/dev/resources/config.edn @@ -0,0 +1,4 @@ +{:dev true + :port 3000 + ;; when :nrepl-port is set the application starts the nREPL server on load + :nrepl-port 7000} diff --git a/env/dev/resources/logback.xml b/env/dev/resources/logback.xml new file mode 100644 index 0000000..a05ccad --- /dev/null +++ b/env/dev/resources/logback.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration> + <statusListener class="ch.qos.logback.core.status.NopStatusListener" /> + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <!-- encoders are assigned the type + ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --> + <encoder> + <charset>UTF-8</charset> + <pattern>%date{ISO8601} [%thread] %-5level %logger{36} - %msg %n</pattern> + </encoder> + </appender> + <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>log/queue-api.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>log/queue-api.%d{yyyy-MM-dd}.%i.log</fileNamePattern> + <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> + <maxFileSize>100MB</maxFileSize> + </timeBasedFileNamingAndTriggeringPolicy> + <!-- keep 30 days of history --> + <maxHistory>30</maxHistory> + </rollingPolicy> + <encoder> + <charset>UTF-8</charset> + <pattern>%date{ISO8601} [%thread] %-5level %logger{36} - %msg %n</pattern> + </encoder> + </appender> + <logger name="org.apache.http" level="warn" /> + <logger name="org.xnio.nio" level="warn" /> + <logger name="io.undertow.session" level="warn" /> + <logger name="io.undertow.request" level="warn" /> + <root level="DEBUG"> + <appender-ref ref="STDOUT" /> + <appender-ref ref="FILE" /> + </root> +</configuration> diff --git a/env/prod/clj/queue_api/env.clj b/env/prod/clj/queue_api/env.clj new file mode 100644 index 0000000..c05d732 --- /dev/null +++ b/env/prod/clj/queue_api/env.clj @@ -0,0 +1,11 @@ +(ns queue-api.env + (:require [clojure.tools.logging :as log])) + +(def defaults + {:init + (fn [] + (log/info "\n-=[queue-api started successfully]=-")) + :stop + (fn [] + (log/info "\n-=[queue-api has shut down successfully]=-")) + :middleware identity}) diff --git a/env/prod/resources/config.edn b/env/prod/resources/config.edn new file mode 100644 index 0000000..b48cfbd --- /dev/null +++ b/env/prod/resources/config.edn @@ -0,0 +1,2 @@ +{:production true + :port 3000} diff --git a/env/prod/resources/logback.xml b/env/prod/resources/logback.xml new file mode 100644 index 0000000..3829eff --- /dev/null +++ b/env/prod/resources/logback.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration> + <statusListener class="ch.qos.logback.core.status.NopStatusListener" /> + <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>log/queue-api.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>log/queue-api.%d{yyyy-MM-dd}.%i.log</fileNamePattern> + <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> + <maxFileSize>100MB</maxFileSize> + </timeBasedFileNamingAndTriggeringPolicy> + <!-- keep 30 days of history --> + <maxHistory>30</maxHistory> + </rollingPolicy> + <encoder> + <charset>UTF-8</charset> + <pattern>%date{ISO8601} [%thread] %-5level %logger{36} - %msg %n</pattern> + </encoder> + </appender> + <logger name="org.apache.http" level="warn" /> + <logger name="org.xnio.nio" level="warn" /> + <root level="INFO"> + <appender-ref ref="FILE" /> + </root> +</configuration> diff --git a/env/test/resources/config.edn b/env/test/resources/config.edn new file mode 100644 index 0000000..6f14c22 --- /dev/null +++ b/env/test/resources/config.edn @@ -0,0 +1,4 @@ +{:dev true + :port 3000 + ;; when :nrepl-port is set the application starts the nREPL server on load + :nrepl-port 7000} diff --git a/env/test/resources/logback.xml b/env/test/resources/logback.xml new file mode 100644 index 0000000..a05ccad --- /dev/null +++ b/env/test/resources/logback.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration> + <statusListener class="ch.qos.logback.core.status.NopStatusListener" /> + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <!-- encoders are assigned the type + ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --> + <encoder> + <charset>UTF-8</charset> + <pattern>%date{ISO8601} [%thread] %-5level %logger{36} - %msg %n</pattern> + </encoder> + </appender> + <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>log/queue-api.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>log/queue-api.%d{yyyy-MM-dd}.%i.log</fileNamePattern> + <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> + <maxFileSize>100MB</maxFileSize> + </timeBasedFileNamingAndTriggeringPolicy> + <!-- keep 30 days of history --> + <maxHistory>30</maxHistory> + </rollingPolicy> + <encoder> + <charset>UTF-8</charset> + <pattern>%date{ISO8601} [%thread] %-5level %logger{36} - %msg %n</pattern> + </encoder> + </appender> + <logger name="org.apache.http" level="warn" /> + <logger name="org.xnio.nio" level="warn" /> + <logger name="io.undertow.session" level="warn" /> + <logger name="io.undertow.request" level="warn" /> + <root level="DEBUG"> + <appender-ref ref="STDOUT" /> + <appender-ref ref="FILE" /> + </root> +</configuration> diff --git a/project.clj b/project.clj new file mode 100644 index 0000000..dcc3317 --- /dev/null +++ b/project.clj @@ -0,0 +1,66 @@ +(defproject queue-api "0.1.0-SNAPSHOT" + + :description "FIXME: write description" + :url "http://example.com/FIXME" + + :dependencies [[clj-time "0.14.2"] + [compojure "1.6.0"] + [cprop "0.1.11"] + [funcool/struct "1.2.0"] + [luminus-immutant "0.2.4"] + [luminus-nrepl "0.1.4"] + [luminus/ring-ttl-session "0.3.2"] + [markdown-clj "1.0.2"] + [metosin/compojure-api "1.1.11"] + [metosin/muuntaja "0.5.0"] + [metosin/ring-http-response "0.9.0"] + [mount "0.1.11"] + [org.clojure/clojure "1.9.0"] + [org.clojure/tools.cli "0.3.5"] + [org.clojure/tools.logging "0.4.0"] + [org.webjars.bower/tether "1.4.3"] + [org.webjars/bootstrap "4.0.0"] + [org.webjars/font-awesome "5.0.6"] + [org.webjars/jquery "3.2.1"] + [ring-webjars "0.2.0"] + [ring/ring-core "1.6.3"] + [ring/ring-defaults "0.3.1"] + [selmer "1.11.6"]] + + :min-lein-version "2.0.0" + + :source-paths ["src/clj"] + :test-paths ["test/clj"] + :resource-paths ["resources"] + :target-path "target/%s/" + :main ^:skip-aot queue-api.core + + :plugins [[lein-immutant "2.1.0"] + [lein-kibit "0.1.2"]] + + :profiles + {:uberjar {:omit-source true + :aot :all + :uberjar-name "queue-api.jar" + :source-paths ["env/prod/clj"] + :resource-paths ["env/prod/resources"]} + + :dev [:project/dev :profiles/dev] + :test [:project/dev :project/test :profiles/test] + + :project/dev {:jvm-opts ["-server" "-Dconf=dev-config.edn"] + :dependencies [[pjstadig/humane-test-output "0.8.3"] + [prone "1.5.0"] + [ring/ring-devel "1.6.3"] + [ring/ring-mock "0.3.2"]] + :plugins [[com.jakemccrary/lein-test-refresh "0.19.0"]] + + :source-paths ["env/dev/clj"] + :resource-paths ["env/dev/resources"] + :repl-options {:init-ns user} + :injections [(require 'pjstadig.humane-test-output) + (pjstadig.humane-test-output/activate!)]} + :project/test {:jvm-opts ["-server" "-Dconf=test-config.edn"] + :resource-paths ["env/test/resources"]} + :profiles/dev {} + :profiles/test {}}) diff --git a/resources/public/favicon.ico b/resources/public/favicon.ico Binary files differnew file mode 100644 index 0000000..0e50cb2 --- /dev/null +++ b/resources/public/favicon.ico diff --git a/src/clj/queue_api/config.clj b/src/clj/queue_api/config.clj new file mode 100644 index 0000000..30ed9a5 --- /dev/null +++ b/src/clj/queue_api/config.clj @@ -0,0 +1,12 @@ +(ns queue-api.config + (:require [cprop.core :refer [load-config]] + [cprop.source :as source] + [mount.core :refer [args defstate]])) + +(defstate env + :start + (load-config + :merge + [(args) + (source/from-system-props) + (source/from-env)])) diff --git a/src/clj/queue_api/core.clj b/src/clj/queue_api/core.clj new file mode 100644 index 0000000..1647375 --- /dev/null +++ b/src/clj/queue_api/core.clj @@ -0,0 +1,48 @@ +(ns queue-api.core + (:require [queue-api.handler :as handler] + [luminus.repl-server :as repl] + [luminus.http-server :as http] + [queue-api.config :refer [env]] + [clojure.tools.cli :refer [parse-opts]] + [clojure.tools.logging :as log] + [mount.core :as mount]) + (:gen-class)) + +(def cli-options + [["-p" "--port PORT" "Port number" + :parse-fn #(Integer/parseInt %)]]) + +(mount/defstate ^{:on-reload :noop} http-server + :start + (http/start + (-> env + (assoc :handler #'handler/app) + (update :io-threads #(or % (* 2 (.availableProcessors (Runtime/getRuntime))))) + (update :port #(or (-> env :options :port) %)))) + :stop + (http/stop http-server)) + +(mount/defstate ^{:on-reload :noop} repl-server + :start + (when-let [nrepl-port (env :nrepl-port)] + (repl/start {:port nrepl-port})) + :stop + (when repl-server + (repl/stop repl-server))) + + +(defn stop-app [] + (doseq [component (:stopped (mount/stop))] + (log/info component "stopped")) + (shutdown-agents)) + +(defn start-app [args] + (doseq [component (-> args + (parse-opts cli-options) + mount/start-with-args + :started)] + (log/info component "started")) + (.addShutdownHook (Runtime/getRuntime) (Thread. stop-app))) + +(defn -main [& args] + (start-app args)) diff --git a/src/clj/queue_api/handler.clj b/src/clj/queue_api/handler.clj new file mode 100644 index 0000000..97afd48 --- /dev/null +++ b/src/clj/queue_api/handler.clj @@ -0,0 +1,19 @@ +(ns queue-api.handler + (:require [compojure.core :refer [routes wrap-routes]] + [queue-api.routes.services :refer [service-routes]] + [compojure.route :as route] + [queue-api.env :refer [defaults]] + [mount.core :as mount] + [queue-api.middleware :as middleware])) + +(mount/defstate init-app + :start ((or (:init defaults) identity)) + :stop ((or (:stop defaults) identity))) + +(mount/defstate app + :start + (middleware/wrap-base + (routes + #'service-routes + (route/not-found + "page not found")))) diff --git a/src/clj/queue_api/middleware.clj b/src/clj/queue_api/middleware.clj new file mode 100644 index 0000000..6d1ea43 --- /dev/null +++ b/src/clj/queue_api/middleware.clj @@ -0,0 +1,15 @@ +(ns queue-api.middleware + (:require [queue-api.env :refer [defaults]] + [queue-api.config :refer [env]] + [ring.middleware.flash :refer [wrap-flash]] + [immutant.web.middleware :refer [wrap-session]] + [ring.middleware.defaults :refer [site-defaults wrap-defaults]])) + +(defn wrap-base [handler] + (-> ((:middleware defaults) handler) + wrap-flash + (wrap-session {:cookie-attrs {:http-only true}}) + (wrap-defaults + (-> site-defaults + (assoc-in [:security :anti-forgery] false) + (dissoc :session))))) diff --git a/src/clj/queue_api/routes/services.clj b/src/clj/queue_api/routes/services.clj new file mode 100644 index 0000000..cc8ac04 --- /dev/null +++ b/src/clj/queue_api/routes/services.clj @@ -0,0 +1,44 @@ +(ns queue-api.routes.services + (:require [ring.util.http-response :refer :all] + [compojure.api.sweet :refer :all] + [schema.core :as s])) + +(defapi service-routes + {:swagger {:ui "/swagger-ui" + :spec "/swagger.json" + :data {:info {:version "1.0.0" + :title "Sample API" + :description "Sample Services"}}}} + + (context "/api" [] + :tags ["thingie"] + + (GET "/plus" [] + :return Long + :query-params [x :- Long, {y :- Long 1}] + :summary "x+y with query-parameters. y defaults to 1." + (ok (+ x y))) + + (POST "/minus" [] + :return Long + :body-params [x :- Long, y :- Long] + :summary "x-y with body-parameters." + (ok (- x y))) + + (GET "/times/:x/:y" [] + :return Long + :path-params [x :- Long, y :- Long] + :summary "x*y with path-parameters" + (ok (* x y))) + + (POST "/divide" [] + :return Double + :form-params [x :- Long, y :- Long] + :summary "x/y with form-parameters" + (ok (/ x y))) + + (GET "/power" [] + :return Long + :header-params [x :- Long, y :- Long] + :summary "x^y with header-parameters" + (ok (long (Math/pow x y)))))) diff --git a/test/clj/queue_api/test/handler.clj b/test/clj/queue_api/test/handler.clj new file mode 100644 index 0000000..1aceb3c --- /dev/null +++ b/test/clj/queue_api/test/handler.clj @@ -0,0 +1,21 @@ +(ns queue-api.test.handler + (:require [clojure.test :refer :all] + [ring.mock.request :refer :all] + [queue-api.handler :refer :all] + [mount.core :as mount])) + +(use-fixtures + :once + (fn [f] + (mount/start #'queue-api.config/env + #'queue-api.handler/app) + (f))) + +(deftest test-app + (testing "main route" + (let [response (app (request :get "/"))] + (is (= 200 (:status response))))) + + (testing "not-found route" + (let [response (app (request :get "/invalid"))] + (is (= 404 (:status response)))))) |