diff --git a/advanced/composing_routers.html b/advanced/composing_routers.html index a8f0dcd6..cfbc08bf 100644 --- a/advanced/composing_routers.html +++ b/advanced/composing_routers.html @@ -1189,7 +1189,7 @@ diff --git a/advanced/configuring_routers.html b/advanced/configuring_routers.html index cb86dc4e..db27941f 100644 --- a/advanced/configuring_routers.html +++ b/advanced/configuring_routers.html @@ -903,7 +903,7 @@ diff --git a/advanced/dev_workflow.html b/advanced/dev_workflow.html index 0c4e7842..e51b4c45 100644 --- a/advanced/dev_workflow.html +++ b/advanced/dev_workflow.html @@ -954,7 +954,7 @@ diff --git a/advanced/different_routers.html b/advanced/different_routers.html index 4fb52d42..4087377b 100644 --- a/advanced/different_routers.html +++ b/advanced/different_routers.html @@ -902,7 +902,7 @@ diff --git a/advanced/index.html b/advanced/index.html deleted file mode 100644 index 062b331e..00000000 --- a/advanced/index.html +++ /dev/null @@ -1,839 +0,0 @@ - - - - - - - Advanced · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - - - - - -
- -
- -
- - - - - - - - -
-
- -
- -
-
- -

results matching ""

-
    - -
    -
    - -

    No results matching ""

    - -
    -
    -
    - -
    -
    - -
    - - - - - - - - - - - - - - -
    - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/advanced/interceptors.html b/advanced/interceptors.html deleted file mode 100644 index 0b687402..00000000 --- a/advanced/interceptors.html +++ /dev/null @@ -1,634 +0,0 @@ - - - - - - - Interceptors · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - - - - - - - -
    - -
    - -
    - - - - - - - - -
    -
    - -
    -
    - -
    - -

    Interceptors

    -

    Reitit also supports Pedestal-style interceptors.

    -

    work in progress

    -
      -
    • port the (coericon) middleware into interceptors
    • -
    • separate Clojure(Script) runner?
    • -
    • Docs
    • -
    • Samples
    • -
    - - -
    - -
    -
    -
    - -

    results matching ""

    -
      - -
      -
      - -

      No results matching ""

      - -
      -
      -
      - -
      -
      - -
      - - - - - - - - - - - - - - -
      - - -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/advanced/route_conflicts.html b/advanced/route_conflicts.html deleted file mode 100644 index 2778821d..00000000 --- a/advanced/route_conflicts.html +++ /dev/null @@ -1,534 +0,0 @@ - - - - - - - Route conflicts · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      -
      - - - - - - - - -
      - -
      - -
      - - - - - - - - -
      -
      - -
      -
      - -
      - -

      Route conflicts

      -

      Many routing libraries allow single path lookup could match multiple routes. Usually, first match is used. This is not good, especially if route tree is merged from multiple sources - routes might regress to be unreachable without a warning.

      -

      Reitit resolves this by running explicit conflicit resolution when a Router is created. Conflicting routes are passed into a :conflicts callback. Default implementation throws ex-info with a descriptive message.

      -

      Examples routes with conflicts:

      -
      (require '[reitit.core :as reitit])
      -
      -(def routes
      -  [["/ping"]
      -   ["/:user-id/orders"]
      -   ["/bulk/:bulk-id"]
      -   ["/public/*path"]
      -   ["/:version/status"]])
      -
      -

      By default, ExceptionInfo is thrown:

      -
      (reitit/router routes)
      -; CompilerException clojure.lang.ExceptionInfo: Router contains conflicting routes:
      -;
      -;    /:user-id/orders
      -; -> /public/*path
      -; -> /bulk/:bulk-id
      -;
      -;    /bulk/:bulk-id
      -; -> /:version/status
      -;
      -;    /public/*path
      -; -> /:version/status
      -;
      -
      -

      Just logging the conflicts:

      -
      (reitit/router
      -  routes
      -  {:conflicts (comp println reitit/conflicts-str)})
      -; Router contains conflicting routes:
      -;
      -;    /:user-id/orders
      -; -> /public/*path
      -; -> /bulk/:bulk-id
      -;
      -;    /bulk/:bulk-id
      -; -> /:version/status
      -;
      -;    /public/*path
      -; -> /:version/status
      -;
      -
      - - -
      - -
      -
      -
      - -

      results matching ""

      -
        - -
        -
        - -

        No results matching ""

        - -
        -
        -
        - -
        -
        - -
        - - - - - - - - - - - - - - -
        - - -
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/advanced/route_validation.html b/advanced/route_validation.html index b7cfbd7a..df0be537 100644 --- a/advanced/route_validation.html +++ b/advanced/route_validation.html @@ -990,7 +990,7 @@ diff --git a/advanced/shared_routes.html b/advanced/shared_routes.html index b1e3269e..f85d653c 100644 --- a/advanced/shared_routes.html +++ b/advanced/shared_routes.html @@ -911,7 +911,7 @@ diff --git a/basics.html b/basics.html deleted file mode 100644 index af4fcf0e..00000000 --- a/basics.html +++ /dev/null @@ -1,682 +0,0 @@ - - - - - - - Route syntax · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        -
        - - - - - - - - -
        - -
        - -
        - - - - - - - - -
        -
        - -
        -
        - -
        - -

        Route Syntax

        -

        Raw routes are defined as vectors, which have a String path, optional (non-sequential) route argument and optional child routes. Routes can be wrapped in vectors and lists and nil routes are ignored. Paths can have path-parameters (:id) or catch-all-parameters (*path).

        -

        Simple route:

        -
        ["/ping"]
        -
        -

        Two routes:

        -
        [["/ping"]
        - ["/pong"]]
        -
        -

        Routes with route arguments:

        -
        [["/ping" ::ping]
        - ["/pong" {:name ::pong}]]
        -
        -

        Routes with path parameters:

        -
        [["/users/:user-id"]
        - ["/api/:version/ping"]]
        -
        -

        Route with catch-all parameter:

        -
        ["/public/*path"]
        -
        -

        Nested routes:

        -
        ["/api"
        - ["/admin" {:middleware [::admin]}
        -  ["" ::admin]
        -  ["/db" ::db]]
        - ["/ping" ::ping]]
        -
        -

        Same routes flattened:

        -
        [["/api/admin" {:middleware [::admin], :name ::admin}]
        - ["/api/admin/db" {:middleware [::admin], :name ::db}]
        - ["/api/ping" {:name ::ping}]]
        -
        -

        As routes are just data, it's easy to create them programamtically:

        -
        (defn cqrs-routes [actions dev-mode?]
        -  ["/api" {:interceptors [::api ::db]}
        -   (for [[type interceptor] actions
        -         :let [path (str "/" (name interceptor))
        -               method (condp = type
        -                        :query :get
        -                        :command :post)]]
        -     [path {method {:interceptors [interceptor]}}])
        -   (if dev-mode? ["/dev-tools" ::dev-tools])])
        -
        -
        (cqrs-routes
        -  [[:query   'get-user]
        -   [:command 'add-user]
        -   [:command 'add-order]]
        -  false)
        -; ["/api" {:interceptors [::api ::db]}
        -;  (["/get-user" {:get {:interceptors [get-user]}}]
        -;   ["/add-user" {:post {:interceptors [add-user]}}]
        -;   ["/add-order" {:post {:interceptors [add-order]}}])
        -;  nil]
        -
        -

        Router

        -

        Routes are just data and to do actual routing, we need a Router satisfying the reitit.core/Router protocol. Routers are created with reitit.core/router function, taking the raw routes and optionally an options map. Raw routes gets expanded and optionally coerced and compiled.

        -

        Router protocol:

        -
        (defprotocol Router
        -  (router-name [this])
        -  (routes [this])
        -  (options [this])
        -  (route-names [this])
        -  (match-by-path [this path])
        -  (match-by-name [this name] [this name params]))
        -
        -

        Creating a router:

        -
        (require '[reitit.core :as r])
        -
        -(def router
        -  (r/router
        -    [["/api"
        -      ["/ping" ::ping]
        -      ["/user/:id" ::user]]]))
        -
        -

        Router flattens the raw routes and expands the route arguments using reitit.core/Expand protocol. By default, Keywords are expanded to :name and functions are expaned to :handler. nil routes are removed. The expanded routes can be retrieved with router:

        -
        (r/routes router)
        -; [["/api/ping" {:name :user/ping}]
        -;  ["/api/user/:id" {:name :user/user}]]
        -
        -

        Path-based routing

        -

        Path-based routing is done using the reitit.core/match-by-path function. It takes the router and path as arguments and returns one of the following:

        -
          -
        • nil, no match
        • -
        • PartialMatch, path matched, missing path-parameters (only in reverse-routing)
        • -
        • Match, exact match
        • -
        -
        (r/match-by-path router "/hello")
        -; nil
        -
        -
        (r/match-by-path router "/api/user/1")
        -; #Match{:template "/api/user/:id"
        -;        :meta {:name :user/user}
        -;        :path "/api/user/1"
        -;        :result nil
        -;        :params {:id "1"}}
        -
        -

        Name-based routing

        -

        All routes which :name route data defined, can be matched by name.

        -

        Listing all route names:

        -
        (r/route-names router)
        -; [:user/ping :user/user]
        -
        -

        Matching by name:

        -
        (r/match-by-name router ::user)
        -; #PartialMatch{:template "/api/user/:id",
        -;               :meta {:name :user/user},
        -;               :result nil,
        -;               :params nil,
        -;               :required #{:id}}
        -
        -(r/partial-match? (r/match-by-name router ::user))
        -; true
        -
        -

        We only got a partial match as we didn't provide the needed path-parameters. Let's provide the them too:

        -
        (r/match-by-name router ::user {:id "1"})
        -; #Match{:template "/api/user/:id"
        -;        :meta {:name :user/user}
        -;        :path "/api/user/1"
        -;        :result nil
        -;        :params {:id "1"}}
        -
        -

        There is also a exception throwing version:

        -
        (r/match-by-name! router ::user)
        -; ExceptionInfo missing path-params for route /api/user/:id: #{:id}
        -
        -

        Route data

        -

        Routes can have arbitrary meta-data, interpreted by the router (via it's :compile hook) or the application itself. For nested routes, route data is accumulated recursively using meta-merge. By default, it appends collections, but it can be overridden to do :prepend, :replace or :displace.

        -

        An example router with nested data:

        -
        (def router
        -  (r/router
        -    ["/api" {:interceptors [::api]}
        -     ["/ping" ::ping]
        -     ["/admin" {:roles #{:admin}}
        -      ["/users" ::users]
        -      ["/db" {:interceptors [::db]
        -              :roles ^:replace #{:db-admin}}
        -       ["/:db" {:parameters {:db String}}
        -        ["/drop" ::drop-db]
        -        ["/stats" ::db-stats]]]]]))
        -
        -

        Resolved route tree:

        -
        (reitit/routes router)
        -; [["/api/ping" {:interceptors [::api]
        -;                :name ::ping}]
        -;  ["/api/admin/users" {:interceptors [::api]
        -;                       :roles #{:admin}
        -;                       :name ::users}]
        -;  ["/api/admin/db/:db/drop" {:interceptors [::api ::db]
        -;                             :roles #{:db-admin}
        -;                             :parameters {:db String}
        -;                             :name ::drop-db}]
        -;  ["/api/admin/db/:db/stats" {:interceptors [::api ::db]
        -;                              :roles #{:db-admin}
        -;                              :parameters {:db String}
        -;                              :name ::db-stats}]]
        -
        -

        Route data is returned with Match and the application can act based on it.

        -
        (r/match-by-path router "/api/admin/db/users/drop")
        -; #Match{:template "/api/admin/db/:db/drop"
        -;        :meta {:interceptors [::api ::db]
        -;               :roles #{:db-admin}
        -;                :parameters {:db String}
        -;        :name ::drop-db}
        -;        :result nil
        -;        :params {:db "users"}
        -;        :path "/api/admin/db/users/drop"}
        -
        -

        Different Routers

        -

        Reitit ships with several different implementations for the Router protocol, originally based on the awesome Pedestal implementation. router selects the most suitable implementation by inspecting the expanded routes. The implementation can be set manually using :router ROUTER OPTION.

        - - - - - - - - - - - - - - - - - - - - - - - - - -
        routerdescription
        :linear-routerMatches the routes one-by-one starting from the top until a match is found. Works with any kind of routes.
        :lookup-routerFastest router, uses hash-lookup to resolve the route. Valid if no paths have path or catch-all parameters.
        :mixed-routerCreates internally a :linear-router and a :lookup-router and used them to effectively get best-of-both-worlds. Valid if there are no CONFLICTING ROUTES.
        :prefix-tree-routerTODO
        -

        The router name can be asked from the router

        -
        (r/router-name router)
        -; :mixed-router
        -
        - - -
        - -
        -
        -
        - -

        results matching ""

        -
          - -
          -
          - -

          No results matching ""

          - -
          -
          -
          - -
          -
          - -
          - - - - - - - - - - -
          - - -
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/basics/different_routers.html b/basics/different_routers.html deleted file mode 100644 index 5c9f2615..00000000 --- a/basics/different_routers.html +++ /dev/null @@ -1,521 +0,0 @@ - - - - - - - Different Routers · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          -
          - - - - - - - - -
          - -
          - -
          - - - - - - - - -
          -
          - -
          -
          - -
          - -

          Different Routers

          -

          Reitit ships with several different implementations for the Router protocol, originally based on the awesome Pedestal implementation. router selects the most suitable implementation by inspecting the expanded routes. The implementation can be set manually using :router ROUTER OPTION.

          - - - - - - - - - - - - - - - - - - - - - - - - - -
          routerdescription
          :linear-routerMatches the routes one-by-one starting from the top until a match is found. Works with any kind of routes.
          :lookup-routerFastest router, uses hash-lookup to resolve the route. Valid if no paths have path or catch-all parameters.
          :mixed-routerCreates internally a :linear-router and a :lookup-router and used them to effectively get best-of-both-worlds. Valid if there are no CONFLICTING ROUTES.
          :prefix-tree-routerTODO
          -

          The router name can be asked from the router

          -
          (r/router-name router)
          -; :mixed-router
          -
          - - -
          - -
          -
          -
          - -

          results matching ""

          -
            - -
            -
            - -

            No results matching ""

            - -
            -
            -
            - -
            -
            - -
            - - - - - - - - - - - - - - -
            - - -
            - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/basics/error_messages.html b/basics/error_messages.html index 3c88771f..c71fe13f 100644 --- a/basics/error_messages.html +++ b/basics/error_messages.html @@ -878,7 +878,7 @@ diff --git a/basics/index.html b/basics/index.html deleted file mode 100644 index 870c8f3a..00000000 --- a/basics/index.html +++ /dev/null @@ -1,842 +0,0 @@ - - - - - - - Basics · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            -
            - - - - - - - - -
            - -
            - -
            - - - - - - - - -
            -
            - -
            - -
            -
            - -

            results matching ""

            -
              - -
              -
              - -

              No results matching ""

              - -
              -
              -
              - -
              -
              - -
              - - - - - - - - - - - - - - -
              - - -
              - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/basics/name_based_routing.html b/basics/name_based_routing.html index 7892ecc2..f04daa80 100644 --- a/basics/name_based_routing.html +++ b/basics/name_based_routing.html @@ -913,7 +913,7 @@ diff --git a/basics/path_based_routing.html b/basics/path_based_routing.html index 091fb3a4..e4c05883 100644 --- a/basics/path_based_routing.html +++ b/basics/path_based_routing.html @@ -871,7 +871,7 @@ diff --git a/basics/route_conflicts.html b/basics/route_conflicts.html index 04868143..b0c0bc4d 100644 --- a/basics/route_conflicts.html +++ b/basics/route_conflicts.html @@ -927,7 +927,7 @@ diff --git a/basics/route_data.html b/basics/route_data.html index 66f8a39e..780a0bb2 100644 --- a/basics/route_data.html +++ b/basics/route_data.html @@ -965,7 +965,7 @@ diff --git a/basics/route_data_validation.html b/basics/route_data_validation.html index 5fbbdcb9..02ee23d7 100644 --- a/basics/route_data_validation.html +++ b/basics/route_data_validation.html @@ -942,7 +942,7 @@ diff --git a/basics/route_syntax.html b/basics/route_syntax.html index b04ef249..69a7afd9 100644 --- a/basics/route_syntax.html +++ b/basics/route_syntax.html @@ -949,7 +949,7 @@ diff --git a/basics/router.html b/basics/router.html index ade2d2ea..bd6b17c6 100644 --- a/basics/router.html +++ b/basics/router.html @@ -925,7 +925,7 @@ diff --git a/coercion/clojure_spec_coercion.html b/coercion/clojure_spec_coercion.html index bceaf5e3..968bd4fa 100644 --- a/coercion/clojure_spec_coercion.html +++ b/coercion/clojure_spec_coercion.html @@ -990,7 +990,7 @@ The s/keys accepts :opt-un to support optional keys. var gitbook = gitbook || []; gitbook.push(function() { - gitbook.page.hasChanged({"page":{"title":"Clojure.spec","level":"3.3","depth":1,"next":{"title":"Data-specs","level":"3.4","depth":1,"path":"coercion/data_spec_coercion.md","ref":"coercion/data_spec_coercion.md","articles":[]},"previous":{"title":"Plumatic Schema","level":"3.2","depth":1,"path":"coercion/schema_coercion.md","ref":"coercion/schema_coercion.md","articles":[]},"dir":"ltr"},"config":{"plugins":["hints","editlink","github","highlight"],"root":"doc","styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"pluginsConfig":{"github":{"url":"https://github.com/metosin/reitit"},"editlink":{"label":"Edit This Page","multilingual":false,"base":"https://github.com/metosin/reitit/tree/master/doc"},"search":{},"hints":{"danger":"fa fa-exclamation-circle","info":"fa fa-info-circle","tip":"fa fa-mortar-board","working":"fa fa-wrench"},"lunr":{"maxIndexSize":1000000,"ignoreSpecialCharacters":false},"fontsettings":{"theme":"white","family":"sans","size":2},"highlight":{},"sharing":{"facebook":true,"twitter":true,"google":false,"weibo":false,"instapaper":false,"vk":false,"all":["facebook","google","twitter","weibo","instapaper"]},"theme-default":{"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"showLevel":false}},"theme":"default","pdf":{"pageNumbers":true,"fontSize":12,"fontFamily":"Arial","paperSize":"a4","chapterMark":"pagebreak","pageBreaksBefore":"/","margin":{"right":62,"left":62,"top":56,"bottom":56}},"structure":{"langs":"LANGS.md","readme":"README.md","glossary":"GLOSSARY.md","summary":"SUMMARY.md"},"variables":{},"gitbook":"*"},"file":{"path":"coercion/clojure_spec_coercion.md","mtime":"2020-05-22T13:12:18.030Z","type":"markdown"},"gitbook":{"version":"3.2.3","time":"2020-07-24T11:08:28.724Z"},"basePath":"..","book":{"language":""}}); + gitbook.page.hasChanged({"page":{"title":"Clojure.spec","level":"3.3","depth":1,"next":{"title":"Data-specs","level":"3.4","depth":1,"path":"coercion/data_spec_coercion.md","ref":"coercion/data_spec_coercion.md","articles":[]},"previous":{"title":"Plumatic Schema","level":"3.2","depth":1,"path":"coercion/schema_coercion.md","ref":"coercion/schema_coercion.md","articles":[]},"dir":"ltr"},"config":{"plugins":["hints","editlink","github","highlight"],"root":"doc","styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"pluginsConfig":{"github":{"url":"https://github.com/metosin/reitit"},"editlink":{"label":"Edit This Page","multilingual":false,"base":"https://github.com/metosin/reitit/tree/master/doc"},"search":{},"hints":{"danger":"fa fa-exclamation-circle","info":"fa fa-info-circle","tip":"fa fa-mortar-board","working":"fa fa-wrench"},"lunr":{"maxIndexSize":1000000,"ignoreSpecialCharacters":false},"fontsettings":{"theme":"white","family":"sans","size":2},"highlight":{},"sharing":{"facebook":true,"twitter":true,"google":false,"weibo":false,"instapaper":false,"vk":false,"all":["facebook","google","twitter","weibo","instapaper"]},"theme-default":{"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"showLevel":false}},"theme":"default","pdf":{"pageNumbers":true,"fontSize":12,"fontFamily":"Arial","paperSize":"a4","chapterMark":"pagebreak","pageBreaksBefore":"/","margin":{"right":62,"left":62,"top":56,"bottom":56}},"structure":{"langs":"LANGS.md","readme":"README.md","glossary":"GLOSSARY.md","summary":"SUMMARY.md"},"variables":{},"gitbook":"*"},"file":{"path":"coercion/clojure_spec_coercion.md","mtime":"2020-05-22T13:12:18.030Z","type":"markdown"},"gitbook":{"version":"3.2.3","time":"2020-07-28T09:52:25.779Z"},"basePath":"..","book":{"language":""}}); }); diff --git a/coercion/coercion.html b/coercion/coercion.html index bfd5d649..10d32ce3 100644 --- a/coercion/coercion.html +++ b/coercion/coercion.html @@ -979,7 +979,7 @@ diff --git a/coercion/data_spec_coercion.html b/coercion/data_spec_coercion.html index 2976f13a..8b5105ab 100644 --- a/coercion/data_spec_coercion.html +++ b/coercion/data_spec_coercion.html @@ -877,7 +877,7 @@ diff --git a/coercion/index.html b/coercion/index.html deleted file mode 100644 index 478248e9..00000000 --- a/coercion/index.html +++ /dev/null @@ -1,839 +0,0 @@ - - - - - - - Coercion · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
              -
              - - - - - - - - -
              - -
              - -
              - - - - - - - - -
              -
              - -
              -
              - -
              - -

              Coercion

              - - - -
              - -
              -
              -
              - -

              results matching ""

              -
                - -
                -
                - -

                No results matching ""

                - -
                -
                -
                - -
                -
                - -
                - - - - - - - - - - - - - - -
                - - -
                - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/coercion/schema_coercion.html b/coercion/schema_coercion.html index 6ab8bea0..fe0cde85 100644 --- a/coercion/schema_coercion.html +++ b/coercion/schema_coercion.html @@ -878,7 +878,7 @@ diff --git a/compiling_middleware.html b/compiling_middleware.html deleted file mode 100644 index 2eb6fa20..00000000 --- a/compiling_middleware.html +++ /dev/null @@ -1,546 +0,0 @@ - - - - - - - Compiling middleware · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                -
                - - - - - - - - -
                - -
                - -
                - - - - - - - - -
                -
                - -
                -
                - -
                - -

                Compiling Middleware

                -

                The meta-data extensions are a easy way to extend the system. Routes meta-data can be transformed into any shape (records, functions etc.) in route compilation, enabling fast access at request-time.

                -

                Still, we can do better. As we know the exact route that interceptor/middleware is linked to, we can pass the (compiled) route information into the interceptor/middleware at creation-time. It can extract and transform relevant data just for it and pass it into the actual request-handler via a closure - yielding faster runtime processing.

                -

                To do this we use middleware records :gen hook instead of the normal :wrap. :gen expects a function of route-meta router-opts => wrap. Middleware can also return nil, which effective unmounts the middleware. Why mount a wrap-enforce-roles middleware for a route if there are no roles required for it?

                -

                To demonstrate the two approaches, below are response coercion middleware written as normal ring middleware function and as middleware record with :gen. These are the actual codes are from reitit.coercion:

                -

                Naive

                -
                  -
                • Extracts the compiled route information on every request.
                • -
                -
                (defn wrap-coerce-response
                -  "Pluggable response coercion middleware.
                -  Expects a :coercion of type `reitit.coercion.protocol/Coercion`
                -  and :responses from route meta, otherwise does not mount."
                -  [handler]
                -  (fn
                -    ([request]
                -     (let [response (handler request)
                -           method (:request-method request)
                -           match (ring/get-match request)
                -           responses (-> match :result method :meta :responses)
                -           coercion (-> match :meta :coercion)
                -           opts (-> match :meta :opts)]
                -       (if (and coercion responses)
                -         (let [coercers (response-coercers coercion responses opts)
                -               coerced (coerce-response coercers request response)]
                -           (coerce-response coercers request (handler request)))
                -         (handler request))))
                -    ([request respond raise]
                -     (let [response (handler request)
                -           method (:request-method request)
                -           match (ring/get-match request)
                -           responses (-> match :result method :meta :responses)
                -           coercion (-> match :meta :coercion)
                -           opts (-> match :meta :opts)]
                -       (if (and coercion responses)
                -         (let [coercers (response-coercers coercion responses opts)
                -               coerced (coerce-response coercers request response)]
                -           (handler request #(respond (coerce-response coercers request %))))
                -         (handler request respond raise))))))
                -
                -

                Compiled

                -
                  -
                • Route information is provided via a closure
                • -
                • Pre-compiled coercers
                • -
                • Mounts only if :coercion and :responses are defined for the route
                • -
                -
                (def gen-wrap-coerce-response
                -  "Generator for pluggable response coercion middleware.
                -  Expects a :coercion of type `reitit.coercion.protocol/Coercion`
                -  and :responses from route meta, otherwise does not mount."
                -  (middleware/create
                -    {:name ::coerce-response
                -     :gen (fn [{:keys [responses coercion opts]} _]
                -            (if (and coercion responses)
                -              (let [coercers (response-coercers coercion responses opts)]
                -                (fn [handler]
                -                  (fn
                -                    ([request]
                -                     (coerce-response coercers request (handler request)))
                -                    ([request respond raise]
                -                     (handler request #(respond (coerce-response coercers request %)) raise)))))))}))
                -
                -

                The :gen -version has 50% less code, is easier to reason about and is 2-4x faster on basic perf tests.

                - - -
                - -
                -
                -
                - -

                results matching ""

                -
                  - -
                  -
                  - -

                  No results matching ""

                  - -
                  -
                  -
                  - -
                  -
                  - -
                  - - - - - - - - - - -
                  - - -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/configuring_routers.html b/configuring_routers.html deleted file mode 100644 index 73060aeb..00000000 --- a/configuring_routers.html +++ /dev/null @@ -1,527 +0,0 @@ - - - - - - - Configuring routers · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - - - - - - - - -
                  - -
                  - -
                  - - - - - - - - -
                  -
                  - -
                  -
                  - -
                  - -

                  Configuring Routers

                  -

                  Routers can be configured via options. Options allow things like clojure.spec validation for meta-data and fast, compiled handlers. The following options are available for the reitit.core/router:

                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  keydescription
                  :pathBase-path for routes
                  :routesInitial resolved routes (default [])
                  :metaInitial expanded route-meta vector (default [])
                  :expandFunction of arg opts => meta to expand route arg to route meta-data (default reitit.core/expand)
                  :coerceFunction of route opts => route to coerce resolved route, can throw or return nil
                  :compileFunction of route opts => result to compile a route handler
                  :conflictsFunction of {route #{route}} => side-effect to handle conflicting routes (default reitit.core/throw-on-conflicts!)
                  :routerFunction of routes opts => router to override the actual router implementation
                  - - -
                  - -
                  -
                  -
                  - -

                  results matching ""

                  -
                    - -
                    -
                    - -

                    No results matching ""

                    - -
                    -
                    -
                    - -
                    -
                    - -
                    - - - - - - - - - - -
                    - - -
                    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/development.html b/development.html index 4059463e..b10356b5 100644 --- a/development.html +++ b/development.html @@ -869,7 +869,7 @@ lein test diff --git a/dynamic_extensions.html b/dynamic_extensions.html deleted file mode 100644 index ed638f77..00000000 --- a/dynamic_extensions.html +++ /dev/null @@ -1,525 +0,0 @@ - - - - - - - Dynamic extensions · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    -
                    - - - - - - - - -
                    - -
                    - -
                    - - - - - - - - -
                    -
                    - -
                    -
                    - -
                    - -

                    Dynamic extensions

                    -

                    ring-handler injects the Match into a request and it can be extracted at runtime with reitit.ring/get-match. This can be used to build dynamic extensions to the system.

                    -

                    Example middleware to guard routes based on user roles:

                    -
                    (require '[clojure.set :as set])
                    -
                    -(defn wrap-enforce-roles [handler]
                    -  (fn [{:keys [::roles] :as request}]
                    -    (let [required (some-> request (ring/get-match) :meta ::roles)]
                    -      (if (and (seq required) (not (set/intersection required roles)))
                    -        {:status 403, :body "forbidden"}
                    -        (handler request)))))
                    -
                    -

                    Mounted to an app via router meta-data (effecting all routes):

                    -
                    (def handler (constantly {:status 200, :body "ok"}))
                    -
                    -(def app
                    -  (ring/ring-handler
                    -    (ring/router
                    -      [["/api"
                    -        ["/ping" handler]
                    -        ["/admin" {::roles #{:admin}}
                    -         ["/ping" handler]]]]
                    -      {:meta {:middleware [wrap-enforce-roles]}})))
                    -
                    -

                    Anonymous access to public route:

                    -
                    (app {:request-method :get, :uri "/api/ping"})
                    -; {:status 200, :body "ok"}
                    -
                    -

                    Anonymous access to guarded route:

                    -
                    (app {:request-method :get, :uri "/api/admin/ping"})
                    -; {:status 403, :body "forbidden"}
                    -
                    -

                    Authorized access to guarded route:

                    -
                    (app {:request-method :get, :uri "/api/admin/ping", ::roles #{:admin}})
                    -; {:status 200, :body "ok"}
                    -
                    - - -
                    - -
                    -
                    -
                    - -

                    results matching ""

                    -
                      - -
                      -
                      - -

                      No results matching ""

                      - -
                      -
                      -
                      - -
                      -
                      - -
                      - - - - - - - - - - - - - - -
                      - - -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/faq.html b/faq.html index 2bf9619e..2bda4285 100644 --- a/faq.html +++ b/faq.html @@ -949,7 +949,7 @@ diff --git a/frontend/README.md b/frontend/README.md deleted file mode 100644 index 65b78197..00000000 --- a/frontend/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Frontend - -* [Basics](basics.md) -* [Browser integration](browser.md) -* [Controllers](controllers.md) diff --git a/frontend/basics.html b/frontend/basics.html index 9db7e6ed..479b6a42 100644 --- a/frontend/basics.html +++ b/frontend/basics.html @@ -866,7 +866,7 @@ React breaking due to errors.

                      diff --git a/frontend/basics.md b/frontend/basics.md deleted file mode 100644 index b0d632fb..00000000 --- a/frontend/basics.md +++ /dev/null @@ -1,3 +0,0 @@ -# Frontend basics - -TODO diff --git a/frontend/browser.html b/frontend/browser.html index b196daff..e26a7dcd 100644 --- a/frontend/browser.html +++ b/frontend/browser.html @@ -889,7 +889,7 @@ go back or forwards, but calling History API functions directly should work:

                      diff --git a/frontend/browser.md b/frontend/browser.md deleted file mode 100644 index a7a8c613..00000000 --- a/frontend/browser.md +++ /dev/null @@ -1,3 +0,0 @@ -# Frontend browser integration - -TODO diff --git a/frontend/controllers.html b/frontend/controllers.html index f7dd3036..2b3c9826 100644 --- a/frontend/controllers.html +++ b/frontend/controllers.html @@ -946,7 +946,7 @@ missing resources.

                      diff --git a/frontend/controllers.md b/frontend/controllers.md deleted file mode 100644 index 11f9f263..00000000 --- a/frontend/controllers.md +++ /dev/null @@ -1,3 +0,0 @@ -# Controllers - -TODO diff --git a/frontend/index.html b/frontend/index.html deleted file mode 100644 index a45f1636..00000000 --- a/frontend/index.html +++ /dev/null @@ -1,838 +0,0 @@ - - - - - - - Frontend · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      -
                      - - - - - - - - -
                      - -
                      - -
                      - - - - - - - - -
                      -
                      - -
                      -
                      - -
                      - -

                      Frontend

                      - - - -
                      - -
                      -
                      -
                      - -

                      results matching ""

                      -
                        - -
                        -
                        - -

                        No results matching ""

                        - -
                        -
                        -
                        - -
                        -
                        - -
                        - - - - - - - - - - - - - - -
                        - - -
                        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/http/default_interceptors.html b/http/default_interceptors.html index 8facbc7a..99e1f6e5 100644 --- a/http/default_interceptors.html +++ b/http/default_interceptors.html @@ -868,7 +868,7 @@ diff --git a/http/interceptors.html b/http/interceptors.html index 25526769..79e19187 100644 --- a/http/interceptors.html +++ b/http/interceptors.html @@ -896,7 +896,7 @@ diff --git a/http/pedestal.html b/http/pedestal.html index a13e2313..cba7c8a0 100644 --- a/http/pedestal.html +++ b/http/pedestal.html @@ -907,7 +907,7 @@ diff --git a/http/sieppari.html b/http/sieppari.html index eaa881d5..f27a6b7c 100644 --- a/http/sieppari.html +++ b/http/sieppari.html @@ -908,7 +908,7 @@ diff --git a/http/transforming_interceptor_chain.html b/http/transforming_interceptor_chain.html index 6878567f..f64360fa 100644 --- a/http/transforming_interceptor_chain.html +++ b/http/transforming_interceptor_chain.html @@ -907,7 +907,7 @@ diff --git a/index.html b/index.html index cc2515a1..a489d428 100644 --- a/index.html +++ b/index.html @@ -972,7 +972,7 @@ diff --git a/interceptors.html b/interceptors.html deleted file mode 100644 index 9b129a6f..00000000 --- a/interceptors.html +++ /dev/null @@ -1,901 +0,0 @@ - - - - - - - Interceptors (WIP) · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        -
                        - - - - - - - - -
                        - -
                        - -
                        - - - - - - - - -
                        -
                        - -
                        -
                        - -
                        - -

                        Interceptors (WIP)

                        -

                        Reitit also support for Pedestal-style interceptors as an alternative to Middleware. Basic interceptor handling is implemented in reitit.interceptor package. There is no interceptor executor shipped, but you can use libraries like Pedestal Interceptor or Sieppari to execute the chains.

                        -

                        Reitit-http

                        -

                        An alternative to reitit-ring, using interceptors instead of middleware. Currently not finalized, you can track progress in here.

                        -

                        Examples

                        -

                        Standalone

                        - -
                        (require '[reitit.interceptor.sieppari :as sieppari])
                        -(require '[reitit.http.coercion :as coercion])
                        -(require '[reitit.http :as http])
                        -(require '[reitit.ring :as ring])
                        -(require '[reitit.coercion.spec])
                        -(require '[clojure.set :as set])
                        -(require '[manifold.deferred :as d])
                        -(require '[ring.adapter.jetty :as jetty])
                        -
                        -(def auth-interceptor
                        -  "Interceptor that mounts itself if route has `:roles` data. Expects `:roles`
                        -  to be a set of keyword and the context to have `[:user :roles]` with user roles.
                        -  responds with HTTP 403 if user doesn't have the roles defined, otherwise no-op."
                        -  {:name ::auth
                        -   :compile (fn [{:keys [roles]} _]
                        -              (if (seq roles)
                        -                {:description (str "requires roles " roles)
                        -                 :spec {:roles #{keyword?}}
                        -                 :context-spec {:user {:roles #{keyword}}}
                        -                 :enter (fn [{{user-roles :roles} :user :as ctx}]
                        -                          (if (not (set/subset? roles user-roles))
                        -                            (assoc ctx :response {:status 403, :body "forbidden"})
                        -                            ctx))}))})
                        -
                        -(def async-interceptor
                        -  {:enter (fn [ctx] (d/future ctx))})
                        -
                        -(def app
                        -  (http/ring-handler
                        -    (http/router
                        -      ["/api" {:interceptors [async-interceptor auth-interceptor]}
                        -       ["/ping" {:name ::ping
                        -                 :get (constantly
                        -                        {:status 200
                        -                         :body "pong"})}]
                        -       ["/plus/:z" {:name ::plus
                        -                    :post {:parameters {:query {:x int?}
                        -                                        :body {:y int?}
                        -                                        :path {:z int?}}
                        -                           :responses {200 {:body {:total pos-int?}}}
                        -                           :roles #{:admin}
                        -                           :handler (fn [{:keys [parameters]}]
                        -                                      (let [total (+ (-> parameters :query :x)
                        -                                                     (-> parameters :body :y)
                        -                                                     (-> parameters :path :z))]
                        -                                        {:status 200
                        -                                         :body {:total total}}))}}]]
                        -      {:data {:coercion reitit.coercion.spec/coercion
                        -              :interceptors [coercion/coerce-exceptions-interceptor
                        -                             coercion/coerce-request-interceptor
                        -                             coercion/coerce-response-interceptor]}})
                        -    (ring/create-default-handler)
                        -    {:executor sieppari/executor}))
                        -
                        -(jetty/run-jetty #'app {:port 3000, :join? false, :async? true})
                        -
                        -

                        Pedestal

                        -

                        TODO

                        - - -
                        - -
                        -
                        -
                        - -

                        results matching ""

                        -
                          - -
                          -
                          - -

                          No results matching ""

                          - -
                          -
                          -
                          - -
                          -
                          - -
                          - - - - - - - - - - - - - - -
                          - - -
                          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/middleware_records.md b/middleware_records.md deleted file mode 100644 index 784d0485..00000000 --- a/middleware_records.md +++ /dev/null @@ -1,34 +0,0 @@ -# Middleware Records - -Reitit supports first-class data-driven middleware via `reitit.middleware/Middleware` records, created with `reitit.middleware/create` function. The following keys have special purpose: - -| key | description | -| -----------|-------------| -| `:name` | Name of the middleware as qualified keyword (optional,recommended for libs) -| `:wrap` | The actual middleware function of `handler args? => request => response` -| `:gen` | Middleware compile function, see [compiling middleware](#compiling-middleware). - -When routes are compiled, all middleware are expanded (and optionally compiled) into `Middleware` and stored in compilation results for later use (api-docs etc). For actual request processing, they are unwrapped into normal middleware functions producing zero runtime performance penalty. Middleware expansion is backed by `reitit.middleware/IntoMiddleware` protocol, enabling plain clojure(script) maps to be used. - -A Record: - -```clj -(require '[reitit.middleware :as middleware]) - -(def wrap2 - (middleware/create - {:name ::wrap2 - :description "a nice little mw, takes 1 arg." - :wrap wrap})) -``` - -As plain map: - -```clj -;; plain map -(def wrap3 - {:name ::wrap3 - :description "a nice little mw, :api as arg" - :wrap (fn [handler] - (wrap handler :api))}) -``` diff --git a/openapi.html b/openapi.html deleted file mode 100644 index d8781fce..00000000 --- a/openapi.html +++ /dev/null @@ -1,690 +0,0 @@ - - - - - - - Swagger & Openapi (WIP) · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                          -
                          - - - - - - - - -
                          - -
                          - -
                          - - - - - - - - -
                          -
                          - -
                          -
                          - -
                          - -

                          Swagger & OpenAPI (WIP)

                          -

                          Goal is to support both Swagger & OpenAPI for route documentation. Documentation is extracted from existing coercion definitions :parameters, :responses and from a set of new doumentation keys.

                          -

                          Swagger-support draft works, but only for Clojure.

                          -

                          TODO

                          - -

                          Example

                          -

                          Current reitit-swagger draft (with reitit-ring & data-specs):

                          -
                          (require '[reitit.ring :as ring])
                          -(require '[reitit.ring.swagger :as swagger])
                          -(require '[reitit.ring.coercion :as rrc])
                          -(require '[reitit.coercion.spec :as spec])
                          -
                          -(def app
                          -  (ring/ring-handler
                          -    (ring/router
                          -      ["/api"
                          -       ;; identify a swagger api
                          -       ;; there can be several in a routing tree
                          -       {:swagger {:id :math}}
                          -
                          -       ;; the (undocumented) swagger spec endpoint
                          -       ["/swagger.json"
                          -        {:get {:no-doc true
                          -               :swagger {:info {:title "my-api"}}
                          -               :handler swagger/swagger-spec-handler}}]
                          -
                          -       ["/minus"
                          -        {:get {:summary "minus"
                          -               :parameters {:query {:x int?, :y int?}}
                          -               :responses {200 {:body {:total int?}}}
                          -               :handler (fn [{{{:keys [x y]} :query} :parameters}]
                          -                          {:status 200, :body {:total (- x y)}})}}]
                          -
                          -       ["/plus"
                          -        {:get {:summary "plus"
                          -               :parameters {:query {:x int?, :y int?}}
                          -               :responses {200 {:body {:total int?}}}
                          -               :handler (fn [{{{:keys [x y]} :query} :parameters}]
                          -                          {:status 200, :body {:total (+ x y)}})}}]]
                          -
                          -      {:data {:middleware [;; does not particiate in request processing
                          -                           ;; just defines specs for the extra keys
                          -                           swagger/swagger-middleware
                          -                           rrc/coerce-exceptions-middleware
                          -                           rrc/coerce-request-middleware
                          -                           rrc/coerce-response-middleware]
                          -              :coercion spec/coercion}})))
                          -
                          - - -
                          - -
                          -
                          -
                          - -

                          results matching ""

                          -
                            - -
                            -
                            - -

                            No results matching ""

                            - -
                            -
                            -
                            - -
                            -
                            - -
                            - - - - - - - - - - - - - - -
                            - - -
                            - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/parameter_coercion.html b/parameter_coercion.html deleted file mode 100644 index 74b99fb7..00000000 --- a/parameter_coercion.html +++ /dev/null @@ -1,565 +0,0 @@ - - - - - - - Parameter coercion · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                            -
                            - - - - - - - - -
                            - -
                            - -
                            - - - - - - - - -
                            -
                            - -
                            -
                            - -
                            - -

                            Parameter coercion

                            -

                            Reitit provides pluggable parameter coercion via reitit.coercion.protocol/Coercion protocol, originally introduced in compojure-api. Reitit ships with reitit.coercion.spec/SpecCoercion providing implemenation for clojure.spec and data-specs.

                            -

                            NOTE: Before Clojure 1.9.0 is shipped, to use the spec-coercion, one needs to add the following dependencies manually to the project:

                            -
                            [org.clojure/clojure "1.9.0-alpha20"]
                            -[org.clojure/spec.alpha "0.1.123"]
                            -[metosin/spec-tools "0.3.3"]
                            -
                            -

                            Ring request and response coercion

                            -

                            To use Coercion with Ring, one needs to do the following:

                            -
                              -
                            1. Define parameters and responses as data into route meta-data, in format adopted from ring-swagger:
                                -
                              • :parameters map, with submaps for different parameters: :query, :body, :form, :header and :path. Parameters are defined in the format understood by the Coercion.
                              • -
                              • :responses map, with response status codes as keys (or :default for "everything else") with maps with :schema and optionally :description as values.
                              • -
                              -
                            2. -
                            3. Define a Coercion to route meta-data under :coercion
                            4. -
                            5. Mount request & response coercion middleware to the routes.
                            6. -
                            -

                            If the request coercion succeeds, the coerced parameters are injected into request under :parameters.

                            -

                            If either request or response coercion fails, an descriptive error is thrown.

                            -

                            Example with data-specs

                            -
                            (require '[reitit.ring :as ring])
                            -(require '[reitit.coercion :as coercion])
                            -(require '[reitit.coercion.spec :as spec])
                            -
                            -(def app
                            -  (ring/ring-handler
                            -    (ring/router
                            -      ["/api"
                            -       ["/ping" {:parameters {:body {:x int?, :y int?}}
                            -                 :responses {200 {:schema {:total pos-int?}}}
                            -                 :get {:handler (fn [{{{:keys [x y]} :body} :parameters}]
                            -                                  {:status 200
                            -                                   :body {:total (+ x y)}})}}]]
                            -      {:meta {:middleware [coercion/gen-wrap-coerce-parameters
                            -                           coercion/gen-wrap-coerce-response]
                            -              :coercion spec/coercion}})))
                            -
                            -
                            (app
                            -  {:request-method :get
                            -   :uri "/api/ping"
                            -   :body-params {:x 1, :y 2}})
                            -; {:status 200, :body {:total 3}}
                            -
                            -

                            Example with specs

                            -
                            (require '[reitit.ring :as ring])
                            -(require '[reitit.coercion :as coercion])
                            -(require '[reitit.coercion.spec :as spec])
                            -(require '[clojure.spec.alpha :as s])
                            -(require '[spec-tools.core :as st])
                            -
                            -(s/def ::x (st/spec int?))
                            -(s/def ::y (st/spec int?))
                            -(s/def ::total int?)
                            -(s/def ::request (s/keys :req-un [::x ::y]))
                            -(s/def ::response (s/keys :req-un [::total]))
                            -
                            -(def app
                            -  (ring/ring-handler
                            -    (ring/router
                            -      ["/api"
                            -       ["/ping" {:parameters {:body ::request}
                            -                 :responses {200 {:schema ::response}}
                            -                 :get {:handler (fn [{{{:keys [x y]} :body} :parameters}]
                            -                                  {:status 200
                            -                                   :body {:total (+ x y)}})}}]]
                            -      {:meta {:middleware [coercion/gen-wrap-coerce-parameters
                            -                           coercion/gen-wrap-coerce-response]
                            -              :coercion spec/coercion}})))
                            -
                            -
                            (app
                            -  {:request-method :get
                            -   :uri "/api/ping"
                            -   :body-params {:x 1, :y 2}})
                            -; {:status 200, :body {:total 3}}
                            -
                            - - -
                            - -
                            -
                            -
                            - -

                            results matching ""

                            -
                              - -
                              -
                              - -

                              No results matching ""

                              - -
                              -
                              -
                              - -
                              -
                              - -
                              - - - - - - - - - - - - - - -
                              - - -
                              - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/patterns/index.html b/patterns/index.html deleted file mode 100644 index 6c1e9f8e..00000000 --- a/patterns/index.html +++ /dev/null @@ -1,836 +0,0 @@ - - - - - - - Patterns · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                              -
                              - - - - - - - - -
                              - -
                              - -
                              - - - - - - - - -
                              -
                              - -
                              -
                              - -
                              - -

                              Patterns

                              - - - -
                              - -
                              -
                              -
                              - -

                              results matching ""

                              -
                                - -
                                -
                                - -

                                No results matching ""

                                - -
                                -
                                -
                                - -
                                -
                                - -
                                - - - - - - - - - - - - - - -
                                - - -
                                - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/patterns/shared_routes.html b/patterns/shared_routes.html deleted file mode 100644 index 2bf6b65a..00000000 --- a/patterns/shared_routes.html +++ /dev/null @@ -1,899 +0,0 @@ - - - - - - - Shared Routes · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                -
                                - - - - - - - - -
                                - -
                                - -
                                - - - - - - - - -
                                -
                                - -
                                -
                                - -
                                - -

                                Shared routes

                                -

                                As reitit-core works with both Clojure & ClojureScript, one can have a shared routing table for both the frontend and the backend application, using the Clujore Common Files.

                                -

                                For backend, you need to define a :handler for the request processing, for fronend, :name enables the use of reverse routing.

                                -

                                There are multiple options to use shared routing table.

                                -

                                Using reader conditionals

                                -
                                ;; define the handlers for for clojure
                                -#?(:clj (declare get-kikka))
                                -#?(:clj (declare post-kikka))
                                -
                                -;; :name for both, :handler just for clojure
                                -(def routes
                                -  ["/kikka"
                                -   {:name ::kikka
                                -    :get #?(:clj {:handler get-kikka})
                                -    :post #?(:clj {:handler post-kikka})}]
                                -
                                -

                                Using custom expander

                                -

                                raw-routes can have any non-sequential data as a route argument, which gets expanded using the :expand option given to the reitit.core.router function. It defaults to reitit.core/expand multimethod.

                                -

                                First, define the common routes (in a .cljc file):

                                -
                                (def routes
                                -  [["/kikka" ::kikka]
                                -   ["/bar" ::bar]])
                                -
                                -

                                Those can be used as-is from ClojureScript:

                                -
                                (require '[reitit.core :as r])
                                -
                                -(def router
                                -  (r/router routes))
                                -
                                -(r/match-by-name router ::kikka)
                                -;#Match{:template "/kikka"
                                -;       :data {:name :user/kikka}
                                -;       :result nil
                                -;       :path-params nil
                                -;       :path "/kikka"}
                                -
                                -

                                For the backend, we can use a custom-expander to expand the routes:

                                -
                                (require '[reitit.ring :as ring])
                                -
                                -(defn my-expand [registry]
                                -  (fn [data opts]
                                -    (or (if (keyword? data)
                                -          (some-> data
                                -                  registry
                                -                  (r/expand opts)
                                -                  (assoc :name data)))
                                -        (r/expand data opts))))
                                -
                                -;; the handler functions
                                -(defn get-kikka [_] {:status 200, :body "get"})
                                -(defn post-kikka [_] {:status 200, :body "post"})
                                -(defn bar [_] {:status 200, :body "bar"})
                                -
                                -(def app
                                -  (ring/ring-handler
                                -    (ring/router
                                -      [["/kikka" ::kikka]
                                -       ["/bar" ::bar]]
                                -      ;; use a custom expander
                                -      {:expand (my-expand
                                -                 {::kikka {:get get-kikka
                                -                           :post post-kikka}
                                -                  ::bar bar})})))
                                -
                                -(app {:request-method :post, :uri "/kikka"})
                                -; {:status 200, :body "post"}
                                -
                                - - -
                                - -
                                -
                                -
                                - -

                                results matching ""

                                -
                                  - -
                                  -
                                  - -

                                  No results matching ""

                                  - -
                                  -
                                  -
                                  - -
                                  -
                                  - -
                                  - - - - - - - - - - - - - - -
                                  - - -
                                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/performance.html b/performance.html index fab06f22..d35b3a93 100644 --- a/performance.html +++ b/performance.html @@ -955,7 +955,7 @@ diff --git a/ring.html b/ring.html deleted file mode 100644 index 365b525c..00000000 --- a/ring.html +++ /dev/null @@ -1,568 +0,0 @@ - - - - - - - Ring-router · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                  -
                                  - - - - - - - - -
                                  - -
                                  - -
                                  - - - - - - - - -
                                  -
                                  - -
                                  -
                                  - -
                                  - -

                                  Ring Router

                                  -

                                  Ring-router adds support for handlers, middleware and routing based on :request-method. Ring-router is created with reitit.ring/router function. It runs a custom route compiler, creating a optimized stucture for handling route matches, with compiled middleware chain & handlers for all request methods. It also ensures that all routes have a :handler defined.

                                  -

                                  Simple Ring app:

                                  -
                                  (require '[reitit.ring :as ring])
                                  -
                                  -(defn handler [_]
                                  -  {:status 200, :body "ok"})
                                  -
                                  -(def app
                                  -  (ring/ring-handler
                                  -    (ring/router
                                  -      ["/ping" handler])))
                                  -
                                  -

                                  Applying the handler:

                                  -
                                  (app {:request-method :get, :uri "/favicon.ico"})
                                  -; nil
                                  -
                                  -(app {:request-method :get, :uri "/ping"})
                                  -; {:status 200, :body "ok"}
                                  -
                                  -

                                  The expanded routes:

                                  -
                                  (-> app (ring/get-router) (reitit/routes))
                                  -; [["/ping"
                                  -;   {:handler #object[...]}
                                  -;   #Methods{:any #Endpoint{:meta {:handler #object[...]},
                                  -;                           :handler #object[...],
                                  -;                           :middleware []}}]]
                                  -
                                  -

                                  Note that the compiled resuts as third element in the route vector.

                                  -

                                  Request-method based routing

                                  -

                                  Handler are also looked under request-method keys: :get, :head, :patch, :delete, :options, :post or :put. Top-level handler is used if request-method based handler is not found.

                                  -
                                  (def app
                                  -  (ring/ring-handler
                                  -    (ring/router
                                  -      ["/ping" {:name ::ping
                                  -                :get handler
                                  -                :post handler}])))
                                  -
                                  -(app {:request-method :get, :uri "/ping"})
                                  -; {:status 200, :body "ok"}
                                  -
                                  -(app {:request-method :put, :uri "/ping"})
                                  -; nil
                                  -
                                  -

                                  Reverse routing:

                                  -
                                  (-> app
                                  -    (ring/get-router)
                                  -    (reitit/match-by-name ::ping)
                                  -    :path)
                                  -; "/ping"
                                  -
                                  -

                                  Middleware

                                  -

                                  Middleware can be added with a :middleware key, with a vector value of the following:

                                  -
                                    -
                                  1. ring middleware function handler -> request -> response
                                  2. -
                                  3. vector of middleware function handler ?args -> request -> response and optinally it's args.
                                  4. -
                                  -

                                  A middleware and a handler:

                                  -
                                  (defn wrap [handler id]
                                  -  (fn [request]
                                  -    (handler (update request ::acc (fnil conj []) id))))
                                  -
                                  -(defn handler [{:keys [::acc]}]
                                  -  {:status 200, :body (conj acc :handler)})
                                  -
                                  -

                                  App with nested middleware:

                                  -
                                  (def app
                                  -  (ring/ring-handler
                                  -    (ring/router
                                  -      ["/api" {:middleware [#(wrap % :api)]}
                                  -       ["/ping" handler]
                                  -       ["/admin" {:middleware [[wrap :admin]]}
                                  -        ["/db" {:middleware [[wrap :db]]
                                  -                :delete {:middleware [#(wrap % :delete)]
                                  -                         :handler handler}}]]])))
                                  -
                                  -

                                  Middleware is applied correctly:

                                  -
                                  (app {:request-method :delete, :uri "/api/ping"})
                                  -; {:status 200, :body [:api :handler]}
                                  -
                                  -
                                  (app {:request-method :delete, :uri "/api/admin/db"})
                                  -; {:status 200, :body [:api :admin :db :delete :handler]}
                                  -
                                  -

                                  Async Ring

                                  -

                                  All built-in middleware provide both 2 and 3-arity and are compiled for both Clojure & ClojureScript, so they work with Async Ring and Node.js too.

                                  - - -
                                  - -
                                  -
                                  -
                                  - -

                                  results matching ""

                                  -
                                    - -
                                    -
                                    - -

                                    No results matching ""

                                    - -
                                    -
                                    -
                                    - -
                                    -
                                    - -
                                    - - - - - - - - - - -
                                    - - -
                                    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ring/RESTful_form_methods.html b/ring/RESTful_form_methods.html index 919ed25f..7f05451a 100644 --- a/ring/RESTful_form_methods.html +++ b/ring/RESTful_form_methods.html @@ -873,7 +873,7 @@ This is so that our middleware is applied before reitit matches the request with diff --git a/ring/RESTful_form_methods.md b/ring/RESTful_form_methods.md deleted file mode 100644 index 42185ade..00000000 --- a/ring/RESTful_form_methods.md +++ /dev/null @@ -1,36 +0,0 @@ -# RESTful form methods - -When designing RESTful applications you will be doing a lot of "PATCH" and "DELETE" request, but most browsers don't support methods other than "GET" and "POST" when it comes to submitting forms. - -There is a pattern to solve this (pioneered by Rails) using a hidden "_method" field in the form and swapping out the "POST" method for whatever is in that field. - -We can do this with middleware in reitit like this: -```clj -(defn- hidden-method - [request] - (keyword - (or (get-in request [:form-params "_method"]) ;; look for "_method" field in :form-params - (get-in request [:multipart-params "_method"])))) ;; or in :multipart-params - -(def wrap-hidden-method - {:name ::wrap-hidden-method - :wrap (fn [handler] - (fn [request] - (if-let [fm (and (= :post (:request-method request)) ;; if this is a :post request - (hidden-method request))] ;; and there is a "_method" field - (handler (assoc request :request-method fm)) ;; replace :request-method - (handler request))))}) -``` - -And apply the middleware like this: -```clj -(reitit.ring/ring-handler - (reitit.ring/router ...) - (reitit.ring/create-default-handler) - {:middleware - [reitit.ring.middleware.parameters/parameters-middleware ;; needed to have :form-params in the request map - reitit.ring.middleware.multipart/multipart-middleware ;; needed to have :multipart-params in the request map - wrap-hidden-method]}) ;; our hidden method wrapper -``` -(NOTE: This middleware must be placed here and not inside the route data given to `reitit.ring/handler`. -This is so that our middleware is applied before reitit matches the request with a spesific handler using the wrong method.) diff --git a/ring/coercion.html b/ring/coercion.html index 5e9cb172..13bca078 100644 --- a/ring/coercion.html +++ b/ring/coercion.html @@ -1074,7 +1074,7 @@ diff --git a/ring/compiling_middleware.html b/ring/compiling_middleware.html index 61501e40..8c4b8a9e 100644 --- a/ring/compiling_middleware.html +++ b/ring/compiling_middleware.html @@ -936,7 +936,7 @@ diff --git a/ring/content_negotiation.html b/ring/content_negotiation.html index 90630b35..77e361c5 100644 --- a/ring/content_negotiation.html +++ b/ring/content_negotiation.html @@ -959,7 +959,7 @@ Server: Jetty(9.2.21.v20170120) diff --git a/ring/data_driven_middleware.html b/ring/data_driven_middleware.html index 1debba8f..d5cec29f 100644 --- a/ring/data_driven_middleware.html +++ b/ring/data_driven_middleware.html @@ -934,7 +934,7 @@ diff --git a/ring/default_handler.html b/ring/default_handler.html index 09f8072d..a270955d 100644 --- a/ring/default_handler.html +++ b/ring/default_handler.html @@ -912,7 +912,7 @@ diff --git a/ring/default_middleware.html b/ring/default_middleware.html index 28f7eeac..043f90db 100644 --- a/ring/default_middleware.html +++ b/ring/default_middleware.html @@ -893,7 +893,7 @@ diff --git a/ring/dynamic_extensions.html b/ring/dynamic_extensions.html index 160984f7..6f703cd9 100644 --- a/ring/dynamic_extensions.html +++ b/ring/dynamic_extensions.html @@ -881,7 +881,7 @@ diff --git a/ring/exceptions.html b/ring/exceptions.html index f1b78a7a..06eb3f2b 100644 --- a/ring/exceptions.html +++ b/ring/exceptions.html @@ -960,7 +960,7 @@ diff --git a/ring/exceptions.md b/ring/exceptions.md deleted file mode 100644 index 58b16648..00000000 --- a/ring/exceptions.md +++ /dev/null @@ -1,107 +0,0 @@ -# Exception Handling with Ring - -```clj -[metosin/reitit-middleware "0.4.2"] -``` - -Exceptions thrown in router creation can be [handled with custom exception handler](../basics/error_messages.md). By default, exceptions thrown at runtime from a handler or a middleware are not caught by the `reitit.ring/ring-handler`. A good practise is a have an top-level exception handler to log and format the errors for clients. - -```clj -(require '[reitit.ring.middleware.exception :as exception]) -``` - -### `exception/exception-middleware` - -A preconfigured middleware using `exception/default-handlers`. Catches: - -* Request & response [Coercion](coercion.md) exceptions -* [Muuntaja](https://github.com/metosin/muuntaja) decode exceptions -* Exceptions with `:type` of `:reitit.ring/response`, returning `:response` key from `ex-data`. -* Safely all other exceptions - -```clj -(require '[reitit.ring :as ring]) - -(def app - (ring/ring-handler - (ring/router - ["/fail" (fn [_] (throw (Exception. "fail")))] - {:data {:middleware [exception/exception-middleware]}}))) - -(app {:request-method :get, :uri "/fail"}) -;{:status 500 -; :body {:type "exception" -; :class "java.lang.Exception"}} -``` - -### `exception/create-exception-middleware` - -Creates the exception-middleware with custom options. Takes a map of `identifier => exception request => response` that is used to select the exception handler for the thrown/raised exception identifier. Exception identifier is either a `Keyword` or a Exception Class. - -The following handlers are available by default: - -| key | description -|--------------------------------------|------------- -| `:reitit.ring/response` | value in ex-data key `:response` will be returned -| `:muuntaja/decode` | handle Muuntaja decoding exceptions -| `:reitit.coercion/request-coercion` | request coercion errors (http 400 response) -| `:reitit.coercion/response-coercion` | response coercion errors (http 500 response) -| `::exception/default` | a default exception handler if nothing else matched (default `exception/default-handler`). -| `::exception/wrap` | a 3-arity handler to wrap the actual handler `handler exception request => response` (no default). - -The handler is selected from the options map by exception identifier in the following lookup order: - -1) `:type` of exception ex-data -2) Class of exception -3) `:type` ancestors of exception ex-data -4) Super Classes of exception -5) The ::default handler - -```clj -;; type hierarchy -(derive ::error ::exception) -(derive ::failure ::exception) -(derive ::horror ::exception) - -(defn handler [message exception request] - {:status 500 - :body {:message message - :exception (.getClass exception) - :data (ex-data exception) - :uri (:uri request)}}) - -(def exception-middleware - (exception/create-exception-middleware - (merge - exception/default-handlers - {;; ex-data with :type ::error - ::error (partial handler "error") - - ;; ex-data with ::exception or ::failure - ::exception (partial handler "exception") - - ;; SQLException and all it's child classes - java.sql.SQLException (partial handler "sql-exception") - - ;; override the default handler - ::exception/default (partial handler "default") - - ;; print stack-traces for all exceptions - ::exception/wrap (fn [handler e request] - (println "ERROR" (pr-str (:uri request))) - (handler e request))}))) - -(def app - (ring/ring-handler - (ring/router - ["/fail" (fn [_] (throw (ex-info "fail" {:type ::failue})))] - {:data {:middleware [exception-middleware]}}))) - -(app {:request-method :get, :uri "/fail"}) -; ERROR "/fail" -; => {:status 500, -; :body {:message "default" -; :exception clojure.lang.ExceptionInfo -; :data {:type :user/failue} -; :uri "/fail"}} -``` diff --git a/ring/index.html b/ring/index.html deleted file mode 100644 index 6e86c752..00000000 --- a/ring/index.html +++ /dev/null @@ -1,848 +0,0 @@ - - - - - - - Ring · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                    -
                                    - - - - - - - - -
                                    - -
                                    - -
                                    - - - - - - - - - - -
                                    - - - - - - - - - - - - - - -
                                    - - -
                                    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ring/middleware_registry.html b/ring/middleware_registry.html index 6c7ea377..18403684 100644 --- a/ring/middleware_registry.html +++ b/ring/middleware_registry.html @@ -892,7 +892,7 @@ diff --git a/ring/parameter_coercion.html b/ring/parameter_coercion.html deleted file mode 100644 index f9888131..00000000 --- a/ring/parameter_coercion.html +++ /dev/null @@ -1,596 +0,0 @@ - - - - - - - Parameter coercion · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                    -
                                    - - - - - - - - -
                                    - -
                                    - -
                                    - - - - - - - - -
                                    -
                                    - -
                                    -
                                    - -
                                    - -

                                    Parameter coercion

                                    -

                                    Reitit provides pluggable parameter coercion via reitit.ring.coercion.protocol/Coercion protocol, originally introduced in compojure-api. Reitit ships with reitit.ring.coercion.spec/SpecCoercion providing implemenation for clojure.spec and data-specs.

                                    -

                                    NOTE: Before Clojure 1.9.0 is shipped, to use the spec-coercion, one needs to add the following dependencies manually to the project:

                                    -
                                    [org.clojure/clojure "1.9.0-beta2"]
                                    -[org.clojure/spec.alpha "0.1.123"]
                                    -[metosin/spec-tools "0.4.0"]
                                    -
                                    -

                                    Ring request and response coercion

                                    -

                                    To use Coercion with Ring, one needs to do the following:

                                    -
                                      -
                                    1. Define parameters and responses as data into route data, in format adopted from ring-swagger:
                                        -
                                      • :parameters map, with submaps for different parameters: :query, :body, :form, :header and :path. Parameters are defined in the format understood by the Coercion.
                                      • -
                                      • :responses map, with response status codes as keys (or :default for "everything else") with maps with :schema and optionally :description as values.
                                      • -
                                      -
                                    2. -
                                    3. Define a Coercion to route data under :coercion
                                    4. -
                                    5. Mount request & response coercion middleware to the routes (recommended to mount to all routes under router as they mounted only to routes which have the parameters / responses defined):
                                        -
                                      • reitit.ring.coercion/gen-wrap-coerce-parameters
                                      • -
                                      • gen-wrap-coerce-parameters/gen-wrap-coerce-responses
                                      • -
                                      -
                                    6. -
                                    -

                                    If the request coercion succeeds, the coerced parameters are injected into request under :parameters.

                                    -

                                    If either request or response coercion fails, an descriptive error is thrown.

                                    -

                                    Example with data-specs

                                    -
                                    (require '[reitit.ring :as ring])
                                    -(require '[reitit.ring.coercion :as coercion])
                                    -(require '[reitit.ring.coercion.spec :as spec])
                                    -
                                    -(def app
                                    -  (ring/ring-handler
                                    -    (ring/router
                                    -      ["/api"
                                    -       ["/ping" {:parameters {:body {:x int?, :y int?}}
                                    -                 :responses {200 {:schema {:total pos-int?}}}
                                    -                 :get {:handler (fn [{{{:keys [x y]} :body} :parameters}]
                                    -                                  {:status 200
                                    -                                   :body {:total (+ x y)}})}}]]
                                    -      {:data {:middleware [coercion/gen-wrap-coerce-parameters
                                    -                           coercion/gen-wrap-coerce-response]
                                    -              :coercion spec/coercion}})))
                                    -
                                    -
                                    (app
                                    -  {:request-method :get
                                    -   :uri "/api/ping"
                                    -   :body-params {:x 1, :y 2}})
                                    -; {:status 200, :body {:total 3}}
                                    -
                                    -

                                    Example with specs

                                    -

                                    Currently, clojure.spec doesn't support runtime transformations via conforming, so one needs to wrap all specs with spec-tools.core/spec.

                                    -
                                    (require '[reitit.ring :as ring])
                                    -(require '[reitit.ring.coercion :as coercion])
                                    -(require '[reitit.ring.coercion.spec :as spec])
                                    -(require '[clojure.spec.alpha :as s])
                                    -(require '[spec-tools.core :as st])
                                    -
                                    -(s/def ::x (st/spec int?))
                                    -(s/def ::y (st/spec int?))
                                    -(s/def ::total int?)
                                    -(s/def ::request (s/keys :req-un [::x ::y]))
                                    -(s/def ::response (s/keys :req-un [::total]))
                                    -
                                    -(def app
                                    -  (ring/ring-handler
                                    -    (ring/router
                                    -      ["/api"
                                    -       ["/ping" {:parameters {:body ::request}
                                    -                 :responses {200 {:schema ::response}}
                                    -                 :get {:handler (fn [{{{:keys [x y]} :body} :parameters}]
                                    -                                  {:status 200
                                    -                                   :body {:total (+ x y)}})}}]]
                                    -      {:data {:middleware [coercion/gen-wrap-coerce-parameters
                                    -                           coercion/gen-wrap-coerce-response]
                                    -              :coercion spec/coercion}})))
                                    -
                                    -
                                    (app
                                    -  {:request-method :get
                                    -   :uri "/api/ping"
                                    -   :body-params {:x 1, :y 2}})
                                    -; {:status 200, :body {:total 3}}
                                    -
                                    - - -
                                    - -
                                    -
                                    -
                                    - -

                                    results matching ""

                                    -
                                      - -
                                      -
                                      - -

                                      No results matching ""

                                      - -
                                      -
                                      -
                                      - -
                                      -
                                      - -
                                      - - - - - - - - - - - - - - -
                                      - - -
                                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ring/reverse_routing.html b/ring/reverse_routing.html index 99350003..598a5549 100644 --- a/ring/reverse_routing.html +++ b/ring/reverse_routing.html @@ -877,7 +877,7 @@ diff --git a/ring/ring.html b/ring/ring.html index 2ad6624b..b4b363c4 100644 --- a/ring/ring.html +++ b/ring/ring.html @@ -1021,7 +1021,7 @@ diff --git a/ring/route_data_validation.html b/ring/route_data_validation.html index 9a5cb532..a7799bb1 100644 --- a/ring/route_data_validation.html +++ b/ring/route_data_validation.html @@ -1089,7 +1089,7 @@ diff --git a/ring/slash_handler.html b/ring/slash_handler.html index 400a7e3e..0fe6fdd0 100644 --- a/ring/slash_handler.html +++ b/ring/slash_handler.html @@ -915,7 +915,7 @@ diff --git a/ring/slash_handler.md b/ring/slash_handler.md deleted file mode 100644 index 76c0ad49..00000000 --- a/ring/slash_handler.md +++ /dev/null @@ -1,64 +0,0 @@ -# Slash handler - -The router works with precise matches. If a route is defined without a trailing slash, for example, it won't match a request with a slash. - -```clj -(require '[reitit.ring :as ring]) - -(def app - (ring/ring-handler - (ring/router - ["/ping" (constantly {:status 200, :body ""})]))) - -(app {:uri "/ping/"}) -; nil -``` - -Sometimes it is desirable that paths with and without a trailing slash are recognized as the same. - -Setting the `redirect-trailing-slash-handler` as a second argument to `ring-handler`: - -```clj -(def app - (ring/ring-handler - (ring/router - [["/ping" (constantly {:status 200, :body ""})] - ["/pong/" (constantly {:status 200, :body ""})]]) - (ring/redirect-trailing-slash-handler))) - -(app {:uri "/ping/"}) -; {:status 308, :headers {"Location" "/ping"}, :body ""} -(app {:uri "/pong"}) -; {:status 308, :headers {"Location" "/pong/"}, :body ""} -``` - -`redirect-trailing-slash-handler` accepts an optional `:method` parameter that allows configuring how (whether) to handle missing/extra slashes. The default is to handle both. - -```clj -(def app - (ring/ring-handler - (ring/router - [["/ping" (constantly {:status 200, :body ""})] - ["/pong/" (constantly {:status 200, :body ""})]]) - ; only handle extra trailing slash - (ring/redirect-trailing-slash-handler {:method :strip}))) - -(app {:uri "/ping/"}) -; {:status 308, :headers {"Location" "/ping"}, :body ""} -(app {:uri "/pong"}) -; nil -``` -```clj -(def app - (ring/ring-handler - (ring/router - [["/ping" (constantly {:status 200, :body ""})] - ["/pong/" (constantly {:status 200, :body ""})]]) - ; only handle missing trailing slash - (ring/redirect-trailing-slash-handler {:method :add}))) - -(app {:uri "/ping/"}) -; nil -(app {:uri "/pong"}) -; {:status 308, :headers {"Location" "/pong/"}, :body ""} -``` diff --git a/ring/static.html b/ring/static.html index 7f14d1ce..49414fbb 100644 --- a/ring/static.html +++ b/ring/static.html @@ -917,7 +917,7 @@ diff --git a/ring/swagger.html b/ring/swagger.html index 7567088f..2d72162a 100644 --- a/ring/swagger.html +++ b/ring/swagger.html @@ -1141,7 +1141,7 @@ see the next example diff --git a/ring/transforming_middleware_chain.html b/ring/transforming_middleware_chain.html index c9365709..5ca6605d 100644 --- a/ring/transforming_middleware_chain.html +++ b/ring/transforming_middleware_chain.html @@ -898,7 +898,7 @@ diff --git a/ring/transforming_middleware_chain.md b/ring/transforming_middleware_chain.md deleted file mode 100644 index 6179bffb..00000000 --- a/ring/transforming_middleware_chain.md +++ /dev/null @@ -1,37 +0,0 @@ -# Transformation Middleware Chain - -There is an extra option in ring-router (actually, in the underlying middleware-router): `:reitit.middleware/transform` to transform the middleware chain per endpoint. It gets the vector of compiled middleware and should return a new vector of middleware. - -## Adding debug middleware between all other middleware - -```clj -(def app - (ring/ring-handler - (ring/router - ["/api" {:middleware [[wrap 1] [wrap2 2]]} - ["/ping" {:get {:middleware [[wrap3 3]] - :handler handler}}]] - {::middleware/transform #(interleave % (repeat [wrap :debug]))}))) -``` - -```clj -(app {:request-method :get, :uri "/api/ping"}) -; {:status 200, :body [1 :debug 2 :debug 3 :debug :handler]} -``` - -## Reversing the middleware chain - -```clj -(def app - (ring/ring-handler - (ring/router - ["/api" {:middleware [[wrap 1] [wrap2 2]]} - ["/ping" {:get {:middleware [[wrap3 3]] - :handler handler}}]] - {::middleware/transform reverse)}))) -``` - -```clj -(app {:request-method :get, :uri "/api/ping"}) -; {:status 200, :body [3 2 1 :handler]} -``` diff --git a/route_conflicts.html b/route_conflicts.html deleted file mode 100644 index cc1ce151..00000000 --- a/route_conflicts.html +++ /dev/null @@ -1,528 +0,0 @@ - - - - - - - Route conflicts · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                      -
                                      - - - - - - - - -
                                      - -
                                      - -
                                      - - - - - - - - -
                                      -
                                      - -
                                      -
                                      - -
                                      - -

                                      Route conflicts

                                      -

                                      Many routing libraries allow single path lookup could match multiple routes. Usually, first match is used. This is not good, especially if route tree is merged from multiple sources - routes might regress to be unreachable without a warning.

                                      -

                                      Reitit resolves this by running explicit conflicit resolution when a Router is created. Conflicting routes are passed into a :conflicts callback. Default implementation throws ex-info with a descriptive message.

                                      -

                                      Examples routes with conflicts:

                                      -
                                      (require '[reitit.core :as reitit])
                                      -
                                      -(def routes
                                      -  [["/ping"]
                                      -   ["/:user-id/orders"]
                                      -   ["/bulk/:bulk-id"]
                                      -   ["/public/*path"]
                                      -   ["/:version/status"]])
                                      -
                                      -

                                      By default, ExceptionInfo is thrown:

                                      -
                                      (reitit/router routes)
                                      -; CompilerException clojure.lang.ExceptionInfo: Router contains conflicting routes:
                                      -;
                                      -;    /:user-id/orders
                                      -; -> /public/*path
                                      -; -> /bulk/:bulk-id
                                      -;
                                      -;    /bulk/:bulk-id
                                      -; -> /:version/status
                                      -;
                                      -;    /public/*path
                                      -; -> /:version/status
                                      -;
                                      -
                                      -

                                      Just logging the conflicts:

                                      -
                                      (reitit/router
                                      -  routes
                                      -  {:conflicts (comp println reitit/conflicts-str)})
                                      -; Router contains conflicting routes:
                                      -;
                                      -;    /:user-id/orders
                                      -; -> /public/*path
                                      -; -> /bulk/:bulk-id
                                      -;
                                      -;    /bulk/:bulk-id
                                      -; -> /:version/status
                                      -;
                                      -;    /public/*path
                                      -; -> /:version/status
                                      -;
                                      -
                                      - - -
                                      - -
                                      -
                                      -
                                      - -

                                      results matching ""

                                      -
                                        - -
                                        -
                                        - -

                                        No results matching ""

                                        - -
                                        -
                                        -
                                        - -
                                        -
                                        - -
                                        - - - - - - - - - - -
                                        - - -
                                        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/route_validation.html b/route_validation.html deleted file mode 100644 index 71b18a85..00000000 --- a/route_validation.html +++ /dev/null @@ -1,644 +0,0 @@ - - - - - - - Route Validation · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                        -
                                        - - - - - - - - -
                                        - -
                                        - -
                                        - - - - - - - - -
                                        -
                                        - -
                                        -
                                        - -
                                        - -

                                        Route validation

                                        -

                                        Namespace reitit.spec contains clojure.spec definitions for raw-routes, routes, router and router options.

                                        -

                                        NOTE: Use of specs requires to use one of the following:

                                        -
                                          -
                                        • [org.clojure/clojurescript "1.9.660"]
                                        • -
                                        • [org.clojure/clojure "1.9.0-alpha19"]
                                        • -
                                        • [clojure-future-spec "1.9.0-alpha17"] (Clojure 1.8)
                                        • -
                                        -

                                        At runtime

                                        -

                                        If route trees are generated at runtime (e.g. from external source like the database), one can use directly the clojure.spec functions.

                                        -
                                        (require '[clojure.spec.alpha :as s])
                                        -(require '[reitit.spec :as spec])
                                        -
                                        -(def routes-from-db
                                        -  ["tenant1" ::tenant1])
                                        -
                                        -(s/valid? ::spec/raw-routes routes-from-db)
                                        -; false
                                        -
                                        -(s/explain ::spec/raw-routes routes-from-db)
                                        -; In: [0] val: "tenant1" fails spec: :reitit.spec/path at: [:route :path] predicate: (or (blank? %) (starts-with? % "/"))
                                        -; In: [0] val: "tenant1" fails spec: :reitit.spec/raw-route at: [:routes] predicate: (cat :path :reitit.spec/path :arg (? :reitit.spec/arg) :childs (* (and (nilable :reitit.spec/raw-route))))
                                        -; In: [1] val: :user/tenant1 fails spec: :reitit.spec/raw-route at: [:routes] predicate: (cat :path :reitit.spec/path :arg (? :reitit.spec/arg) :childs (* (and (nilable :reitit.spec/raw-route))))
                                        -; :clojure.spec.alpha/spec  :reitit.spec/raw-routes
                                        -; :clojure.spec.alpha/value  ["tenant1" :user/tenant1]
                                        -
                                        -

                                        At development time

                                        -

                                        reitit.core/router can be instrumented and use something like expound to pretty-print the spec problems.

                                        -

                                        First add a :dev dependency to:

                                        -
                                        [expound "0.3.0"]
                                        -
                                        -

                                        Some bootstrapping:

                                        -
                                        (require '[clojure.spec.test.alpha :as stest])
                                        -(require '[expound.alpha :as expound])
                                        -(require '[clojure.spec.alpha :as s])
                                        -(require '[reitit.spec])
                                        -
                                        -(stest/instrument `reitit/router)
                                        -(set! s/*explain-out* expound/printer)
                                        -
                                        -

                                        And we are ready to go:

                                        -
                                        
                                        -(reitit/router
                                        -  ["/api"
                                        -   ["/public"
                                        -    ["/ping"]
                                        -    ["pong"]]])
                                        -
                                        -; CompilerException clojure.lang.ExceptionInfo: Call to #'reitit.core/router did not conform to spec:
                                        -;
                                        -; -- Spec failed --------------------
                                        -;
                                        -; Function arguments
                                        -;
                                        -; (["/api" ...])
                                        -;   ^^^^^^
                                        -;
                                        -;     should satisfy
                                        -;
                                        -; (clojure.spec.alpha/cat
                                        -;   :path
                                        -;   :reitit.spec/path
                                        -;   :arg
                                        -;   (clojure.spec.alpha/? :reitit.spec/arg)
                                        -;   :childs
                                        -;   (clojure.spec.alpha/*
                                        -;     (clojure.spec.alpha/and
                                        -;       (clojure.spec.alpha/nilable :reitit.spec/raw-route))))
                                        -;
                                        -; or
                                        -;
                                        -; (clojure.spec.alpha/cat
                                        -;   :path
                                        -;   :reitit.spec/path
                                        -;   :arg
                                        -;   (clojure.spec.alpha/? :reitit.spec/arg)
                                        -;   :childs
                                        -;   (clojure.spec.alpha/*
                                        -;     (clojure.spec.alpha/and
                                        -;       (clojure.spec.alpha/nilable :reitit.spec/raw-route))))
                                        -;
                                        -; -- Relevant specs -------
                                        -;
                                        -; :reitit.spec/raw-route:
                                        -; (clojure.spec.alpha/cat
                                        -;   :path
                                        -;   :reitit.spec/path
                                        -;   :arg
                                        -;   (clojure.spec.alpha/? :reitit.spec/arg)
                                        -;   :childs
                                        -;   (clojure.spec.alpha/*
                                        -;     (clojure.spec.alpha/and
                                        -;       (clojure.spec.alpha/nilable :reitit.spec/raw-route))))
                                        -; :reitit.spec/raw-routes:
                                        -; (clojure.spec.alpha/or
                                        -;   :route
                                        -;   :reitit.spec/raw-route
                                        -;   :routes
                                        -;   (clojure.spec.alpha/coll-of :reitit.spec/raw-route :into []))
                                        -;
                                        -; -- Spec failed --------------------
                                        -;
                                        -; Function arguments
                                        -;
                                        -; ([... [... ... ["pong"]]])
                                        -;                 ^^^^^^
                                        -;
                                        -;     should satisfy
                                        -;
                                        -; (fn
                                        -;   [%]
                                        -;   (or
                                        -;     (clojure.string/blank? %)
                                        -;     (clojure.string/starts-with? % "/")))
                                        -;
                                        -; or
                                        -;
                                        -; (fn
                                        -;   [%]
                                        -;   (or
                                        -;     (clojure.string/blank? %)
                                        -;     (clojure.string/starts-with? % "/")))
                                        -;
                                        -; -- Relevant specs -------
                                        -;
                                        -; :reitit.spec/path:
                                        -; (clojure.spec.alpha/and
                                        -;   clojure.core/string?
                                        -;   (clojure.core/fn
                                        -;     [%]
                                        -;     (clojure.core/or
                                        -;       (clojure.string/blank? %)
                                        -;       (clojure.string/starts-with? % "/"))))
                                        -; :reitit.spec/raw-route:
                                        -; (clojure.spec.alpha/cat
                                        -;   :path
                                        -;   :reitit.spec/path
                                        -;   :arg
                                        -;   (clojure.spec.alpha/? :reitit.spec/arg)
                                        -;   :childs
                                        -;   (clojure.spec.alpha/*
                                        -;     (clojure.spec.alpha/and
                                        -;       (clojure.spec.alpha/nilable :reitit.spec/raw-route))))
                                        -; :reitit.spec/raw-routes:
                                        -; (clojure.spec.alpha/or
                                        -;   :route
                                        -;   :reitit.spec/raw-route
                                        -;   :routes
                                        -;   (clojure.spec.alpha/coll-of :reitit.spec/raw-route :into []))
                                        -;
                                        -; -------------------------
                                        -; Detected 2 errors
                                        -
                                        -

                                        Validating route data

                                        -

                                        TODO

                                        - - -
                                        - -
                                        -
                                        -
                                        - -

                                        results matching ""

                                        -
                                          - -
                                          -
                                          - -

                                          No results matching ""

                                          - -
                                          -
                                          -
                                          - -
                                          -
                                          - -
                                          - - - - - - - - - - - - - - -
                                          - - -
                                          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/routing/route_conflicts.html b/routing/route_conflicts.html deleted file mode 100644 index 044f8de0..00000000 --- a/routing/route_conflicts.html +++ /dev/null @@ -1,433 +0,0 @@ - - - - - - - Route conflicts · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                          -
                                          - - - - - - - - -
                                          - -
                                          - -
                                          - - - - - - - - -
                                          -
                                          - -
                                          -
                                          - -
                                          - -

                                          Route conflicts

                                          -

                                          Route trees should not have multiple routes that match to a single (request) path. router checks the route tree at creation for conflicts and calls a registered :conflicts option callback with the found conflicts. Default implementation throws ex-info with a descriptive message.

                                          -
                                          (reitit/router
                                          -  [["/ping"]
                                          -   ["/:user-id/orders"]
                                          -   ["/bulk/:bulk-id"]
                                          -   ["/public/*path"]
                                          -   ["/:version/status"]])
                                          -; CompilerException clojure.lang.ExceptionInfo: router contains conflicting routes:
                                          -;
                                          -;    /:user-id/orders
                                          -; -> /public/*path
                                          -; -> /bulk/:bulk-id
                                          -;
                                          -;    /bulk/:bulk-id
                                          -; -> /:version/status
                                          -;
                                          -;    /public/*path
                                          -; -> /:version/status
                                          -;
                                          -
                                          - - -
                                          - -
                                          -
                                          -
                                          - -

                                          results matching ""

                                          -
                                            - -
                                            -
                                            - -

                                            No results matching ""

                                            - -
                                            -
                                            -
                                            - -
                                            -
                                            - -
                                            - - - - - - - - - - - - - - -
                                            - - -
                                            - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/routing/route_metadata.html b/routing/route_metadata.html deleted file mode 100644 index ab7e8862..00000000 --- a/routing/route_metadata.html +++ /dev/null @@ -1,455 +0,0 @@ - - - - - - - Route metadata · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                            -
                                            - - - - - - - - -
                                            - -
                                            - -
                                            - - - - - - - - -
                                            -
                                            - -
                                            -
                                            - -
                                            - -

                                            Route meta-data

                                            -

                                            Routes can have arbitrary meta-data. For nested routes, the meta-data is accumulated from root towards leafs using meta-merge.

                                            -

                                            A router based on nested route tree:

                                            -
                                            (def router
                                            -  (reitit/router
                                            -    ["/api" {:interceptors [::api]}
                                            -     ["/ping" ::ping]
                                            -     ["/admin" {:roles #{:admin}}
                                            -      ["/users" ::users]
                                            -      ["/db" {:interceptors [::db]
                                            -              :roles ^:replace #{:db-admin}}
                                            -       ["/:db" {:parameters {:db String}}
                                            -        ["/drop" ::drop-db]
                                            -        ["/stats" ::db-stats]]]]]))
                                            -
                                            -

                                            Resolved route tree:

                                            -
                                            (reitit/routes router)
                                            -; [["/api/ping" {:interceptors [::api]
                                            -;                :name ::ping}]
                                            -;  ["/api/admin/users" {:interceptors [::api]
                                            -;                       :roles #{:admin}
                                            -;                       :name ::users}]
                                            -;  ["/api/admin/db/:db/drop" {:interceptors [::api ::db]
                                            -;                             :roles #{:db-admin}
                                            -;                             :parameters {:db String}
                                            -;                             :name ::drop-db}]
                                            -;  ["/api/admin/db/:db/stats" {:interceptors [::api ::db]
                                            -;                              :roles #{:db-admin}
                                            -;                              :parameters {:db String}
                                            -;                              :name ::db-stats}]]
                                            -
                                            -

                                            Path-based routing:

                                            -
                                            (reitit/match-by-path router "/api/admin/users")
                                            -; #Match{:template "/api/admin/users"
                                            -;        :meta {:interceptors [::api]
                                            -;               :roles #{:admin}
                                            -;               :name ::users}
                                            -;        :result nil
                                            -;        :params {}
                                            -;        :path "/api/admin/users"}
                                            -
                                            -

                                            On match, route meta-data is returned and can interpreted by the application.

                                            -

                                            Routers also support meta-data compilation enabling things like fast Ring or Pedestal -style handlers. Compilation results are found under :result in the match. See configuring routers for details.

                                            - - -
                                            - -
                                            -
                                            -
                                            - -

                                            results matching ""

                                            -
                                              - -
                                              -
                                              - -

                                              No results matching ""

                                              - -
                                              -
                                              -
                                              - -
                                              -
                                              - -
                                              - - - - - - - - - - - - - - -
                                              - - -
                                              - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/routing/route_syntax.html b/routing/route_syntax.html deleted file mode 100644 index caf59862..00000000 --- a/routing/route_syntax.html +++ /dev/null @@ -1,435 +0,0 @@ - - - - - - - Route syntax · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                              -
                                              - - - - - - - - -
                                              - -
                                              - -
                                              - - - - - - - - -
                                              -
                                              - -
                                              -
                                              - -
                                              - -

                                              Route Syntax

                                              -

                                              Routes are defined as vectors, which String path, optional (non-vector) route argument and optional child routes. Routes can be wrapped in vectors.

                                              -

                                              Simple route:

                                              -
                                              ["/ping"]
                                              -
                                              -

                                              Two routes:

                                              -
                                              [["/ping"]
                                              - ["/pong"]]
                                              -
                                              -

                                              Routes with meta-data:

                                              -
                                              [["/ping" ::ping]
                                              - ["/pong" {:name ::pong}]]
                                              -
                                              -

                                              Routes with path and catch-all parameters:

                                              -
                                              [["/users/:user-id"]
                                              - ["/public/*path"]]
                                              -
                                              -

                                              Nested routes with meta-data:

                                              -
                                              ["/api"
                                              - ["/admin" {:middleware [::admin]}
                                              -  ["/user" ::user]
                                              -  ["/db" ::db]
                                              - ["/ping" ::ping]]
                                              -
                                              -

                                              Same routes flattened:

                                              -
                                              [["/api/admin/user" {:middleware [::admin], :name ::user}
                                              - ["/api/admin/db" {:middleware [::admin], :name ::db}
                                              - ["/api/ping" ::ping]]
                                              -
                                              - - -
                                              - -
                                              -
                                              -
                                              - -

                                              results matching ""

                                              -
                                                - -
                                                -
                                                - -

                                                No results matching ""

                                                - -
                                                -
                                                -
                                                - -
                                                -
                                                - -
                                                - - - - - - - - - - -
                                                - - -
                                                - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/routing/routers.html b/routing/routers.html deleted file mode 100644 index d81044c0..00000000 --- a/routing/routers.html +++ /dev/null @@ -1,471 +0,0 @@ - - - - - - - Routers · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                                -
                                                - - - - - - - - -
                                                - -
                                                - -
                                                - - - - - - - - -
                                                -
                                                - -
                                                -
                                                - -
                                                - -

                                                Routers

                                                -

                                                For routing, a Router is needed. Reitit ships with several different router implementations: :linear-router, :lookup-router and :mixed-router, based on the awesome Pedestal implementation.

                                                -

                                                Router is created with reitit.core/router, which takes routes and optional options map as arguments. The route tree gets expanded, optionally coerced and compiled. Actual Router implementation is selected automatically but can be defined with a :router option. Router support both path- and name-based lookups.

                                                -

                                                Creating a router:

                                                -
                                                (require '[reitit.core :as reitit])
                                                -
                                                -(def router
                                                -  (reitit/router
                                                -    [["/api"
                                                -      ["/ping" ::ping]
                                                -      ["/user/:id" ::user]]]))
                                                -
                                                -

                                                :mixed-router is created (both static & wild routes are found):

                                                -
                                                (reitit/router-name router)
                                                -; :mixed-router
                                                -
                                                -

                                                The expanded routes:

                                                -
                                                (reitit/routes router)
                                                -; [["/api/ping" {:name :user/ping}]
                                                -;  ["/api/user/:id" {:name :user/user}]]
                                                -
                                                -

                                                Route names:

                                                -
                                                (reitit/route-names router)
                                                -; [:user/ping :user/user]
                                                -
                                                -

                                                Path-based routing

                                                -
                                                (reitit/match-by-path router "/hello")
                                                -; nil
                                                -
                                                -(reitit/match-by-path router "/api/user/1")
                                                -; #Match{:template "/api/user/:id"
                                                -;        :meta {:name :user/user}
                                                -;        :path "/api/user/1"
                                                -;        :result nil
                                                -;        :params {:id "1"}}
                                                -
                                                -

                                                Name-based (reverse) routing

                                                -
                                                (reitit/match-by-name router ::user)
                                                -; #PartialMatch{:template "/api/user/:id",
                                                -;               :meta {:name :user/user},
                                                -;               :result nil,
                                                -;               :params nil,
                                                -;               :required #{:id}}
                                                -
                                                -(reitit/partial-match? (reitit/match-by-name router ::user))
                                                -; true
                                                -
                                                -

                                                Only a partial match. Let's provide the path-parameters:

                                                -
                                                (reitit/match-by-name router ::user {:id "1"})
                                                -; #Match{:template "/api/user/:id"
                                                -;        :meta {:name :user/user}
                                                -;        :path "/api/user/1"
                                                -;        :result nil
                                                -;        :params {:id "1"}}
                                                -
                                                -

                                                There is also a exception throwing version:

                                                -
                                                (reitit/match-by-name! router ::user)
                                                -; ExceptionInfo missing path-params for route /api/user/:id: #{:id}
                                                -
                                                - - -
                                                - -
                                                -
                                                -
                                                - -

                                                results matching ""

                                                -
                                                  - -
                                                  -
                                                  - -

                                                  No results matching ""

                                                  - -
                                                  -
                                                  -
                                                  - -
                                                  -
                                                  - -
                                                  - - - - - - - - - - - - - - -
                                                  - - -
                                                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/swagger.html b/swagger.html deleted file mode 100644 index 78a6a13a..00000000 --- a/swagger.html +++ /dev/null @@ -1,716 +0,0 @@ - - - - - - - Swagger-support · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                                  -
                                                  - - - - - - - - -
                                                  - -
                                                  - -
                                                  - - - - - - - - -
                                                  -
                                                  - -
                                                  -
                                                  - -
                                                  - -

                                                  Swagger

                                                  -

                                                  Reitit supports Swagger to generate route documentation. Documentation is extracted from existing coercion definitions :parameters, :responses and from a set of new doumentation keys.

                                                  -

                                                  Example

                                                  -

                                                  Current reitit-swagger draft (with reitit-ring & data-specs):

                                                  -
                                                  (require '[reitit.ring :as ring])
                                                  -(require '[reitit.ring.swagger :as swagger])
                                                  -(require '[reitit.ring.coercion :as rrc])
                                                  -(require '[reitit.coercion.spec :as spec])
                                                  -
                                                  -(def app
                                                  -  (ring/ring-handler
                                                  -    (ring/router
                                                  -      ["/api"
                                                  -
                                                  -       ;; identify a swagger api
                                                  -       ;; there can be several in a routing tree
                                                  -       {:swagger {:id :math}}
                                                  -
                                                  -       ;; the (undocumented) swagger spec endpoint
                                                  -       ["/swagger.json"
                                                  -        {:get {:no-doc true
                                                  -               :swagger {:info {:title "my-api"}}
                                                  -               :handler (swagger/create-swagger-handler)}}]
                                                  -
                                                  -       ;; the (undocumented) swagger-ui
                                                  -       ;; [org.webjars/swagger-ui "3.13.4"]
                                                  -       ["/docs/*"
                                                  -        {:get {:no-doc true
                                                  -               :handler (ring/create-resource-handler
                                                  -                          {:root "META-INF/resources/webjars/swagger-ui"})}}]
                                                  -
                                                  -       ["/minus"
                                                  -        {:get {:summary "minus"
                                                  -               :parameters {:query {:x int?, :y int?}}
                                                  -               :responses {200 {:body {:total int?}}}
                                                  -               :handler (fn [{{{:keys [x y]} :query} :parameters}]
                                                  -                          {:status 200, :body {:total (- x y)}})}}]
                                                  -
                                                  -       ["/plus"
                                                  -        {:get {:summary "plus"
                                                  -               :parameters {:query {:x int?, :y int?}}
                                                  -               :responses {200 {:body {:total int?}}}
                                                  -               :handler (fn [{{{:keys [x y]} :query} :parameters}]
                                                  -                          {:status 200, :body {:total (+ x y)}})}}]]
                                                  -
                                                  -      {:data {:middleware [rrc/coerce-exceptions-middleware
                                                  -                           rrc/coerce-request-middleware
                                                  -                           rrc/coerce-response-middleware
                                                  -                           ;; provides just route data specs
                                                  -                           swagger/swagger-feature]
                                                  -              :coercion spec/coercion}})))
                                                  -
                                                  - - -
                                                  - -
                                                  -
                                                  -
                                                  - -

                                                  results matching ""

                                                  -
                                                    - -
                                                    -
                                                    - -

                                                    No results matching ""

                                                    - -
                                                    -
                                                    -
                                                    - -
                                                    -
                                                    - -
                                                    - - - - - - - - - - - - - - -
                                                    - - -
                                                    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/validating.html b/validating.html deleted file mode 100644 index 396714db..00000000 --- a/validating.html +++ /dev/null @@ -1,498 +0,0 @@ - - - - - - - Validating route-trees · GitBook - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                                    -
                                                    - - - - - - - - -
                                                    - -
                                                    - -
                                                    - - - - - - - - -
                                                    -
                                                    - -
                                                    -
                                                    - -
                                                    - -

                                                    Validating route-trees

                                                    -

                                                    Namespace reitit.spec contains specs for routes, router and router options.

                                                    -

                                                    To enable spec-validation of router inputs & outputs at development time, one can do the following:

                                                    -
                                                    ; add to dependencies:
                                                    -; [expound "0.3.0"]
                                                    -
                                                    -(require '[clojure.spec.test.alpha :as st])
                                                    -(require '[expound.alpha :as expound])
                                                    -(require '[clojure.spec.alpha :as s])
                                                    -(require '[reitit.spec])
                                                    -
                                                    -(st/instrument `reitit/router)
                                                    -(set! s/*explain-out* expound/printer)
                                                    -
                                                    -(reitit/router
                                                    -  ["/api"
                                                    -   ["/publuc"
                                                    -    ["/ping"]
                                                    -    ["pong"]]])
                                                    -; -- Spec failed --------------------
                                                    -;
                                                    -; ["/api" ...]
                                                    -;  ^^^^^^
                                                    -;
                                                    -;     should satisfy
                                                    -;
                                                    -; (clojure.spec.alpha/cat
                                                    -;   :path
                                                    -;   :reitit.spec/path
                                                    -;   :arg
                                                    -;   (clojure.spec.alpha/? :reitit.spec/arg)
                                                    -;   :childs
                                                    -;   (clojure.spec.alpha/* (clojure.spec.alpha/and :reitit.spec/raw-route)))
                                                    -;
                                                    -; -- Relevant specs -------
                                                    -;
                                                    -; :reitit.spec/raw-route:
                                                    -; (clojure.spec.alpha/cat
                                                    -;   :path
                                                    -;   :reitit.spec/path
                                                    -;   :arg
                                                    -;   (clojure.spec.alpha/? :reitit.spec/arg)
                                                    -;   :childs
                                                    -;   (clojure.spec.alpha/* (clojure.spec.alpha/and :reitit.spec/raw-route)))
                                                    -; :reitit.spec/raw-routes:
                                                    -; (clojure.spec.alpha/or
                                                    -;   :route
                                                    -;   :reitit.spec/raw-route
                                                    -;   :routes
                                                    -;   (clojure.spec.alpha/coll-of :reitit.spec/raw-route :into []))
                                                    -;
                                                    -; -- Spec failed --------------------
                                                    -;
                                                    -; [... [... ... ["pong"]]]
                                                    -;                ^^^^^^
                                                    -;
                                                    -;     should satisfy
                                                    -;
                                                    -; (fn [%] (clojure.string/starts-with? % "/"))
                                                    -;
                                                    -; -- Relevant specs -------
                                                    -;
                                                    -; :reitit.spec/path:
                                                    -; (clojure.spec.alpha/and
                                                    -;   clojure.core/string?
                                                    -;   (clojure.core/fn [%] (clojure.string/starts-with? % "/")))
                                                    -; :reitit.spec/raw-route:
                                                    -; (clojure.spec.alpha/cat
                                                    -;   :path
                                                    -;   :reitit.spec/path
                                                    -;   :arg
                                                    -;   (clojure.spec.alpha/? :reitit.spec/arg)
                                                    -;   :childs
                                                    -;   (clojure.spec.alpha/* (clojure.spec.alpha/and :reitit.spec/raw-route)))
                                                    -; :reitit.spec/raw-routes:
                                                    -; (clojure.spec.alpha/or
                                                    -;   :route
                                                    -;   :reitit.spec/raw-route
                                                    -;   :routes
                                                    -;   (clojure.spec.alpha/coll-of :reitit.spec/raw-route :into []))
                                                    -;
                                                    -; -------------------------
                                                    -; Detected 2 errors
                                                    -
                                                    -

                                                    Validating meta-data

                                                    -

                                                    TODO

                                                    - - -
                                                    - -
                                                    -
                                                    -
                                                    - -

                                                    results matching ""

                                                    -
                                                      - -
                                                      -
                                                      - -

                                                      No results matching ""

                                                      - -
                                                      -
                                                      -
                                                      - -
                                                      -
                                                      - -
                                                      - - - - - - - - - - - - - - -
                                                      - - -
                                                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -