Pedestal, use jetty for now (might switch to immutant)

This commit is contained in:
Carolyn Grey Bridgette Knight-Serrano 2019-12-01 17:57:36 -08:00
parent e714a9312f
commit 735dd4a7ea
Signed by: gigavinyl
GPG Key ID: 50858748146544CB
7 changed files with 184 additions and 120 deletions

3
.gitignore vendored
View File

@ -1,3 +1,4 @@
config.edn
target
.nrepl-history
.nrepl-history
TAGS

View File

@ -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)))

BIN
resources/reitit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 KiB

View File

@ -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))

View File

@ -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))

View File

@ -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})

View File

@ -1,4 +0,0 @@
(ns redblackrose.core)
(defn -main [& args]
(println "I don't do much yet."))