blob: e646f7e0cc358bf193551d6d28414612fb706fed (
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
|
(ns ruuter.core
(:require [clojure.string :as string]
[org.httpkit.server :as http])
(:gen-class))
(def routes [{:path "/"
:method :get
:response {:status 200
:body "Hello, World."}}
{:path "/some/page/goes/here"
:method :get
:response {:status 200
:body ":)"}}
{:path "/hi/:name"
:method :get
:response (fn [req]
{:status 200
:body (str "Hi, " (:name (:params req)))})}
{:path :not-found
:response {:status 404
:body "Not found."}}])
(defn- path->regex-path
[path]
(if (= "/" path)
path
(->> (string/split path #"/")
(map (fn [piece]
(if (string/starts-with? piece ":")
".*"
piece)))
(string/join "/"))))
(defn- path+uri->path-params
[path uri]
(if (= "/" path)
{}
(let [split-path (string/split path #"/")
split-uri (string/split uri #"/")]
(into {} (map-indexed
(fn [idx item]
(when (string/starts-with? item ":")
{(keyword (subs item 1)) (get split-uri idx)}))
split-path)))))
(defn- match-route
[routes uri request-method]
(->> routes
(filter #(not (= :not-found (:path %))))
(map #(merge % {:regex-path (path->regex-path (:path %))}))
(filter #(and (re-matches (re-pattern (:regex-path %)) uri)
(= (:method %) request-method)))
first))
(defn- route+req->response
[{:keys [path response]} {:keys [uri] :as req}]
(cond
; responses are maps, so there's no reason they can't be
; direct maps.
(map? response)
response
; responses can also be functions that return maps, and
; when using a function, you get the whole `req` and params
; with it as well.
(fn? response)
(response (->> {:params (path+uri->path-params path uri)}
(merge req)))
; if by whatever reason we make it here it must mean the
; route is invalid, or doesn't exist, in which case we return
; an error message.
:else
{:status 404
:body "Not found."}))
(defn- router
[routes {:keys [uri request-method] :as req}]
(if-let [route (match-route routes uri request-method)]
(route+req->response route req)
(route+req->response (->> routes
(filter #(= :not-found (:path %)))
first) req)))
(defn route!
([routes]
(route! routes {:port 9600}))
([routes opts]
(http/run-server #(router routes %) opts)))
(defn -main [& opts]
(route! routes))
|