Add example for Reitit + Pedestal + Malli coercion

This commit is contained in:
Ian Fernandez 2022-12-04 00:07:05 +00:00
parent e84495585c
commit eebc2a3df0
3 changed files with 184 additions and 0 deletions

View file

@ -0,0 +1,11 @@
/target
/classes
/checkouts
pom.xml
pom.xml.asc
*.jar
*.class
/.lein-*
/.nrepl-port
.hgignore
.hg/

View file

@ -0,0 +1,9 @@
(defproject pedestal-malli-swagger-example "0.1.0-SNAPSHOT"
:description "Reitit-http with pedestal"
:dependencies [[org.clojure/clojure "1.10.0"]
[io.pedestal/pedestal.service "0.5.5"]
[io.pedestal/pedestal.jetty "0.5.5"]
[metosin/reitit-malli "0.5.18"]
[metosin/reitit-pedestal "0.5.18"]
[metosin/reitit "0.5.18"]]
:repl-options {:init-ns example.server})

View file

@ -0,0 +1,164 @@
(ns example.server
(:require [clojure.java.io :as io]
[io.pedestal.http.route]
[reitit.interceptor]
[reitit.dev.pretty :as pretty]
[reitit.coercion.malli]
[io.pedestal.http]
[reitit.ring]
[reitit.ring.malli]
[reitit.http]
[reitit.pedestal]
[reitit.swagger :as swagger]
[reitit.swagger-ui :as swagger-ui]
[reitit.http.coercion :as coercion]
[reitit.http.interceptors.parameters :as parameters]
[reitit.http.interceptors.muuntaja :as muuntaja]
[reitit.http.interceptors.multipart :as multipart]
[muuntaja.core]
[malli.util :as mu]))
(defn reitit-routes
[_config]
[["/swagger.json" {:get {:no-doc true
:swagger {:info {:title "my-api"
:description "with [malli](https://github.com/metosin/malli) and reitit-ring"}
:tags [{:name "files",
:description "file api"}
{:name "math",
:description "math api"}]}
:handler (swagger/create-swagger-handler)}}]
["/files" {:swagger {:tags ["files"]}}
["/upload"
{:post {:summary "upload a file"
:parameters {:multipart [:map [:file reitit.ring.malli/temp-file-part]]}
:responses {200 {:body [:map
[:name string?]
[:size int?]]}}
:handler (fn [{{{{:keys [filename
size]} :file}
:multipart}
:parameters}]
{:status 200
:body {:name filename
:size size}})}}]
["/download" {:get {:summary "downloads a file"
:swagger {:produces ["image/png"]}
:handler (fn [_]
{:status 200
:headers {"Content-Type" "image/png"}
:body (-> "reitit.png"
(io/resource)
(io/input-stream))})}}]]
["/math" {:swagger {:tags ["math"]}}
["/plus"
{:get {:summary "plus with malli query parameters"
:parameters {:query [:map
[:x
{:title "X parameter"
:description "Description for X parameter"
:json-schema/default 42}
int?]
[:y int?]]}
:responses {200 {:body [:map [:total int?]]}}
:handler (fn [{{{:keys [x
y]}
:query}
:parameters}]
{:status 200
:body {:total (+ x y)}})}
:post {:summary "plus with malli body parameters"
:parameters {:body [:map
[:x
{:title "X parameter"
:description "Description for X parameter"
:json-schema/default 42}
int?]
[:y int?]]}
:responses {200 {:body [:map [:total int?]]}}
:handler (fn [{{{:keys [x
y]}
:body}
:parameters}]
{:status 200
:body {:total (+ x y)}})}}]]])
(defn reitit-ring-routes
[_config]
[(swagger-ui/create-swagger-ui-handler
{:path "/"
:config {:validatorUrl nil
:operationsSorter "alpha"}})
(reitit.ring/create-resource-handler)
(reitit.ring/create-default-handler)])
(defn reitit-router-config
[_config]
{:exception pretty/exception
:data {:coercion (reitit.coercion.malli/create
{:error-keys #{:coercion
:in
:schema
:value
:errors
:humanized}
:compile mu/closed-schema
:strip-extra-keys true
:default-values true
:options nil})
:muuntaja muuntaja.core/instance
:interceptors [swagger/swagger-feature
(parameters/parameters-interceptor)
(muuntaja/format-negotiate-interceptor)
(muuntaja/format-response-interceptor)
(muuntaja/format-request-interceptor)
(coercion/coerce-response-interceptor)
(coercion/coerce-request-interceptor)
(multipart/multipart-interceptor)]}})
(def config
{:env :dev
:io.pedestal.http/routes []
:io.pedestal.http/type :jetty
:io.pedestal.http/port 3000
:io.pedestal.http/join? false
:io.pedestal.http/secure-headers {:content-security-policy-settings
{:default-src "'self'"
:style-src "'self' 'unsafe-inline'"
:script-src "'self' 'unsafe-inline'"}}
::reitit-routes reitit-routes
::reitit-ring-routes reitit-ring-routes
::reitit-router-config reitit-router-config})
(defn reitit-http-router
[{::keys [reitit-routes
reitit-ring-routes
reitit-router-config]
:as config}]
(reitit.pedestal/routing-interceptor
(reitit.http/router
(reitit-routes config)
(reitit-router-config config))
(->> config
reitit-ring-routes
(apply reitit.ring/routes))))
(defonce server (atom nil))
(defn start
[server
config]
(when @server
(io.pedestal.http/stop @server)
(println "server stopped"))
(-> config
io.pedestal.http/default-interceptors
(reitit.pedestal/replace-last-interceptor (reitit-http-router config))
io.pedestal.http/dev-interceptors
io.pedestal.http/create-server
io.pedestal.http/start
(->> (reset! server)))
(println "server running in port 3000"))
#_(start server config)