mirror of
https://github.com/metosin/reitit.git
synced 2025-12-16 16:01:11 +00:00
use ring for serving resources.
This commit is contained in:
parent
fc0b634865
commit
f8a43f0996
7 changed files with 104 additions and 145 deletions
|
|
@ -25,6 +25,12 @@
|
|||
* new helper `reitit.ring/router` to compose routes outside of a router.
|
||||
* `reitit.ring/create-resource-handler` function to serve static routes. See (docs)[https://metosin.github.io/reitit/ring/static.html].
|
||||
|
||||
* new dependencies:
|
||||
|
||||
```clj
|
||||
[ring/ring-core "1.6.3"]
|
||||
```
|
||||
|
||||
### `reitit-swagger`
|
||||
|
||||
* New module to produce swagger-docs from routing tree, including `Coercion` definitions. Works with both middleware & interceptors and Schema & Spec. See [docs](https://metosin.github.io/reitit/swagger.html).
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ There are two options to serve the files.
|
|||
|
||||
This is good option if static files can be from non-conflicting paths, e.g. `"/assets/*"`.
|
||||
|
||||
|
||||
```clj
|
||||
(require '[reitit.ring :as ring])
|
||||
|
||||
|
|
@ -50,13 +49,16 @@ To serve files from conflicting paths, e.g. `"/*"`, one option is to mount them
|
|||
|
||||
`reitit.ring/create-resource-handler` takes optionally an options map to configure how the files are being served.
|
||||
|
||||
| key | description |
|
||||
| -------------|-------------|
|
||||
| :parameter | optional name of the wildcard parameter, defaults to unnamed keyword `:`
|
||||
| :root | optional resource root, defaults to `"public"`
|
||||
| :mime-types | optional extension->mime-type mapping, defaults to `reitit.ring.mime/default-types`
|
||||
| :path | optional path to mount the handler to. Works only if mounted outside of a router.
|
||||
| key | description |
|
||||
| -----------------|-------------|
|
||||
| :parameter | optional name of the wildcard parameter, defaults to unnamed keyword `:`
|
||||
| :root | optional resource root, defaults to `"public"`
|
||||
| :path | optional path to mount the handler to. Works only if mounted outside of a router.
|
||||
| :loader | optional class loader to resolve the resources
|
||||
| :allow-symlinks? | allow symlinks that lead to paths outside the root classpath directories, defaults to `false`
|
||||
|
||||
### TODO
|
||||
|
||||
* support for things like `:cache`, `:last-modified?`, `:index-files` and `:gzip`
|
||||
* support for ClojureScript
|
||||
* serve from file-system
|
||||
|
|
|
|||
|
|
@ -6,4 +6,5 @@
|
|||
:plugins [[lein-parent "0.3.2"]]
|
||||
:parent-project {:path "../../project.clj"
|
||||
:inherit [:deploy-repositories :managed-dependencies]}
|
||||
:dependencies [[metosin/reitit-core]])
|
||||
:dependencies [[metosin/reitit-core]
|
||||
[ring/ring-core]])
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
(ns reitit.ring
|
||||
(:require [meta-merge.core :refer [meta-merge]]
|
||||
[reitit.middleware :as middleware]
|
||||
[reitit.ring.mime :as mime]
|
||||
[reitit.core :as r]
|
||||
[reitit.impl :as impl]
|
||||
#?(:clj
|
||||
[clojure.java.io :as io])))
|
||||
#?@(:clj [
|
||||
[ring.util.mime-type :as mime-type]
|
||||
[ring.util.response :as response]])))
|
||||
|
||||
(def http-methods #{:get :head :post :put :delete :connect :options :trace :patch})
|
||||
(defrecord Methods [get head post put delete connect options trace patch])
|
||||
|
|
@ -71,42 +71,36 @@
|
|||
(defn create-resource-handler
|
||||
"A ring handler for serving classpath resources, configured via options:
|
||||
|
||||
| key | description |
|
||||
| key | description |
|
||||
| -----------------|-------------|
|
||||
| :parameter | optional name of the wildcard parameter, defaults to unnamed keyword `:`
|
||||
| :root | optional resource root, defaults to `\"public\"`
|
||||
| :mime-types | optional extension->mime-type mapping, defaults to `reitit.ring.mime/default-types`
|
||||
| :parameter | optional name of the wildcard parameter, defaults to unnamed keyword `:`
|
||||
| :root | optional resource root, defaults to `\"public\"`
|
||||
| :path | optional path to mount the handler to. Works only if mounted outside of a router.
|
||||
| :loader | optional class loader to resolve the resources
|
||||
| :allow-symlinks? | allow symlinks that lead to paths outside the root classpath directories, defaults to `false`"
|
||||
([]
|
||||
(create-resource-handler nil))
|
||||
([{:keys [parameter root mime-types path loader allow-symlinks?]
|
||||
([{:keys [parameter root path loader allow-symlinks?]
|
||||
:or {parameter (keyword "")
|
||||
root "public"
|
||||
mime-types mime/default-mime-types}}]
|
||||
(let [response (fn [file]
|
||||
{:status 200
|
||||
:body file
|
||||
:headers {"Content-Type" (mime/ext-mime-type (.getName file) mime-types)}})]
|
||||
(if path
|
||||
(let [path-size (count path)
|
||||
serve (fn [req]
|
||||
(let [uri (:uri req)]
|
||||
(if (and (>= (count uri) path-size))
|
||||
(some->> (str root (subs uri path-size)) io/resource io/file response))))]
|
||||
(fn
|
||||
([req]
|
||||
(serve req))
|
||||
([req respond _]
|
||||
(respond (serve req)))))
|
||||
(let [serve (fn [req]
|
||||
(or (some->> req :path-params parameter (str root "/") io/resource io/file response)
|
||||
{:status 404}))]
|
||||
(fn ([req]
|
||||
(serve req))
|
||||
([req respond _]
|
||||
(respond (serve req))))))))))
|
||||
root "public"}}]
|
||||
(let [options {:root root, :loader loader, :allow-symlinks? allow-symlinks?}
|
||||
path-size (count path)
|
||||
create (fn [handler]
|
||||
(fn
|
||||
([request] (handler request))
|
||||
([request respond _] (respond (handler request)))))
|
||||
response (fn [path]
|
||||
(if-let [response (response/resource-response path options)]
|
||||
(response/content-type response (mime-type/ext-mime-type path))))
|
||||
handler (if path
|
||||
(fn [request]
|
||||
(let [uri (:uri request)]
|
||||
(if (>= (count uri) path-size)
|
||||
(response (subs uri path-size)))))
|
||||
(fn [request]
|
||||
(let [path (-> request :path-params parameter)]
|
||||
(or (response path) {:status 404}))))]
|
||||
(create handler)))))
|
||||
|
||||
(defn ring-handler
|
||||
"Creates a ring-handler out of a ring-router.
|
||||
|
|
|
|||
|
|
@ -1,99 +0,0 @@
|
|||
(ns reitit.ring.mime
|
||||
(:require [clojure.string :as str]))
|
||||
|
||||
(def default-mime-types
|
||||
"A map of file extensions to mime-types."
|
||||
{"7z" "application/x-7z-compressed"
|
||||
"aac" "audio/aac"
|
||||
"ai" "application/postscript"
|
||||
"appcache" "text/cache-manifest"
|
||||
"asc" "text/plain"
|
||||
"atom" "application/atom+xml"
|
||||
"avi" "video/x-msvideo"
|
||||
"bin" "application/octet-stream"
|
||||
"bmp" "image/bmp"
|
||||
"bz2" "application/x-bzip"
|
||||
"class" "application/octet-stream"
|
||||
"cer" "application/pkix-cert"
|
||||
"crl" "application/pkix-crl"
|
||||
"crt" "application/x-x509-ca-cert"
|
||||
"css" "text/css"
|
||||
"csv" "text/csv"
|
||||
"deb" "application/x-deb"
|
||||
"dart" "application/dart"
|
||||
"dll" "application/octet-stream"
|
||||
"dmg" "application/octet-stream"
|
||||
"dms" "application/octet-stream"
|
||||
"doc" "application/msword"
|
||||
"dvi" "application/x-dvi"
|
||||
"edn" "application/edn"
|
||||
"eot" "application/vnd.ms-fontobject"
|
||||
"eps" "application/postscript"
|
||||
"etx" "text/x-setext"
|
||||
"exe" "application/octet-stream"
|
||||
"flv" "video/x-flv"
|
||||
"flac" "audio/flac"
|
||||
"gif" "image/gif"
|
||||
"gz" "application/gzip"
|
||||
"htm" "text/html"
|
||||
"html" "text/html"
|
||||
"ico" "image/x-icon"
|
||||
"iso" "application/x-iso9660-image"
|
||||
"jar" "application/java-archive"
|
||||
"jpe" "image/jpeg"
|
||||
"jpeg" "image/jpeg"
|
||||
"jpg" "image/jpeg"
|
||||
"js" "text/javascript"
|
||||
"json" "application/json"
|
||||
"lha" "application/octet-stream"
|
||||
"lzh" "application/octet-stream"
|
||||
"mov" "video/quicktime"
|
||||
"m4v" "video/mp4"
|
||||
"mp3" "audio/mpeg"
|
||||
"mp4" "video/mp4"
|
||||
"mpe" "video/mpeg"
|
||||
"mpeg" "video/mpeg"
|
||||
"mpg" "video/mpeg"
|
||||
"oga" "audio/ogg"
|
||||
"ogg" "audio/ogg"
|
||||
"ogv" "video/ogg"
|
||||
"pbm" "image/x-portable-bitmap"
|
||||
"pdf" "application/pdf"
|
||||
"pgm" "image/x-portable-graymap"
|
||||
"png" "image/png"
|
||||
"pnm" "image/x-portable-anymap"
|
||||
"ppm" "image/x-portable-pixmap"
|
||||
"ppt" "application/vnd.ms-powerpoint"
|
||||
"ps" "application/postscript"
|
||||
"qt" "video/quicktime"
|
||||
"rar" "application/x-rar-compressed"
|
||||
"ras" "image/x-cmu-raster"
|
||||
"rb" "text/plain"
|
||||
"rd" "text/plain"
|
||||
"rss" "application/rss+xml"
|
||||
"rtf" "application/rtf"
|
||||
"sgm" "text/sgml"
|
||||
"sgml" "text/sgml"
|
||||
"svg" "image/svg+xml"
|
||||
"swf" "application/x-shockwave-flash"
|
||||
"tar" "application/x-tar"
|
||||
"tif" "image/tiff"
|
||||
"tiff" "image/tiff"
|
||||
"ttf" "application/x-font-ttf"
|
||||
"txt" "text/plain"
|
||||
"webm" "video/webm"
|
||||
"wmv" "video/x-ms-wmv"
|
||||
"woff" "application/font-woff"
|
||||
"xbm" "image/x-xbitmap"
|
||||
"xls" "application/vnd.ms-excel"
|
||||
"xml" "text/xml"
|
||||
"xpm" "image/x-xpixmap"
|
||||
"xwd" "image/x-xwindowdump"
|
||||
"zip" "application/zip"})
|
||||
|
||||
(defn file-ext [name]
|
||||
(if-let [i (str/last-index-of name ".")]
|
||||
(subs name (inc i))))
|
||||
|
||||
(defn ext-mime-type [name mime-types]
|
||||
(-> name file-ext mime-types))
|
||||
|
|
@ -4,7 +4,10 @@
|
|||
[reitit.ring :as ring]
|
||||
[clojure.java.io :as io]
|
||||
[criterium.core :as cc]
|
||||
[ring.util.mime-type :as mime]))
|
||||
[ring.util.response]
|
||||
[ring.middleware.defaults]
|
||||
[ring.middleware.resource]
|
||||
[ring.util.mime-type]))
|
||||
|
||||
;;
|
||||
;; start repl with `lein perf repl`
|
||||
|
|
@ -21,14 +24,14 @@
|
|||
;; Memory: 16 GB
|
||||
;;
|
||||
|
||||
(def app
|
||||
(def app1
|
||||
(ring/ring-handler
|
||||
(ring/router
|
||||
[["/ping" (constantly {:status 200, :body "pong"})]
|
||||
["/files/*" (ring/create-resource-handler)]])
|
||||
(ring/create-default-handler)))
|
||||
|
||||
(def app
|
||||
(def app2
|
||||
(ring/ring-handler
|
||||
(ring/router
|
||||
["/ping" (constantly {:status 200, :body "pong"})])
|
||||
|
|
@ -36,19 +39,69 @@
|
|||
(ring/create-resource-handler {:path "/files"})
|
||||
(ring/create-default-handler))))
|
||||
|
||||
(def wrap-resource
|
||||
(-> (constantly {:status 200, :body "pong"})
|
||||
(ring.middleware.resource/wrap-resource "public")))
|
||||
|
||||
(def wrap-defaults
|
||||
(-> (constantly {:status 200, :body "pong"})
|
||||
(ring.middleware.defaults/wrap-defaults ring.middleware.defaults/site-defaults)))
|
||||
|
||||
(comment
|
||||
(def server (web/run #'app {:port 3000, :dispatch? false, :server {:always-set-keep-alive false}}))
|
||||
(routing-test))
|
||||
|
||||
(defn bench-resources []
|
||||
|
||||
;; 134µs
|
||||
(cc/quick-bench
|
||||
(ring.util.response/resource-response "hello.json" {:root "public"}))
|
||||
|
||||
;; 144µs
|
||||
(cc/quick-bench
|
||||
(app1 {:request-method :get, :uri "/files/hello.json"}))
|
||||
|
||||
;; 144µs
|
||||
(cc/quick-bench
|
||||
(app2 {:request-method :get, :uri "/files/hello.json"}))
|
||||
|
||||
;; 143µs
|
||||
(cc/quick-bench
|
||||
(wrap-resource {:request-method :get, :uri "/hello.json"}))
|
||||
|
||||
;; 163µs
|
||||
(cc/quick-bench
|
||||
(wrap-defaults {:request-method :get, :uri "/hello.json"})))
|
||||
|
||||
(defn bench-handler []
|
||||
|
||||
;; 140ns
|
||||
(cc/quick-bench
|
||||
(app1 {:request-method :get, :uri "/ping"}))
|
||||
|
||||
;; 134ns
|
||||
(cc/quick-bench
|
||||
(app2 {:request-method :get, :uri "/ping"}))
|
||||
|
||||
;; 108µs
|
||||
(cc/quick-bench
|
||||
(wrap-resource {:request-method :get, :uri "/ping"}))
|
||||
|
||||
;; 146µs
|
||||
(cc/quick-bench
|
||||
(wrap-defaults {:request-method :get, :uri "/ping"})))
|
||||
|
||||
(comment
|
||||
(bench-resources)
|
||||
(bench-handler)
|
||||
|
||||
(let [file (-> "logback.xml" io/resource io/file)
|
||||
name (.getName file)]
|
||||
|
||||
;; 639ns
|
||||
(cc/quick-bench
|
||||
(mime/ext-mime-type name))
|
||||
|
||||
(ring.util.mime-type/ext-mime-type name))
|
||||
|
||||
;; 106ns
|
||||
(cc/quick-bench
|
||||
(ext-mime-type name))))
|
||||
(reitit.ring.mime/ext-mime-type name reitit.ring.mime/default-mime-types))))
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
[metosin/reitit-swagger "0.1.1-SNAPSHOT"]
|
||||
|
||||
[meta-merge "1.0.0"]
|
||||
[ring/ring-core "1.6.3"]
|
||||
[metosin/spec-tools "0.6.2-SNAPSHOT"]
|
||||
[metosin/schema-tools "0.10.2-SNAPSHOT"]]
|
||||
|
||||
|
|
@ -60,6 +61,7 @@
|
|||
"-Dclojure.compiler.direct-linking=true"]
|
||||
:test-paths ["perf-test/clj"]
|
||||
:dependencies [[compojure "1.6.1"]
|
||||
[ring/ring-defaults "0.3.1"]
|
||||
[ikitommi/immutant-web "3.0.0-alpha1"]
|
||||
[io.pedestal/pedestal.route "0.5.3"]
|
||||
[org.clojure/core.async "0.4.474"]
|
||||
|
|
|
|||
Loading…
Reference in a new issue