Pedestal, use jetty for now (might switch to immutant)
This commit is contained in:
parent
e714a9312f
commit
735dd4a7ea
|
@ -1,3 +1,4 @@
|
|||
config.edn
|
||||
target
|
||||
.nrepl-history
|
||||
.nrepl-history
|
||||
TAGS
|
||||
|
|
47
build.boot
47
build.boot
|
@ -1,21 +1,60 @@
|
|||
(set-env!
|
||||
:source-paths #{"src"}
|
||||
:source-paths #{"src/clj" "src/cljc"}
|
||||
:resource-paths #{"resources"}
|
||||
:dependencies '[[org.clojure/clojure "1.10.1"]])
|
||||
:dependencies '[[org.clojure/clojure "1.10.1"]
|
||||
[org.clojure/spec.alpha "0.2.176"]
|
||||
[org.clojure/core.typed "0.6.0"]
|
||||
[io.pedestal/pedestal.service "0.5.7"]
|
||||
[io.pedestal/pedestal.service-tools "0.5.7"]
|
||||
[io.pedestal/pedestal.immutant "0.5.7"]
|
||||
[io.pedestal/pedestal.jetty "0.5.7"]
|
||||
[manifold "0.1.8"]
|
||||
[tolitius/boot-check "0.1.12"]
|
||||
[cprop "0.1.14"]
|
||||
[metosin/muuntaja "0.6.6"]
|
||||
[com.fasterxml.jackson.core/jackson-databind "2.10.0"]
|
||||
[com.fasterxml.jackson.core/jackson-annotations "2.10.0"]
|
||||
[com.fasterxml.jackson.core/jackson-core "2.10.0"]
|
||||
[metosin/jsonista "0.2.5"]
|
||||
[javax.servlet/servlet-api "2.5"]
|
||||
[domino/core "0.3.0"]
|
||||
[samestep/boot-refresh "0.1.0" :scope "test"]
|
||||
[metosin/reitit "0.3.10"]
|
||||
[metosin/reitit-pedestal "0.3.10"]])
|
||||
|
||||
(def version "0.1.0-SNAPSHOT")
|
||||
(task-options! pom {:project 'redblackrose
|
||||
:version (str version "-standalone")
|
||||
:description "FIXME: write description"
|
||||
:license {"Eclipse Public License" "http://www.eclipse.org/legal/epl-v10.html"}})
|
||||
:license {"Eclipse Public License" "http://www.eclipse.org/legal/epl-v10.html"}}
|
||||
jar {:main 'redblackrose.core}
|
||||
aot {:all true})
|
||||
|
||||
(require '[tolitius.boot-check :as check])
|
||||
(require '[samestep.boot-refresh :refer [refresh]])
|
||||
|
||||
;; == Cider Support =======================================
|
||||
|
||||
(require 'boot.repl)
|
||||
(swap! boot.repl/*default-dependencies*
|
||||
concat '[[cider/cider-nrepl "0.10.0-snapshot"]])
|
||||
concat '[[cider/cider-nrepl "LATEST"]])
|
||||
|
||||
(swap! boot.repl/*default-middleware*
|
||||
conj 'cider.nrepl/cider-middleware)
|
||||
|
||||
;; -- My Tasks --------------------------------------------
|
||||
(deftask check-sources []
|
||||
(set-env! :source-paths #{"src/clj" "src/cljc" "test"}
|
||||
(comp
|
||||
(check/with-yagni)
|
||||
(check/with-eastwood)
|
||||
(check/with-kibit)
|
||||
(check/with-bikeshed))))
|
||||
|
||||
|
||||
(deftask build
|
||||
"Build an uberjar of the project."
|
||||
[]
|
||||
(check-sources)
|
||||
(comp (aot) (pom) (uber) (jar) (target)))
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 494 KiB |
|
@ -1,63 +0,0 @@
|
|||
(ns redblackrose.core
|
||||
(:require [schema.core :as s]
|
||||
[yada.yada :as yada]
|
||||
[taoensso.timbre :as timbre]))
|
||||
|
||||
(timbre/set-config! {:level :info})
|
||||
|
||||
(def server (atom nil))
|
||||
|
||||
(defn widget-resource
|
||||
[initial-value]
|
||||
"simple modifiable widget. look at yada.resources.atom-resource for ways to add
|
||||
last-modified headers and the like"
|
||||
(let [value (atom initial-value)]
|
||||
(yada/resource
|
||||
{:methods {:get {:produces "application/json"
|
||||
:response (fn [ctx] @value)}
|
||||
:post {:parameters {:body {:sprockets s/Num
|
||||
:reaction s/Str
|
||||
(s/optional-key :extras) s/Any}}
|
||||
:consumes "application/json"
|
||||
:response (fn [ctx]
|
||||
(let [body (get-in ctx [:parameters :body])]
|
||||
(reset! value body)))}}})))
|
||||
|
||||
(defn routes
|
||||
[]
|
||||
["/"
|
||||
{"hello" (yada/as-resource "hello from redblackrose")
|
||||
"json" (yada/as-resource {:message "yo! from redblackrose"})
|
||||
"modifiable-string" (yada/as-resource (atom "original value"))
|
||||
"widget" (widget-resource {:sprockets 3
|
||||
:reaction "wow"})
|
||||
"die" (yada/as-resource (fn []
|
||||
(future (Thread/sleep 100) (@server))
|
||||
"shutting down in 100ms..."))}])
|
||||
(defn run
|
||||
"Returns promise to capture lifecycle of server"
|
||||
[]
|
||||
(let [listener (yada/listener (routes) {:port 3000})
|
||||
done (promise)]
|
||||
(reset! server (fn []
|
||||
((:close listener))
|
||||
(deliver done :done)))
|
||||
done))
|
||||
|
||||
(defn -main
|
||||
[& args]
|
||||
(let [done (run)]
|
||||
(println "server running on port 3000... GET \"http://localhost:3000/die\" to kill")
|
||||
@done))
|
||||
|
||||
(comment
|
||||
"to run in a repl, eval this:"
|
||||
(def server-promise (run))
|
||||
"then either wait on the promise:"
|
||||
@server-promise
|
||||
"or with a timeout"
|
||||
(deref server-promise 1000 :timeout)
|
||||
"or close it yourself"
|
||||
(@server))
|
||||
|
||||
|
|
@ -1,32 +1,143 @@
|
|||
(ns redblackrose.core
|
||||
(:require [clojure.spec.alpha :as s]
|
||||
[io.pedestal.http :as http]
|
||||
[redblackrose.service :as service])
|
||||
(:gen-class))
|
||||
(:gen-class)
|
||||
(:require [io.pedestal.http :as server]
|
||||
[reitit.ring :as ring]
|
||||
[reitit.http :as http]
|
||||
[reitit.coercion.spec]
|
||||
[reitit.swagger :as swagger]
|
||||
[reitit.swagger-ui :as swagger-ui]
|
||||
[reitit.http.coercion :as coercion]
|
||||
[reitit.dev.pretty :as pretty]
|
||||
[reitit.http.interceptors.parameters :as parameters]
|
||||
[reitit.http.interceptors.muuntaja :as muuntaja]
|
||||
[reitit.http.interceptors.exception :as exception]
|
||||
[reitit.http.interceptors.multipart :as multipart]
|
||||
[reitit.http.interceptors.dev :as dev]
|
||||
[reitit.http.spec :as spec]
|
||||
[spec-tools.spell :as spell]
|
||||
[io.pedestal.http :as server]
|
||||
[reitit.pedestal :as pedestal]
|
||||
[clojure.core.async :as a]
|
||||
[clojure.java.io :as io]
|
||||
[muuntaja.core :as m]))
|
||||
|
||||
(defonce runnable-service (http/create-server service/service))
|
||||
(defn interceptor [number]
|
||||
{:enter (fn [ctx] (a/go (update-in ctx [:request :number] (fnil + 0) number)))})
|
||||
|
||||
(defn run-dev
|
||||
"The entry-point for 'lein run-dev'"
|
||||
[& args]
|
||||
(println "\nCreating your [DEV] server...")
|
||||
(-> service/service ;; start with production configuration
|
||||
(merge {:env :dev
|
||||
;; do not block thread that starts web server
|
||||
::http/join? false
|
||||
;; Routes can be a function that resolve routes,
|
||||
;; we can use this to set the routes to be reloadable
|
||||
::http/routes #(deref #'service/routes)
|
||||
;; all origins are allowed in dev mode
|
||||
::http/allowed-origins {:creds true :allowed-origins (constantly true)}})
|
||||
;; Wire up interceptor chains
|
||||
http/default-interceptors
|
||||
http/dev-interceptors
|
||||
http/create-server
|
||||
http/start))
|
||||
(def router
|
||||
(pedestal/routing-interceptor
|
||||
(http/router
|
||||
[["/swagger.json"
|
||||
{:get {:no-doc true
|
||||
:swagger {:info {:title "my-api"
|
||||
:description "with pedestal & reitit-http"}}
|
||||
:handler (swagger/create-swagger-handler)}}]
|
||||
|
||||
(defn -main
|
||||
"The entry-point for 'boot run'"
|
||||
[& args]
|
||||
(println "\nCreating your server...")
|
||||
(http/start runnable-service))
|
||||
["/interceptors"
|
||||
{:swagger {:tags ["interceptors"]}
|
||||
:interceptors [(interceptor 1)]}
|
||||
|
||||
["/number"
|
||||
{:interceptors [(interceptor 10)]
|
||||
:get {:interceptors [(interceptor 100)]
|
||||
:handler (fn [req]
|
||||
{:status 200
|
||||
:body (select-keys req [:number])})}}]]
|
||||
|
||||
["/files"
|
||||
{:swagger {:tags ["files"]}}
|
||||
|
||||
["/upload"
|
||||
{:post {:summary "upload a file"
|
||||
:parameters {:multipart {:file multipart/temp-file-part}}
|
||||
:responses {200 {:body {:name string?, :size int?}}}
|
||||
:handler (fn [{{{:keys [file]} :multipart} :parameters}]
|
||||
{:status 200
|
||||
:body {:name (:filename file)
|
||||
:size (:size file)}})}}]
|
||||
|
||||
["/download"
|
||||
{:get {:summary "downloads a file"
|
||||
:swagger {:produces ["image/png"]}
|
||||
:handler (fn [_]
|
||||
{:status 200
|
||||
:headers {"Content-Type" "image/png"}
|
||||
:body (io/input-stream
|
||||
(io/resource "reitit.png"))})}}]]
|
||||
|
||||
["/math"
|
||||
{:swagger {:tags ["math"]}}
|
||||
|
||||
["/plus"
|
||||
{:get {:summary "plus with spec query parameters"
|
||||
:parameters {:query {:x int?, :y int?}}
|
||||
:responses {200 {:body {:total int?}}}
|
||||
:handler (fn [{{{:keys [x y]} :query} :parameters}]
|
||||
{:status 200
|
||||
:body {:total (+ x y)}})}
|
||||
:post {:summary "plus with spec body parameters"
|
||||
:parameters {:body {:x int?, :y int?}}
|
||||
:responses {200 {:body {:total int?}}}
|
||||
:handler (fn [{{{:keys [x y]} :body} :parameters}]
|
||||
{:status 200
|
||||
:body {:total (+ x y)}})}}]]]
|
||||
|
||||
{:reitit.interceptor/transform dev/print-context-diffs ;; pretty context diffs
|
||||
:validate spec/validate ;; enable spec validation for route data
|
||||
:reitit.spec/wrap spell/closed ;; strict top-level validation
|
||||
:exception pretty/exception
|
||||
:data {:coercion reitit.coercion.spec/coercion
|
||||
:muuntaja m/instance
|
||||
:interceptors [;; swagger feature
|
||||
swagger/swagger-feature
|
||||
;; query-params & form-params
|
||||
(parameters/parameters-interceptor)
|
||||
;; content-negotiation
|
||||
(muuntaja/format-negotiate-interceptor)
|
||||
;; encoding response body
|
||||
(muuntaja/format-response-interceptor)
|
||||
;; exception handling
|
||||
(exception/exception-interceptor)
|
||||
;; decoding request body
|
||||
(muuntaja/format-request-interceptor)
|
||||
;; coercing response bodys
|
||||
(coercion/coerce-response-interceptor)
|
||||
;; coercing request parameters
|
||||
(coercion/coerce-request-interceptor)
|
||||
;; multipart
|
||||
(multipart/multipart-interceptor)]}})
|
||||
|
||||
;; optional default ring handler (if no routes have matched)
|
||||
(ring/routes
|
||||
(swagger-ui/create-swagger-ui-handler
|
||||
{:path "/"
|
||||
:config {:validatorUrl nil
|
||||
:operationsSorter "alpha"}})
|
||||
(ring/create-resource-handler)
|
||||
(ring/create-default-handler))))
|
||||
|
||||
(defn start []
|
||||
(-> {:env :dev
|
||||
::server/type :jetty
|
||||
::server/port 3000
|
||||
::server/join? false
|
||||
;; no pedestal routes
|
||||
::server/routes []
|
||||
;; allow serving the swagger-ui styles & scripts from self
|
||||
::server/secure-headers {:content-security-policy-settings
|
||||
{:default-src "'self'"
|
||||
:style-src "'self' 'unsafe-inline'"
|
||||
:script-src "'self' 'unsafe-inline'"}}}
|
||||
(server/default-interceptors)
|
||||
;; use the reitit router
|
||||
(pedestal/replace-last-interceptor router)
|
||||
(server/dev-interceptors)
|
||||
(server/create-server)
|
||||
(server/start))
|
||||
(println "server running in port 3000"))
|
||||
|
||||
(comment
|
||||
(start))
|
||||
|
||||
(defn -main [& args]
|
||||
(start))
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
(ns redblackrose.service
|
||||
(:require [io.pedestal.http :as http]
|
||||
[io.pedestal.http.route :as route]
|
||||
[io.pedestal.http.body-params :as body-params]
|
||||
[io.pedestal.http.route.definition :refer [defroutes]]))
|
||||
|
||||
(defn hello-world
|
||||
[request]
|
||||
(let [name (get-in request [:params :name] "World")]
|
||||
{:status 200 :body (str "Hello " name "!\n")}))
|
||||
|
||||
(defroutes routes
|
||||
[[["/"
|
||||
["/hello" {:get hello-world}]]]])
|
||||
|
||||
(def service {:env :prod
|
||||
::http/routes routes
|
||||
::http/resource-path "/public"
|
||||
::http/type :immutant
|
||||
::http/port 8080})
|
|
@ -1,4 +0,0 @@
|
|||
(ns redblackrose.core)
|
||||
|
||||
(defn -main [& args]
|
||||
(println "I don't do much yet."))
|
Loading…
Reference in New Issue