summaryrefslogtreecommitdiff
path: root/README.md
blob: b3c7ba92b07c8f520b522cfee61df666bd16dcc5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# Ruuter

A tiny HTTP router that operates with a simple data structure where each route is a map inside a vector. Yup, that's it. No magic, no bullshit. 

## Installation

[![Clojars Project](https://img.shields.io/clojars/v/org.clojars.askonomm/ruuter.svg)](https://clojars.org/org.clojars.askonomm/ruuter)

## Usage

### Setting up

Require the namespace `ruuter.core` and then pass your routes to the `route` function along with the current request map, like this:

```clojure
(ns myapp.core
  (:require [ruuter.core :as ruuter]))

(def routes [{:path "/"
              :method :get
              :response {:status 200
                         :body "Hi there!"}}])

(def request {:uri "/"
              :request-method :get})

(ruuter/route routes request) ; => {:status 200
                              ;     :body "Hi there!"}
```

This will attempt to match a route with the request map and return the matched route' response. If no route was found, it will attempt to find a route that has a `:path` that is `:not-found`, and return its response instead. But if not even that route was found, it will simply return a built-in 404 response instead.

Note that the `request-method` doesn't have to be a keyword, it can be anything that your HTTP server returns. But it does have to be called `request-method` for the router to know where to look for. 

### Setting up with http-kit

Now, obviously on its own the router is not very useful as it needs an actual HTTP server to return the responses to the world, so here's an example that uses http-kit:

```clojure
(ns myapp.core
  (:require [ruuter.core :as ruuter]
            [org.httpkit.server :as http]))

; The given request map (second argument) will match the
; first route in this example, and return its response.
(def routes [{:path "/"
              :method :get
              :response {:status 200
                         :body "Hi there!"}}
             {:path "/hello/:who"
              :method :get
              :response (fn [req]
                          {:status 200
                           :body (str "Hello, " (:who (:params req)))})}])

(defn -main []
  (http/run-server #(ruuter/route routes %) {:port 8080}))
```

### Creating routes

Like mentioned above, each route is a map inside of a vector - the order is important only in that the route matcher will return the first result it finds according to `:path`. 

Each route consists of three items:

#### `:path`

A string path starting with a forward slash describing the URL path to match. 

To create parameters from the path, prepend a colon (:) in front of a path slice like you would with a Clojure keyword. For example a string such as `/hi/:name` would match any string that matches the `/hi/.*` regex. The `:name` itself will then be available with its value from the `request` passed to the response function, like this:

```clojure
(fn [req]
  (let [name (:name (:params req))]
    {:status 200
     :body (str "Hi, " name)}))
```

#### `:method`

The HTTP method to listen for when matching the given path. This can be whatever the HTTP server uses. For example, if you're using http-kit for the HTTP server then the accepted values are:

- `:get`
- `:post`
- `:put`
- `:delete`
- `:head`
- `:options`
- `:patch`

#### `:response`

The response can be a direct map, or a function returning a map. In case of a function, you will also get passed to you the `request` map that the HTTP server returns, with added-in `:params` that contain the values for the URL parameters you use in your route's `:path`.

Thus, a `:response` can be a map:

```clojure
{:status 200
 :body "Hi there!"}
 ```

Or a function returning a map:

```clojure
(fn [req]
  {:status 200
   :body "Hi there!"})
 ```

What the actual map can contain that you return depends again on the HTTP server you decided to use Ruuter with. The examples I've noted here are based on `http-kit`, but feel free to make a PR with additions for other HTTP servers.

## Changelog

### 1.1.0

- Made Ruuter server-agnostic, which means now it really is just a router and nothing else, and can thus be used with just about any HTTP server you can throw at it. It also means there are now zero dependencies! ZERO!