### Start REPL and Server
Source: https://github.com/metosin/reitit/blob/master/examples/buddy-auth/README.md
Instructions for starting the REPL and the server in the example project.
```sh
lein repl
```
```clojure
(start)
```
--------------------------------
### Example Application Setup
Source: https://github.com/metosin/reitit/blob/master/doc/ring/transforming_middleware_chain.md
Sets up a basic Reitit Ring application with middleware applied at different levels. Demonstrates how middleware is composed.
```clojure
(require '[reitit.ring :as ring])
(require '[reitit.middleware :as middleware])
(defn wrap [handler id]
(fn [request]
(handler (update request ::acc (fnil conj []) id))))
(defn handler [{::keys [acc]}]
{:status 200, :body (conj acc :handler)})
(def app
(ring/ring-handler
(ring/router
["/api" {:middleware [[wrap 1] [wrap 2]]}
["/ping" {:get {:middleware [[wrap 3]]
:handler handler}}]])))
(app {:request-method :get, :uri "/api/ping"})
; {:status 200, :body [1 2 3 :handler]}
```
--------------------------------
### Start REPL and Restart Server Examples
Source: https://github.com/metosin/reitit/blob/master/examples/just-coercion-with-ring/README.md
Instructions for starting a REPL and restarting the server with different coercion strategies (naive, schema, spec, data-spec).
```clojure
> lein repl
(require '[example.server :as server])
;; the manually coerced version
(require '[example.naive :as naive])
(server/restart naive/app)
;; schema-coercion
(require '[example.schema :as schema])
(server/restart schema/app)
;; spec-coercion
(require '[example.spec :as spec])
(server/restart spec/app)
;; data-spec-coercion
(require '[example.dspec :as dspec])
(server/restart dspec/app)
```
--------------------------------
### Example Application Setup
Source: https://github.com/metosin/reitit/blob/master/doc/http/transforming_interceptor_chain.md
Sets up a basic Reitit HTTP application with interceptors and a handler. Demonstrates the default interceptor chain execution.
```clojure
(require '[reitit.http :as http])
(require '[reitit.interceptor.sieppari :as sieppari])
(defn interceptor [message]
{:enter (fn [ctx] (update-in ctx [:request :message] (fnil conj []) message))})
(defn handler [req]
{:status 200
:body (select-keys req [:message])})
(def app
(http/ring-handler
(http/router
["/api" {:interceptors [(interceptor 1) (interceptor 2)]}
["/ping" {:get {:interceptors [(interceptor 3)]
:handler handler}}]])
{:executor sieppari/executor}))
(app {:request-method :get, :uri "/api/ping"})
; {:status 200, :body {:message [1 2 3]}}
```
--------------------------------
### Start Reitit Application
Source: https://github.com/metosin/reitit/blob/master/examples/http-swagger/README.md
Start the Reitit application in a REPL environment.
```clojure
> lein repl
(start)
```
--------------------------------
### Full Reitit and Schema Coercion Example
Source: https://github.com/metosin/reitit/blob/master/doc/coercion/coercion.md
This example demonstrates setting up a router with Schema coercion and a function to match paths and apply coercion. It shows both successful and failed coercion scenarios.
```clojure
(require '[reitit.coercion.schema])
(require '[reitit.coercion :as coercion])
(require '[reitit.core :as r])
(require '[schema.core :as s])
(def router
(r/router
["/:company/users/:user-id" {:name ::user-view
:coercion reitit.coercion.schema/coercion
:parameters {:path {:company s/Str
:user-id s/Int}}}]
{:compile coercion/compile-request-coercers}))
(defn match-by-path-and-coerce! [path]
(if-let [match (r/match-by-path router path)]
(assoc match :parameters (coercion/coerce! match))))
(match-by-path-and-coerce! "/metosin/users/123")
; #Match{:template "/:company/users/:user-id",
; :data {:name :user/user-view,
; :coercion <<:schema>>
; :parameters {:path {:company java.lang.String,
; :user-id Int}}},
; :result {:path #object[reitit.coercion$request_coercer$]},
; :path-params {:company "metosin", :user-id "123"},
; :parameters {:path {:company "metosin", :user-id 123}}
; :path "/metosin/users/123"}
(match-by-path-and-coerce! "/metosin/users/ikitommi")
; => ExceptionInfo Request coercion failed...
```
--------------------------------
### HTTPie GET Request Example
Source: https://github.com/metosin/reitit/blob/master/doc/ring/content_negotiation.md
Example of making a GET request to the /xml endpoint using httpie to test forced XML response.
```bash
> http :3000/xml
HTTP/1.1 200 OK
Content-Length: 20
Content-Type: text/xml
Date: Wed, 22 Aug 2018 16:59:58 GMT
Server: Jetty(9.2.21.v20170120)
kukka
```
--------------------------------
### Minimalistic Pedestal Example with Reitit Router
Source: https://github.com/metosin/reitit/blob/master/doc/http/pedestal.md
This example demonstrates how to replace Pedestal's default router with a reitit router. It defines custom interceptors and routes, then configures the Pedestal server to use reitit for routing.
```clojure
; [io.pedestal/pedestal.service "0.5.5"]
; [io.pedestal/pedestal.jetty "0.5.5"]
; [metosin/reitit-pedestal "0.10.1"]
; [metosin/reitit "0.10.1"]
(require '[io.pedestal.http :as server])
(require '[reitit.pedestal :as pedestal])
(require '[reitit.http :as http])
(require '[reitit.ring :as ring])
(defn interceptor [number]
{:enter (fn [ctx] (update-in ctx [:request :number] (fnil + 0) number))})
(def routes
["/api"
{:interceptors [(interceptor 1)]}
["/number"
{:interceptors [(interceptor 10)]
:get {:interceptors [(interceptor 100)]
:handler (fn [req]
{:status 200
:body (select-keys req [:number])})}}]])
(-> {::server/type :jetty
::server/port 3000
::server/join? false
;; no pedestal routes
::server/routes []}
(server/default-interceptors)
;; swap the reitit router
(pedestal/replace-last-interceptor
(pedestal/routing-interceptor
(http/router routes)))
(server/dev-interceptors)
(server/create-server)
(server/start))
```
--------------------------------
### Build Project
Source: https://github.com/metosin/reitit/blob/master/doc/development.md
Run this command to clean and install the project modules.
```bash
./scripts/lein-modules do clean, install
```
--------------------------------
### Start Figwheel Development Server
Source: https://github.com/metosin/reitit/blob/master/examples/frontend-prompt/README.md
Use this command to start the Figwheel development server for the reitit-frontend project. Access the application via the provided localhost URL.
```bash
lein figwheel
```
--------------------------------
### Full Coercion Example with Reitit, Ring, and Schema
Source: https://github.com/metosin/reitit/blob/master/doc/ring/coercion.md
This example demonstrates setting up Reitit with coercion middleware for request and response handling. It includes defining a custom schema, configuring the router with middleware, and defining routes with parameter and response coercion.
```clojure
(require '[reitit.ring.coercion :as rrc])
(require '[reitit.coercion.schema])
(require '[reitit.ring :as ring])
(require '[schema.core :as s])
(def PositiveInt (s/constrained s/Int pos? 'PositiveInt))
(def app
(ring/ring-handler
(ring/router
["/api"
["/ping" {:name ::ping
:get (fn [_]
{:status 200
:body "pong"})}]
["/plus/:z" {:name ::plus
:post {:coercion reitit.coercion.schema/coercion
:parameters {:query {:x s/Int}
:body {:y s/Int}
:path {:z s/Int}}
:responses {200 {:body {:total PositiveInt}}}
:handler (fn [{:keys [parameters]}]
(let [total (+ (-> parameters :query :x)
(-> parameters :body :y)
(-> parameters :path :z))]
{:status 200
:body {:total total}}))}}]]
{:data {:middleware [rrc/coerce-exceptions-middleware
rrc/coerce-request-middleware
rrc/coerce-response-middleware]}})))
```
--------------------------------
### Start reitit-frontend Development Server
Source: https://github.com/metosin/reitit/blob/master/examples/frontend-auth/README.md
Use this command to start the Figwheel development server for reitit-frontend. Access the application at http://localhost:3449.
```clojure
> lein figwheel
```
--------------------------------
### HTTPie POST Request Example
Source: https://github.com/metosin/reitit/blob/master/doc/ring/content_negotiation.md
Example of making a POST request to the /math endpoint using httpie to test content negotiation.
```bash
> http POST :3000/math x:=1 y:=2
HTTP/1.1 200 OK
Content-Length: 11
Content-Type: application/json; charset=utf-8
Date: Wed, 22 Aug 2018 16:59:54 GMT
Server: Jetty(9.2.21.v20170120)
{
"total": 3
}
```
--------------------------------
### Clojure Performance Test Setup
Source: https://github.com/metosin/reitit/blob/master/doc/performance.md
This code block outlines the setup for running performance tests in Clojure, including the REPL command and system specifications. It's important to run tests with your own routing tables for accurate results.
```clojure
;;
;; start repl with `lein perf repl`
;; perf measured with the following setup:
;;
;; Model Name: MacBook Pro
;; Model Identifier: MacBookPro11,3
;; Processor Name: Intel Core i7
;; Processor Speed: 2,5 GHz
;; Number of Processors: 1
;; Total Number of Cores: 4
;; L2 Cache (per Core): 256 KB
;; L3 Cache: 6 MB
;; Memory: 16 GB
;;
```
--------------------------------
### Per-Content-Type Coercions with Multiple Examples
Source: https://github.com/metosin/reitit/blob/master/doc/ring/openapi.md
Defines a route with multiple content types and examples for a GET request. Supports JSON and EDN responses, each with specific schemas and named examples.
```clojure
"/pizza"
{:get {:summary "Fetch a pizza | Multiple content-types, multiple examples"
:responses {200 {:description "Fetch a pizza as json or EDN"
:content {"application/json" {:schema [:map
[:color :keyword]
[:pineapple :boolean]]
:examples {:white {:description "White pizza with pineapple"
:value {:color :white
:pineapple true}}
:red {:description "Red pizza"
:value {:color :red
:pineapple false}}}}
"application/edn" {:schema [:map
[:color :keyword]
[:pineapple :boolean]]
:examples {:red {:description "Red pizza with pineapple"
:value (pr-str {:color :red :pineapple true})}}}}}}
```
--------------------------------
### Basic Router Setup
Source: https://github.com/metosin/reitit/blob/master/doc/basics/route_data_validation.md
A simple Reitit router configuration. This serves as a baseline before validation is introduced.
```clojure
(require '[reitit.core :as r])
(r/router
["/api" {:handler "identity"}])
```
--------------------------------
### Matching with String Parameters
Source: https://github.com/metosin/reitit/blob/master/doc/coercion/coercion.md
This example demonstrates how a path is matched and the resulting `:path-params` are all strings, reflecting the default behavior.
```clojure
(r/match-by-path router "/metosin/users/123")
; #Match{:template "/:company/users/:user-id",
; :data {:name :user/user-view},
; :result nil,
; :path-params {:company "metosin", :user-id "123"},
; :path "/metosin/users/123"}
```
--------------------------------
### Correctly Add Examples to Query Parameters
Source: https://github.com/metosin/reitit/blob/master/doc/ring/openapi.md
When adding examples for query parameters, ensure they are applied to individual parameters, not the surrounding map schema, due to OpenAPI representation limitations.
```clojure
;; Wrong!
{:parameters {:query [:map
{:json-schema/example {:a 1}}
[:a :int]]}}
;; Right!
{:parameters {:query [:map
[:a {:json-schema/example 1} :int]]}}
```
--------------------------------
### Full Example of Middleware Execution Order
Source: https://github.com/metosin/reitit/blob/master/doc/ring/ring.md
A comprehensive example demonstrating the execution order of middleware applied through various methods: top-level, top-level route data, nested route data, and route-specific middleware. This illustrates the combined effect of different middleware application strategies.
```clojure
(def app
(ring/ring-handler
(ring/router
["/api" {:middleware [[wrap :3-parent]]}
["/get" {:get handler
:middleware [[wrap :4-route]]}]]
{:data {:middleware [[wrap :2-top-level-route-data]]}})
nil
{:middleware [[wrap :1-top]]}))
```
--------------------------------
### Example Usage of Programmatic Route Generation
Source: https://github.com/metosin/reitit/blob/master/doc/basics/route_syntax.md
Shows how to call the `cqrs-routes` function with sample actions to produce a route structure.
```clojure
(cqrs-routes
[[:query 'get-user]
[:command 'add-user]
[:command 'add-order]])
; ["/api" {:interceptors [::api ::db]}
; (["/get-user" {:get {:interceptors [get-user]}}]
; ["/add-user" {:post {:interceptors [add-user]}}]
; ["/add-order" {:post {:interceptors [add-order]}}])]
```
--------------------------------
### Run Ring Server from Command Line
Source: https://github.com/metosin/reitit/blob/master/examples/ring-integrant/README.md
Execute this command in your terminal to start the Ring server.
```bash
lein run
```
--------------------------------
### Compojure Dynamic Routing Example
Source: https://github.com/metosin/reitit/blob/master/doc/advanced/composing_routers.md
A basic example of dynamic routing using Compojure's `context` function, provided for performance comparison with Reitit's dynamic routing.
```clojure
(require '[compojure.core :refer [context]])
(def app
(context "/dynamic" [] (constantly :duo)))
(app {:uri "/dynamic/duo" :request-method :get})
; :duo
```
--------------------------------
### Run Ring Server from REPL
Source: https://github.com/metosin/reitit/blob/master/examples/ring-integrant/README.md
Start the Ring server interactively from the Clojure REPL. Ensure you are in the project directory.
```clojure
(go)
```
--------------------------------
### Test Endpoints with httpie
Source: https://github.com/metosin/reitit/blob/master/examples/ring-malli-lite-swagger/README.md
Examples of how to test the application's endpoints using the httpie command-line tool.
```bash
http GET :3000/math/plus x==1 y==20
```
```bash
http POST :3000/math/plus x:=1 y:=20
```
```bash
http GET :3000/swagger.json
```
--------------------------------
### Bidi Route Syntax Example
Source: https://github.com/metosin/reitit/blob/master/doc/faq.md
Illustrates Bidi's route definition syntax, which uses special Clojure syntax for route patterns.
```clojure
(def routes
["/" [["auth/login" :auth/login]
[["auth/recovery/token/" :token] :auth/recovery]
["workspace/" [[[:project-uuid "/" :page-uuid] :workspace/page]]]]])
```
--------------------------------
### Reitit Route Syntax Example
Source: https://github.com/metosin/reitit/blob/master/doc/faq.md
Demonstrates Reitit's route definition syntax, which uses simple path strings and separates them from route data.
```clojure
(def routes
["/auth/login" :auth/login]
["/auth/recovery/token/:token" :auth/recovery]
["/workspace/:project-uuid/:page-uuid" :workspace/page]])
```
--------------------------------
### App Execution Example (Internal Zone)
Source: https://github.com/metosin/reitit/blob/master/doc/ring/route_data_validation.md
Demonstrates executing the configured application with a request to an internal zone. This shows a successful request when roles are not explicitly checked or are implicitly valid.
```clojure
(app {:request-method :get
:uri "/api/zones/admin/ping"})
; in zone :internal
; => {:status 200, :body "ok"}
```
--------------------------------
### Frontend Routing with reitit-frontend
Source: https://context7.com/metosin/reitit/llms.txt
Use reitit.frontend.easy for stateful singleton routing in ClojureScript browser apps. Start the router with `start!`, navigate using `navigate!` and `href`, and access coerced parameters via `match-by-path`.
```clojure
(ns my-app.core
(:require [reitit.frontend :as rf]
[reitit.frontend.easy :as rfe]
[reitit.coercion.spec :as rcs]
[reagent.core :as r]))
(def routes
[["/" {:name ::home :view #'home-page}]
["/users" {:name ::users :view #'users-page}]
["/users/:id" {:name ::user
:view #'user-page
:parameters {:path {:id int?}}
:coercion rcs/coercion}]])
(defonce current-match (r/atom nil))
(defn on-navigate [match _history]
(reset! current-match match))
(defn init! []
(rfe/start!
(rf/router routes)
on-navigate
{:use-fragment false})) ; use HTML5 history (server must serve index.html for all routes)
;; Generate links
(rfe/href ::user {:id 42})
;; => "/users/42"
(rfe/href ::users nil {:page 2 :per-page 20})
;; => "/users?page=2&per-page=20"
;; Navigate programmatically
(rfe/navigate! ::user {:id 42})
(rfe/push-state ::home)
(rfe/replace-state ::users nil {:page 3})
;; Read coerced params in handler
(let [match @current-match]
(-> match :parameters :path :id)) ; integer, not string
;; => 42
```
--------------------------------
### Successful Path Coercion Example
Source: https://github.com/metosin/reitit/blob/master/doc/coercion/clojure_spec_coercion.md
Demonstrates a successful call to `match-by-path-and-coerce!` with a path that matches the defined route and its parameters are coerced correctly.
```clojure
(match-by-path-and-coerce! "/metosin/users/123")
; #Match{:template "/:company/users/:user-id",
; :data {:name :user/user-view,
; :coercion <<:spec>>
; :parameters {:path ::path-params}},
; :result {:path #object[reitit.coercion$request_coercer$]},
; :path-params {:company "metosin", :user-id "123"},
; :parameters {:path {:company "metosin", :user-id 123}}
; :path "/metosin/users/123"}
```
--------------------------------
### Pedestal Route Syntax Example
Source: https://github.com/metosin/reitit/blob/master/doc/faq.md
Shows Pedestal's route definition syntax, which can use keyword arguments or maps for route data.
```clojure
["/api/ping" :get identity :route-name ::ping]
```
--------------------------------
### Define a Simple Ring Router
Source: https://github.com/metosin/reitit/blob/master/doc/ring/ring.md
Create a basic router with a GET handler for the '/ping' path.
```clojure
(require '[reitit.ring :as ring])
(defn handler [_]
{:status 200, :body "ok"})
(def router
(ring/router
["/ping" {:get handler}]))
```
--------------------------------
### Router Configuration with Middleware
Source: https://github.com/metosin/reitit/blob/master/doc/ring/route_data_validation.md
Configure a Reitit router with the `wrap-enforce-roles` middleware. This example shows how the middleware is added to a route group.
```clojure
(def app
(ring/ring-handler
(ring/router
["/api" {:middleware [zone-middleware
wrap-enforce-roles]} ;; <--- added
["/public" {:zone :public}
["/ping" {:get handler}]]
["/internal" {:zone :internal}
["/users" {:get {:handler handler}
:delete {:handler handler}}]]]
{:validate rrs/validate
::rs/explain e/expound-str})))
```
--------------------------------
### Test Ring Endpoints with httpie
Source: https://github.com/metosin/reitit/blob/master/examples/ring-example/README.md
Examples of how to test different Ring endpoints using httpie. Supports plain, schema, data-specs, and specs.
```bash
# Plain
http GET :3000/plain/plus x==1 y==20
http POST :3000/plain/plus x:=1 y:=20
```
```bash
# Schema
http GET :3000/schema/plus x==1 y==20
http POST :3000/schema/plus x:=1 y:=20
```
```bash
# Data-specs
http GET :3000/dspec/plus x==1 y==20
http POST :3000/dspec/plus x:=1 y:=20
```
```bash
# Specs
http GET :3000/spec/plus x==1 y==20
http POST :3000/spec/plus x:=1 y:=20
```
--------------------------------
### Valid Request Example
Source: https://github.com/metosin/reitit/blob/master/doc/ring/coercion.md
Demonstrates a successful request to the '/api/plus' endpoint with correctly formatted query, body, and path parameters, resulting in a 200 OK response.
```clojure
(app {:request-method :post
:uri "/api/plus/3"
:query-params {"x" "1"}
:body-params {:y 2}})
; {:status 200, :body {:total 6}}
```
--------------------------------
### Successful Coercion Example
Source: https://github.com/metosin/reitit/blob/master/doc/coercion/malli_coercion.md
Demonstrates a successful path coercion using the defined router. The output shows the matched route and the correctly coerced parameters.
```clojure
(match-by-path-and-coerce! "/metosin/users/123")
; #Match{:template "/:company/users/:user-id",
; :data {:name :user/user-view,
; :coercion <<:malli>>
; :parameters {:path [:map
; [:company string?]
; [:user-id int?]]}},
; :result {:path #object[reitit.coercion$request_coercer$]},
; :path-params {:company "metosin", :user-id "123"},
; :parameters {:path {:company "metosin", :user-id 123}}
; :path "/metosin/users/123"}
```
--------------------------------
### Slash-Free Routing Examples
Source: https://github.com/metosin/reitit/blob/master/doc/basics/route_syntax.md
Demonstrates routes that do not require explicit slashes, useful for dynamic path structures.
```clojure
[["broker.{customer}.{device}.{*data}" {...}]
["events.{target}.{type}" {...}]]
```
--------------------------------
### Matching Root and Nested Routes
Source: https://github.com/metosin/reitit/blob/master/doc/advanced/composing_routers.md
Examples of matching paths against the composed router, demonstrating both direct static route matches and matches within nested routers like '/beers/lager'.
```clojure
(name-path router "/vodka/russian")
; nil
(name-path router "/gin/napue")
; [:napue]
```
```clojure
(name-path router "/beers/lager")
; [:beers :lager]
(name-path router "/beers/saison")
; nil
```
--------------------------------
### Router with Closed Specs and Missing Required Key
Source: https://github.com/metosin/reitit/blob/master/doc/basics/route_data_validation.md
Uses `spec-tools.spell/closed` to enforce that only defined keys are present. This example fails because the required `:description` key is missing.
```clojure
(require '[clojure.spec.alpha :as s])
(require '[reitit.core :as r])
(require '[reitit.spec :as rs])
(require '[spec-tools.spell :as spell])
(require '[reitit.dev.pretty :as pretty])
(s/def ::description string?)
(r/router
["/api" {:summary "kikka"}]
{:validate rs/validate
:spec (s/merge ::rs/default-data
(s/keys :req-un [::description]))
::rs/wrap spell/closed
:exception pretty/exception})
```
--------------------------------
### Test Middleware Application Order
Source: https://github.com/metosin/reitit/blob/master/doc/ring/data_driven_middleware.md
Verify that the middleware functions are applied in the correct order by inspecting the request context after processing. This example demonstrates the accumulated data from nested middleware.
```clojure
(app {:request-method :get, :uri "/api/ping"})
; {:status 200, :body [1 2 3 :handler]}
```
--------------------------------
### Nested Controllers Example
Source: https://github.com/metosin/reitit/blob/master/doc/frontend/controllers.md
Controllers from nested routes are concatenated. Root controllers start for any route, and nested controllers start/stop based on their parameters.
```clojure
["/" {:controllers [{:start (fn [_] (js/console.log "root start"))}]}
["/item/:id"
{:controllers [{:parameters {:path [:id]}
:start (fn [parameters] (js/console.log "item start" (-> parameters :path :id)))
:stop (fn [parameters] (js/console.log "item stop" (-> parameters :path :id)))}
]}]
```
--------------------------------
### Get Router Name
Source: https://github.com/metosin/reitit/blob/master/doc/advanced/different_routers.md
The router name can be queried from an existing router instance. This example shows the default router name for a given route configuration.
```clojure
(require '[reitit.core :as r])
(def router
(r/router
[["/ping" ::ping]
["/api/:users" ::users]]))
(r/router-name router)
```
--------------------------------
### User API Endpoint with Path Parameter Coercion
Source: https://context7.com/metosin/reitit/llms.txt
An example of a GET endpoint that retrieves user information by ID. It showcases path parameter definition and automatic type coercion from string to integer.
```APIDOC
## GET /api/users/:id
### Description
Retrieves user information based on the provided user ID. The ID is automatically coerced to an integer.
### Method
GET
### Endpoint
/api/users/:id
### Parameters
#### Path Parameters
- **id** (int) - Required - The unique identifier for the user.
### Response
#### Success Response (200)
- **id** (int) - The user's ID.
- **name** (string) - The user's name.
#### Response Example
```json
{
"id": 7,
"name": "Alice"
}
```
```
--------------------------------
### Applying RESTful Form Method Middleware in Reitit
Source: https://github.com/metosin/reitit/blob/master/doc/ring/RESTful_form_methods.md
This example shows how to apply the custom `wrap-hidden-method` middleware within the Reitit Ring handler setup. Ensure `parameters-middleware` and `multipart-middleware` are included before `wrap-hidden-method`.
```clojure
(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
```
--------------------------------
### Install NPM Dependencies for CLJS
Source: https://github.com/metosin/reitit/blob/master/CONTRIBUTING.md
Install Node.js dependencies required for ClojureScript support.
```bash
npm install
```
--------------------------------
### Simple Reitit HTTP Interceptor Example
Source: https://github.com/metosin/reitit/blob/master/doc/http/interceptors.md
Demonstrates setting up an HTTP router with interceptors defined at different levels (global, route, and method). Requires `reitit.ring`, `reitit.http`, and an interceptor executor like `reitit.interceptor.sieppari`.
```clojure
(require '[reitit.ring :as ring])
(require '[reitit.http :as http])
(require '[reitit.interceptor.sieppari :as sieppari])
(defn interceptor [number]
{:enter (fn [ctx] (update-in ctx [:request :number] (fnil + 0) number))})
(def app
(http/ring-handler
(http/router
["/api"
{:interceptors [(interceptor 1)]}
["/number"
{:interceptors [(interceptor 10)]
:get {:interceptors [(interceptor 100)]
:handler (fn [req]
{:status 200
:body (select-keys req [:number])})}}]])
;; the default handler
(ring/create-default-handler)
;; executor
{:executor sieppari/executor}))
(app {:request-method :get, :uri "/"})
; {:status 404, :body "", :headers {}}
(app {:request-method :get, :uri "/api/number"})
; {:status 200, :body {:number 111}}
```
--------------------------------
### Reitit Router with Content Negotiation
Source: https://github.com/metosin/reitit/blob/master/doc/ring/content_negotiation.md
Set up a Reitit Ring router with content negotiation, coercion, and other middlewares. This example demonstrates handling JSON, EDN, and Transit requests and responses, as well as a forced XML response.
```clojure
(require '[reitit.ring :as ring])
(require '[reitit.ring.coercion :as rrc])
(require '[reitit.coercion.spec :as rcs])
(require '[ring.adapter.jetty :as jetty])
(require '[muuntaja.core :as m])
(def app
(ring/ring-handler
(ring/router
(["/math"
{:post {:summary "negotiated request & response (json, edn, transit)"
:parameters {:body {:x int?, :y int?}}
:responses {200 {:body {:total int?}}}
:handler (fn [{{{:keys [x y]} :body} :parameters}]
{:status 200
:body {:total (+ x y)}})}}]
["/xml"
{:get {:summary "forced xml response"
:handler (fn [_]
{:status 200
:headers {"Content-Type" "text/xml"}
:body "kukka"})}}]]
{:data {:muuntaja m/instance
:coercion rcs/coercion
:middleware [muuntaja/format-middleware
rrc/coerce-exceptions-middleware
rrc/coerce-request-middleware
rrc/coerce-response-middleware]}})))
(jetty/run-jetty #'app {:port 3000, :join? false})
```
--------------------------------
### Wildcards with {bracket} Syntax
Source: https://github.com/metosin/reitit/blob/master/doc/basics/route_syntax.md
Examples of using {bracket} path parameters, which can have various terminators.
```clojure
[["/api/{version}" {...}]
["/files/{name}.{extension}" {...}]
["/user/{user-id}/orders" {...}]]
```
--------------------------------
### Get Flattened Routes
Source: https://github.com/metosin/reitit/blob/master/doc/basics/router.md
Inspect the flattened route tree of a router using `r/routes`.
```clojure
(r/routes router)
; [["/api/ping" {:name :user/ping}]
; ["/api/user/:id" {:name :user/user}]]
```
--------------------------------
### Get Router Name
Source: https://github.com/metosin/reitit/blob/master/doc/basics/router.md
Retrieve the name of a created router instance using `r/router-name`.
```clojure
(r/router-name router)
; :mixed-router
```
--------------------------------
### Math Plus Endpoint (GET)
Source: https://github.com/metosin/reitit/blob/master/doc/ring/swagger.md
Performs addition of two integers provided as query parameters.
```APIDOC
## GET /math/plus
### Description
Performs addition of two integers provided as query parameters.
### Method
GET
### Endpoint
/math/plus
### Parameters
#### Query Parameters
- **x** (int) - Required - The first integer.
- **y** (int) - Required - The second integer.
### Request Example
`/math/plus?x=5&y=3`
### Response
#### Success Response (200)
- **total** (int) - The sum of x and y.
#### Response Example
```json
{
"total": 8
}
```
```
--------------------------------
### Full Reitit Ring Application Setup
Source: https://github.com/metosin/reitit/blob/master/doc/ring/swagger.md
This code defines a complete Reitit Ring application, including routing, Swagger generation, Swagger UI integration, and various middleware for request/response handling. It's designed to be served via Jetty.
```clojure
(ns example.server
(:require [reitit.ring :as ring]
[reitit.swagger :as swagger]
[reitit.swagger-ui :as swagger-ui]
[reitit.ring.coercion :as coercion]
[reitit.coercion.spec]
[reitit.ring.middleware.muuntaja :as muuntaja]
[reitit.ring.middleware.exception :as exception]
[reitit.ring.middleware.multipart :as multipart]
[reitit.ring.middleware.parameters :as parameters]
[ring.middleware.params :as params]
[ring.adapter.jetty :as jetty]
[muuntaja.core :as m]
[clojure.java.io :as io]))
(def app
(ring/ring-handler
(ring/router
[["/swagger.json"
{:get {:no-doc true
:swagger {:info {:title "my-api"}
:basePath "/"} ;; prefix for all paths
:handler (swagger/create-swagger-handler)}}]
["/files"
{:swagger {:tags ["files"]}}
["/upload"
{:post {:summary "upload a file"
:parameters {:multipart {:file multipart/temp-file-part}}
:responses {200 {:body {:file multipart/temp-file-part}}}
:handler (fn [{{{:keys [file]} :multipart} :parameters}]
{:status 200
:body {:file file}})}}]
["/download"
{:get {:summary "downloads a file"
:swagger {:produces ["image/png"]}
:handler (fn [_]
{:status 200
:headers {"Content-Type" "image/png"}
:body (io/input-stream (io/resource "reitit.png"))})}}]]
["/math"
{:swagger {:tags ["math"]}}
["/plus"
{:get {:summary "plus with spec query parameters"
:parameters {:query {:x int?, :y int?}}
:responses {200 {:body {:total int?}}}
:handler (fn [{{{:keys [x y]} :query} :parameters}]
{:status 200
:body {:total (+ x y)}})}
:post {:summary "plus with spec body parameters"
:parameters {:body {:x int?, :y int?}}
:responses {200 {:body {:total int?}}}
:handler (fn [{{{:keys [x y]} :body} :parameters}]
{:status 200
:body {:total (+ x y)}})}}]]]
{:data {:coercion reitit.coercion.spec/coercion
:muuntaja m/instance
:middleware [;; query-params & form-params
parameters/parameters-middleware
;; content-negotiation
muuntaja/format-negotiate-middleware
;; encoding response body
muuntaja/format-response-middleware
;; exception handling
exception/exception-middleware
;; decoding request body
muuntaja/format-request-middleware
;; coercing response bodys
coercion/coerce-response-middleware
;; coercing request parameters
coercion/coerce-request-middleware
;; multipart
multipart/multipart-middleware]}})
(ring/routes
(swagger-ui/create-swagger-ui-handler {:path "/"})
(ring/create-default-handler))))
(defn start []
(jetty/run-jetty #'app {:port 3000, :join? false})
(println "server running in port 3000"))
```
--------------------------------
### Get Router Options
Source: https://github.com/metosin/reitit/blob/master/doc/basics/router.md
Access the options map associated with a router instance using `r/options`.
```clojure
(r/options router)
{:lookup #object[...]
:expand #object[...]
:coerce #object[...]
:compile #object[...]
:conflicts #object[...]}
```
--------------------------------
### Create a Ring Router with Handlers and Middleware
Source: https://github.com/metosin/reitit/blob/master/doc/README.md
Set up a Ring-compatible router that includes handlers, middleware, and request method routing. Middleware can be applied at different levels.
```clojure
(require '[reitit.ring :as ring])
(defn handler [_]
{:status 200, :body "ok"})
(defn wrap [handler id]
(fn [request]
(update (handler request) :wrap (fnil conj '()) id)))
(def app
(ring/ring-handler
(ring/router
["/api" {:middleware [[wrap :api]]}
["/ping" {:get handler
:name ::ping}]
["/admin" {:middleware [[wrap :admin]]}
["/users" {:get handler
:post handler}]]])))
```
--------------------------------
### Basic Reitit App with Swagger and Swagger UI
Source: https://github.com/metosin/reitit/blob/master/doc/ring/swagger.md
Sets up a Reitit Ring application with two API routes, a Swagger JSON endpoint, and a Swagger UI endpoint. For production, consider adding content negotiation middleware.
```clojure
(require '[reitit.ring :as ring])
(require '[reitit.swagger :as swagger])
(require '[reitit.swagger-ui :as swagger-ui])
(def app
(ring/ring-handler
(ring/router
[["/api"
["/ping" {:get (constantly {:status 200, :body "ping"})}]
["/pong" {:post (constantly {:status 200, :body "pong"})}]]
["" {:no-doc true}
["/swagger.json" {:get (swagger/create-swagger-handler)}]
["/api-docs/*" {:get (swagger-ui/create-swagger-ui-handler)}]]])))
```
--------------------------------
### Test HTTP Endpoints with httpie
Source: https://github.com/metosin/reitit/blob/master/examples/http-swagger/README.md
Use httpie to test the GET and POST endpoints of the Reitit application.
```bash
http GET :3000/math/plus x==1 y==20
```
```bash
http POST :3000/math/plus x:=1 y:=2
```
```bash
http GET :3000/async results==1 seed==reitit
```
--------------------------------
### Async-ring Request with Sieppari
Source: https://github.com/metosin/reitit/blob/master/doc/http/sieppari.md
Demonstrates how to make an asynchronous Ring request to the Reitit application configured with Sieppari's executor. This example shows how to handle the response using a promise.
```clojure
(let [respond (promise)])
(app {:request-method :get, :uri "/api/ping"} respond nil)
(deref respond 1000 ::timeout))
;enter :api
;enter :ping
;enter :get
;leave :get
;leave :ping
;leave :api
;=> {:status 200, :body "pong"}
```
--------------------------------
### Get Merged Route Tree
Source: https://github.com/metosin/reitit/blob/master/doc/basics/router.md
View the combined and flattened route tree after composing multiple route definitions.
```clojure
(r/routes router)
; [["/admin/ping" {:name :user/ping}]
; ["/admin/db" {:name :user/db}]
; ["/users" {:name :user/users}]
; ["/users/:id" {:name :user/user}]]
```
--------------------------------
### Default Router Creation with Error Handling
Source: https://github.com/metosin/reitit/blob/master/doc/basics/error_messages.md
This snippet demonstrates the default router creation process where all exceptions are caught and formatted by `reitit.core/router` using the default exception formatter.
```clojure
(require '[reitit.core :as r])
(r/router
[["/ping"]
["/:user-id/orders"]
["/bulk/:bulk-id"]
["/public/*path"]
["/:version/status"]])
```
--------------------------------
### Serve Static Assets Internally
Source: https://github.com/metosin/reitit/blob/master/doc/ring/static.md
Use `reitit.ring/create-resource-handler` within a router for non-conflicting paths like `"/assets/*"`. Ensure `reitit.ring` is required.
```clojure
(require '[reitit.ring :as ring])
(ring/ring-handler
(ring/router
[["/ping" (constantly {:status 200, :body "pong"})]
["/assets/*" (ring/create-resource-handler)]])
(ring/create-default-handler))
```
--------------------------------
### Wildcards with :colon Syntax
Source: https://github.com/metosin/reitit/blob/master/doc/basics/route_syntax.md
Examples of using :colon path parameters that must end with a slash or the end of the path string.
```clojure
[["/api/:version" {...}]
["/files/file-:number" {...}]
["/user/:user-id/orders" {...}]]
```
--------------------------------
### Create Release Commit
Source: https://github.com/metosin/reitit/blob/master/doc/development.md
Steps to create a release commit, including setting the version and committing changes.
```bash
# create a release commit
./scripts/set-version "1.0.0"
# !!! update the changelog
git add -u
git commit -m "Release 1.0.0"
# push the commit
git push
```
--------------------------------
### Add Reitit Dependency
Source: https://github.com/metosin/reitit/blob/master/doc/README.md
Include the Reitit library in your project dependencies. This example shows the latest version for all bundled modules.
```clojure
[metosin/reitit "0.10.1"]
```
--------------------------------
### Override Router Implementation
Source: https://github.com/metosin/reitit/blob/master/doc/advanced/different_routers.md
Manually set the router implementation using the `:router` option. This example forces the use of the `:linear-router`.
```clojure
(require '[reitit.core :as r])
(def router
(r/router
[["/ping" ::ping]
["/api/:users" ::users]]
{:router r/linear-router}))
(r/router-name router)
```
--------------------------------
### Create Router with Default Path Conflict Detection
Source: https://github.com/metosin/reitit/blob/master/doc/basics/route_conflicts.md
Attempt to create a router with the default settings. This will throw an exception if path conflicts are detected.
```clojure
(r/router routes)
```
--------------------------------
### Invoke a Ring Handler
Source: https://github.com/metosin/reitit/blob/master/doc/ring/ring.md
Call the generated Ring handler with a request map to get a response. A non-matching request returns nil.
```clojure
(app {:request-method :get, :uri "/favicon.ico"})
; nil
(app {:request-method :get, :uri "/ping"})
; {:status 200, :body "ok"}
```
--------------------------------
### Handle Exact Path Match with Parameters
Source: https://github.com/metosin/reitit/blob/master/doc/basics/path_based_routing.md
Shows how `match-by-path` returns a Match record containing route details and extracted path parameters when a path is an exact match.
```clojure
(r/match-by-path router "/api/user/1")
; #Match{:template "/api/user/:id"
; :data {:name :user/user}
; :path "/api/user/1"
; :result nil
; :path-params {:id "1"}}
```
--------------------------------
### Execute Full Middleware Execution Order Example
Source: https://github.com/metosin/reitit/blob/master/doc/ring/ring.md
Tests the full middleware execution order by making a request to a deeply nested route. Verifies that all middleware, from top-level to route-specific, are applied in the correct sequence.
```clojure
(app {:request-method :get, :uri "/api/get"})
```
```clojure
; {:status 200, :body [:1-top :2-top-level-route-data :3-parent :4-route :handler]}
```
--------------------------------
### Test reitit-ring endpoints with httpie
Source: https://github.com/metosin/reitit/blob/master/examples/ring-malli-swagger/README.md
Use httpie to test GET and POST requests to the /math/plus endpoint and to retrieve the swagger.json specification.
```bash
http GET :3000/math/plus x==1 y==20
http POST :3000/math/plus x:=1 y:=20
http GET :3000/swagger.json
```
--------------------------------
### Retrieving Expanded Routes
Source: https://github.com/metosin/reitit/blob/master/doc/basics/route_data.md
Use `r/routes` to get the fully expanded route data from a router. This is useful for introspection or generating documentation.
```clojure
(r/routes router)
; [["/ping" {:name ::ping}]
; ["/pong" {:handler identity}]
; ["/users" {:get {:roles #{:admin}
; :handler identity}}]]
```
--------------------------------
### Define and Use Middleware in Registry
Source: https://github.com/metosin/reitit/blob/master/doc/ring/middleware_registry.md
Demonstrates how to define a custom middleware and use it via keywords in the router's options and route definitions. The registry is stored under ::middleware/registry.
```clojure
(require '[reitit.ring :as ring])
(require '[reitit.middleware :as middleware])
(defn wrap-bonus [handler value]
(fn [request]
(handler (update request :bonus (fnil + 0) value))))
(def app
(ring/ring-handler
(ring/router
["/api" {:middleware [[:bonus 20]]}
["/bonus" {:middleware [:bonus10]
:get (fn [{:keys [bonus]}]
{:status 200, :body {:bonus bonus}})}]]
{::middleware/registry {:bonus wrap-bonus
:bonus10 [:bonus 10]}})))
```
--------------------------------
### Route with Catch-All Parameter (*path syntax)
Source: https://github.com/metosin/reitit/blob/master/doc/basics/route_syntax.md
Define a route that captures the rest of the path using the *path syntax.
```clojure
["/public/*path" {:handler get-file}]
```
--------------------------------
### Define Route with Controller
Source: https://github.com/metosin/reitit/blob/master/doc/frontend/controllers.md
Add controllers to a route's data using the `:controllers` vector. Specify parameters, start, and stop functions.
```clojure
["/item/:id"
{:controllers [{:parameters {:path [:id]}
:start (fn [parameters] (js/console.log :start (-> parameters :path :id)))
:stop (fn [parameters] (js/console.log :stop (-> parameters :path :id)))}]}]
```
--------------------------------
### Route with Catch-All Parameter ({*path} syntax)
Source: https://github.com/metosin/reitit/blob/master/doc/basics/route_syntax.md
Define a route that captures the rest of the path using the {*path} syntax.
```clojure
["/public/{*path}" {:handler get-file}]
```
--------------------------------
### Annotate Schema Parameters with Schema-Tools
Source: https://github.com/metosin/reitit/blob/master/doc/ring/openapi.md
Use schema-tools to annotate parameters with descriptions, deprecation status, examples, and default values for OpenAPI generation.
```clojure
["/plus"
{:post
{:parameters
{:body {:x (schema-tools.core/schema s/Num {:description "Description for X parameter"
:openapi/deprecated true
:openapi/example 13
:openapi/default 42})
:y int?}}}}]
```
--------------------------------
### Handle Missing Middleware in Registry
Source: https://github.com/metosin/reitit/blob/master/doc/ring/middleware_registry.md
Illustrates how router creation fails with a descriptive error if a middleware keyword used in the routes is not found in the provided registry.
```clojure
(def app
(ring/ring-handler
(ring/router
["/api" {:middleware [[:bonus 20]]}
["/bonus" {:middleware [:bonus10]
:get (fn [{:keys [bonus]}]
{:status 200, :body {:bonus bonus}})}]]
{::middleware/registry {:bonus wrap-bonus}})))
;CompilerException clojure.lang.ExceptionInfo: Middleware :bonus10 not found in registry.
;
;Available middleware in registry:
;
;| :id | :description |
;|--------+--------------------------------------|
;| :bonus | reitit.ring_test$wrap_bonus@59fddabb |
```
--------------------------------
### Serve Swagger UI from Reitit App
Source: https://github.com/metosin/reitit/blob/master/doc/ring/swagger.md
This code demonstrates how to invoke the Reitit application to serve the Swagger UI interface.
```clojure
(app {:request-method :get, :uri "/api-docs/index.html"})
```
--------------------------------
### Customizing Route Expansion with Protocol Extension
Source: https://github.com/metosin/reitit/blob/master/doc/basics/route_data.md
Extend the `r/Expand` protocol to customize how route arguments are expanded. This example adds support for `java.io.File`.
```clojure
(extend-type java.io.File
r/Expand
(expand [file options]
(r/expand
#(slurp file)
options)))
(r/router
["/" (java.io.File. "index.html")])
```