diff --git a/CHANGELOG.md b/CHANGELOG.md index 50761e5b..84f579e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 0.1.1-SNAPSHOT +## 0.1.1 (2018-5-20) ### `reitit-core` @@ -34,7 +34,7 @@ ### `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/ring/swagger.html). +* 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/ring/swagger.html) and [example project](https://github.com/metosin/reitit/tree/master/examples/ring-swagger). ### `reitit-swagger-ui` diff --git a/README.md b/README.md index 35bae12b..bdb9e2e2 100644 --- a/README.md +++ b/README.md @@ -36,18 +36,18 @@ See the [full documentation](https://metosin.github.io/reitit/) for details. All bundled: ```clj -[metosin/reitit "0.1.1-SNAPSHOT"] +[metosin/reitit "0.1.1"] ``` Optionally, the parts can be required separately: ```clj -[metosin/reitit-core "0.1.1-SNAPSHOT"] -[metosin/reitit-ring "0.1.1-SNAPSHOT"] -[metosin/reitit-spec "0.1.1-SNAPSHOT"] -[metosin/reitit-schema "0.1.1-SNAPSHOT"] -[metosin/reitit-swagger "0.1.1-SNAPSHOT"] -[metosin/reitit-swagger-ui "0.1.1-SNAPSHOT"] +[metosin/reitit-core "0.1.1"] +[metosin/reitit-ring "0.1.1"] +[metosin/reitit-spec "0.1.1"] +[metosin/reitit-schema "0.1.1"] +[metosin/reitit-swagger "0.1.1"] +[metosin/reitit-swagger-ui "0.1.1"] ``` ## Quick start @@ -127,10 +127,14 @@ Invalid request: ; :in [:y]}], ; :value {:x "1", :y "a"}, ; :in [:request :query-params]}} - - ``` +**NOTE**: Reitit is not a batteries included web-stack. You should also include at least: +* content negotiation library like [Muuntaja](https://github.com/metosin/muuntaja) +* some default Ring-middleware like `ring.middleware.params/wrap-params` + +See [Ring with Swagger Example](https://github.com/metosin/reitit/tree/master/examples/ring-swagger) for a runnable example. Plan is to have more batteries as separate modules, templates and example projects. Stay tuned. + ## More info [Check out the full documentation!](https://metosin.github.io/reitit/) diff --git a/doc/README.md b/doc/README.md index 6cd36ee0..d4dc0e45 100644 --- a/doc/README.md +++ b/doc/README.md @@ -23,18 +23,18 @@ Modules: To use Reitit, add the following dependecy to your project: ```clj -[metosin/reitit "0.1.1-SNAPSHOT"] +[metosin/reitit "0.1.1"] ``` Optionally, the parts can be required separately: ```clj -[metosin/reitit-core "0.1.1-SNAPSHOT"] -[metosin/reitit-ring "0.1.1-SNAPSHOT"] -[metosin/reitit-spec "0.1.1-SNAPSHOT"] -[metosin/reitit-schema "0.1.1-SNAPSHOT"] -[metosin/reitit-swagger "0.1.1-SNAPSHOT"] -[metosin/reitit-swagger-ui "0.1.1-SNAPSHOT"] +[metosin/reitit-core "0.1.1"] +[metosin/reitit-ring "0.1.1"] +[metosin/reitit-spec "0.1.1"] +[metosin/reitit-schema "0.1.1"] +[metosin/reitit-swagger "0.1.1"] +[metosin/reitit-swagger-ui "0.1.1"] ``` For discussions, there is a [#reitit](https://clojurians.slack.com/messages/reitit/) channel in [Clojurians slack](http://clojurians.net/). diff --git a/doc/cljdoc.edn b/doc/cljdoc.edn index a3db2599..b9d8277a 100644 --- a/doc/cljdoc.edn +++ b/doc/cljdoc.edn @@ -46,4 +46,5 @@ ["Swagger Support" {:file "doc/ring/swagger.md"}]] ["Performance" {:file "doc/performance.md"}] ["Interceptors (WIP)" {:file "doc/interceptors.md"}] + ["Development Instructions" {:file "doc/development.md"}] ["FAQ" {:file "doc/faq.md"}]]} diff --git a/doc/ring/ring.md b/doc/ring/ring.md index f80be622..039b636f 100644 --- a/doc/ring/ring.md +++ b/doc/ring/ring.md @@ -3,7 +3,7 @@ [Ring](https://github.com/ring-clojure/ring) is a Clojure web applications library inspired by Python's WSGI and Ruby's Rack. By abstracting the details of HTTP into a simple, unified API, Ring allows web applications to be constructed of modular components that can be shared among a variety of applications, web servers, and web frameworks. ```clj -[metosin/reitit-ring "0.1.1-SNAPSHOT"] +[metosin/reitit-ring "0.1.1"] ``` Ring-router adds support for [handlers](https://github.com/ring-clojure/ring/wiki/Concepts#handlers), [middleware](https://github.com/ring-clojure/ring/wiki/Concepts#middleware) and routing based on `:request-method`. Ring-router is created with `reitit.ring/router` function. It uses a custom route compiler, creating a optimized data structure for handling route matches, with compiled middleware chain & handlers for all request methods. It also ensures that all routes have a `:handler` defined. `reitit.ring/ring-handler` is used to create a Ring handler out of ring-router. diff --git a/doc/ring/static.md b/doc/ring/static.md index 959b4746..b2570bfd 100644 --- a/doc/ring/static.md +++ b/doc/ring/static.md @@ -55,7 +55,6 @@ A better way to serve files from conflicting paths, e.g. `"/*"`, is to serve the | :path | optional path to mount the handler to. Works only if mounted outside of a router. | :loader | optional class loader to resolve the resources | :index-files | optional vector of index-files to look in a resource directory, defaults to `["index.html"]` -| :allow-symlinks? | allow symlinks that lead to paths outside the root classpath directories, defaults to `false` ### TODO diff --git a/doc/ring/swagger.md b/doc/ring/swagger.md index 64791d53..3d282a65 100644 --- a/doc/ring/swagger.md +++ b/doc/ring/swagger.md @@ -1,7 +1,7 @@ # Swagger Support ``` -[metosin/reitit-swagger "0.1.1-SNAPSHOT"] +[metosin/reitit-swagger "0.1.1"] ``` Reitit supports [Swagger2](https://swagger.io/) documentation, thanks to [schema-tools](https://github.com/metosin/schema-tools) and [spec-tools](https://github.com/metosin/spec-tools). Documentation is extracted from route definitions, coercion `:parameters` and `:responses` and from a set of new documentation keys. @@ -44,7 +44,7 @@ If you need to post-process the generated spec, just wrap the handler with a cus [Swagger-ui](https://github.com/swagger-api/swagger-ui) is a user interface to visualize and interact with the Swagger spesification. To make things easy, there is a pre-integrated version of the swagger-ui as a separate module. ``` -[metosin/reitit-swagger-ui "0.1.1-SNAPSHOT"] +[metosin/reitit-swagger-ui "0.1.1"] ``` `reitit.swagger-ui/create-swagger-ui-hander` can be used to create a ring-handler to serve the swagger-ui. It accepts the following options: diff --git a/examples/just-coercion-with-ring/README.md b/examples/just-coercion-with-ring/README.md index f1da29e8..c1818e3d 100644 --- a/examples/just-coercion-with-ring/README.md +++ b/examples/just-coercion-with-ring/README.md @@ -36,4 +36,4 @@ http://localhost:3000/?x=1&y=20 ## License -Copyright © 2017 Metosin Oy +Copyright © 2017-2018 Metosin Oy diff --git a/examples/just-coercion-with-ring/project.clj b/examples/just-coercion-with-ring/project.clj index d77b03cc..d14fe645 100644 --- a/examples/just-coercion-with-ring/project.clj +++ b/examples/just-coercion-with-ring/project.clj @@ -3,4 +3,4 @@ :dependencies [[org.clojure/clojure "1.9.0"] [ring "1.6.3"] [metosin/muuntaja "0.4.1"] - [metosin/reitit "0.1.1-SNAPSHOT"]]) + [metosin/reitit "0.1.1"]]) diff --git a/examples/ring-example/README.md b/examples/ring-example/README.md index a3811b30..96df02cd 100644 --- a/examples/ring-example/README.md +++ b/examples/ring-example/README.md @@ -30,4 +30,4 @@ http POST :3000/spec/plus x:=1 y:=20 ## License -Copyright © 2017 Metosin Oy +Copyright © 2017-2018 Metosin Oy diff --git a/examples/ring-example/project.clj b/examples/ring-example/project.clj index a4783cf9..332cb4b8 100644 --- a/examples/ring-example/project.clj +++ b/examples/ring-example/project.clj @@ -3,4 +3,4 @@ :dependencies [[org.clojure/clojure "1.9.0"] [ring "1.6.3"] [metosin/muuntaja "0.4.1"] - [metosin/reitit "0.1.1-SNAPSHOT"]]) + [metosin/reitit "0.1.1"]]) diff --git a/examples/ring-swagger/README.md b/examples/ring-swagger/README.md index 79416373..05020421 100644 --- a/examples/ring-swagger/README.md +++ b/examples/ring-swagger/README.md @@ -23,4 +23,4 @@ http GET :3000/api/swagger.json ## License -Copyright © 2017 Metosin Oy +Copyright © 2017-2018 Metosin Oy diff --git a/examples/ring-swagger/project.clj b/examples/ring-swagger/project.clj index f3133c0c..dfe97c89 100644 --- a/examples/ring-swagger/project.clj +++ b/examples/ring-swagger/project.clj @@ -3,5 +3,5 @@ :dependencies [[org.clojure/clojure "1.9.0"] [ring "1.6.3"] [metosin/muuntaja "0.5.0"] - [metosin/reitit "0.1.1-SNAPSHOT"]] + [metosin/reitit "0.1.1"]] :repl-options {:init-ns example.server}) diff --git a/modules/reitit-core/project.clj b/modules/reitit-core/project.clj index b49f1317..23099fba 100644 --- a/modules/reitit-core/project.clj +++ b/modules/reitit-core/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-core "0.1.1-SNAPSHOT" +(defproject metosin/reitit-core "0.1.1" :description "Snappy data-driven router for Clojure(Script)" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-ring/project.clj b/modules/reitit-ring/project.clj index 059df996..71be148e 100644 --- a/modules/reitit-ring/project.clj +++ b/modules/reitit-ring/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-ring "0.1.1-SNAPSHOT" +(defproject metosin/reitit-ring "0.1.1" :description "Reitit: Ring routing" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-ring/src/reitit/ring.cljc b/modules/reitit-ring/src/reitit/ring.cljc index 9d5f830e..020ed15d 100644 --- a/modules/reitit-ring/src/reitit/ring.cljc +++ b/modules/reitit-ring/src/reitit/ring.cljc @@ -5,7 +5,8 @@ [reitit.impl :as impl] #?@(:clj [ [ring.util.mime-type :as mime-type] - [ring.util.response :as response]]))) + [ring.util.response :as response]]) + [clojure.string :as str])) (def http-methods #{:get :head :post :put :delete :connect :options :trace :patch}) (defrecord Methods [get head post put delete connect options trace patch]) @@ -71,6 +72,7 @@ ;; TODO: optimize for perf ;; TODO: ring.middleware.not-modified/wrap-not-modified ;; TODO: ring.middleware.head/wrap-head + ;; TODO: handle etags (defn create-resource-handler "A ring handler for serving classpath resources, configured via options: @@ -80,8 +82,7 @@ | :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 - | :index-files | optional vector of index-files to look in a resource directory, defaults to `[\"index.html\"]` - | :allow-symlinks? | allow symlinks that lead to paths outside the root classpath directories, defaults to `false`" + | :index-files | optional vector of index-files to look in a resource directory, defaults to `[\"index.html\"]`" ([] (create-resource-handler nil)) ([{:keys [parameter root path loader allow-symlinks? index-files paths] @@ -90,30 +91,29 @@ index-files ["index.html"] paths (constantly nil)}}] (let [options {:root root, :loader loader, :allow-symlinks? allow-symlinks?} - path-size (inc (count path)) + path-size (count path) create (fn [handler] (fn ([request] (handler request)) ([request respond _] (respond (handler request))))) - resource-response (fn [path accept] - (if-let [path (accept path)] - (if-let [response (or (paths path) (response/resource-response path options))] - (response/content-type response (mime-type/ext-mime-type path))))) - path-or-index-response (fn [path accept] - (or (resource-response path accept) - (loop [[file & files] index-files] - (if file - (or (resource-response (str path "/" file) accept) - (recur files)))))) + resource-response (fn [path] + (if-let [response (or (paths path) (response/resource-response path options))] + (response/content-type response (mime-type/ext-mime-type path)))) + path-or-index-response (fn [path] + (or (resource-response path) + (let [separator (if-not (str/ends-with? path "/") "/")] + (loop [[file & files] index-files] + (if file + (or (resource-response (str path separator file)) + (recur files))))))) handler (if path (fn [request] (let [uri (:uri request)] - (path-or-index-response uri (fn [path] - (if (>= (count path) path-size) - (subs path path-size)))))) + (if-let [path (if (>= (count uri) path-size) (subs uri path-size))] + (path-or-index-response path)))) (fn [request] (let [path (-> request :path-params parameter)] - (or (path-or-index-response path identity) {:status 404}))))] + (or (path-or-index-response path) {:status 404}))))] (create handler))))) (defn ring-handler diff --git a/modules/reitit-schema/project.clj b/modules/reitit-schema/project.clj index 4327d3de..0663c72b 100644 --- a/modules/reitit-schema/project.clj +++ b/modules/reitit-schema/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-schema "0.1.1-SNAPSHOT" +(defproject metosin/reitit-schema "0.1.1" :description "Reitit: Plumatic Schema coercion" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-spec/project.clj b/modules/reitit-spec/project.clj index 545408e9..f217ae61 100644 --- a/modules/reitit-spec/project.clj +++ b/modules/reitit-spec/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-spec "0.1.1-SNAPSHOT" +(defproject metosin/reitit-spec "0.1.1" :description "Reitit: clojure.spec coercion" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-swagger-ui/project.clj b/modules/reitit-swagger-ui/project.clj index fa43ea9e..5d530067 100644 --- a/modules/reitit-swagger-ui/project.clj +++ b/modules/reitit-swagger-ui/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-swagger-ui "0.1.1-SNAPSHOT" +(defproject metosin/reitit-swagger-ui "0.1.1" :description "Reitit: Swagger-ui support" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-swagger/project.clj b/modules/reitit-swagger/project.clj index 384e6c5f..0339c0cc 100644 --- a/modules/reitit-swagger/project.clj +++ b/modules/reitit-swagger/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-swagger "0.1.1-SNAPSHOT" +(defproject metosin/reitit-swagger "0.1.1" :description "Reitit: Swagger-support" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit/project.clj b/modules/reitit/project.clj index 21b5b664..51aec6d4 100644 --- a/modules/reitit/project.clj +++ b/modules/reitit/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit "0.1.1-SNAPSHOT" +(defproject metosin/reitit "0.1.1" :description "Snappy data-driven router for Clojure(Script)" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/project.clj b/project.clj index abcbc7f6..42fa5ba3 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject metosin/reitit-parent "0.1.1-SNAPSHOT" +(defproject metosin/reitit-parent "0.1.1" :description "Snappy data-driven router for Clojure(Script)" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" @@ -9,13 +9,13 @@ :source-uri "https://github.com/metosin/reitit/{version}/{filepath}#L{line}" :metadata {:doc/format :markdown}} - :managed-dependencies [[metosin/reitit "0.1.1-SNAPSHOT"] - [metosin/reitit-core "0.1.1-SNAPSHOT"] - [metosin/reitit-ring "0.1.1-SNAPSHOT"] - [metosin/reitit-spec "0.1.1-SNAPSHOT"] - [metosin/reitit-schema "0.1.1-SNAPSHOT"] - [metosin/reitit-swagger "0.1.1-SNAPSHOT"] - [metosin/reitit-swagger-ui "0.1.1-SNAPSHOT"] + :managed-dependencies [[metosin/reitit "0.1.1"] + [metosin/reitit-core "0.1.1"] + [metosin/reitit-ring "0.1.1"] + [metosin/reitit-spec "0.1.1"] + [metosin/reitit-schema "0.1.1"] + [metosin/reitit-swagger "0.1.1"] + [metosin/reitit-swagger-ui "0.1.1"] [meta-merge "1.0.0"] [ring/ring-core "1.6.3"] @@ -53,6 +53,7 @@ [orchestra "2017.11.12-1"] [ring "1.6.3"] + [ikitommi/immutant-web "3.0.0-alpha1"] [metosin/muuntaja "0.5.0"] [metosin/jsonista "0.2.0"] [metosin/ring-swagger-ui "2.2.10"] diff --git a/test/cljc/reitit/ring_test.cljc b/test/cljc/reitit/ring_test.cljc index c803a320..27a5ad83 100644 --- a/test/cljc/reitit/ring_test.cljc +++ b/test/cljc/reitit/ring_test.cljc @@ -284,7 +284,7 @@ (ring/create-resource-handler {:path "/files"}) (ring/create-resource-handler {:path "/"}) (ring/create-default-handler)))]] - prefix ["/" "/files"] + prefix ["" "/" "/files" "/files/"] :let [request (fn [uri] {:uri (str prefix uri), :request-method :get})]] (testing test @@ -300,6 +300,10 @@ (testing "index-files" (let [response (app (request "/docs"))] + (is (= "text/html" (get-in response [:headers "Content-Type"]))) + (is (get-in response [:headers "Last-Modified"])) + (is (= "