-
-
Notifications
You must be signed in to change notification settings - Fork 19
/
response.clj
148 lines (128 loc) · 4.16 KB
/
response.clj
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
(ns fierycod.holy-lambda.response
"Response helpers adapted from ring-core/util/response.clj"
(:require
[clojure.string :as s]))
(def redirect-status-codes
"Map a keyword to a redirect status code."
{:moved-permanently 301
:found 302
:see-other 303
:temporary-redirect 307
:permanent-redirect 308})
(defn redirect
"Returns a response for an HTTP 302 redirect. Status may be
a key in redirect-status-codes or a numeric code. Defaults to 302"
([url] (redirect url :found))
([url status]
{:statusCode (redirect-status-codes status status)
:headers {"location" url}
:body nil}))
(defn created
"Returns a response for a HTTP 201 created response."
{:added "1.2"}
([url] (created url nil))
([url body]
{:statusCode 201
:headers {"location" url}
:body body}))
(defn bad-request
"Returns a 400 'bad request' response."
[body]
{:statusCode 400
:headers {}
:body body})
(defn not-found
"Returns a 404 'not found' response."
[body]
{:statusCode 404
:headers {}
:body body})
(defn response
"Returns a skeletal response with the given body, status of 200, and no
headers."
[body]
{:statusCode 200
:headers {}
:body body})
(defn json
"Returns a skeletal response with the given body, status of 200, and `Content-Type` set to `application/json`."
[body]
{:statusCode 200
:headers {"content-type" "application/json"}
:body body})
(defn text
"Returns a skeletal response with the given msg, status of 200, and `Content-Type` set to `text/plain`."
[?msg]
{:statusCode 200
:headers {"content-type" "text/plain; charset=utf-8"}
:body ?msg})
(defn html
"Returns a skeletal response with the given body, status of 200, and `Content-Type` set to `text/html`."
[?body]
{:statusCode 200
:headers {"content-type" "text/html; charset=utf-8"}
:body ?body})
(defn status
"Returns an updated response with the given status."
([?status]
{:statusCode ?status
:headers {}
:body {}})
([resp ?status]
(assoc resp :statusCode ?status)))
(defn header
"Returns an updated response with the specified header added."
[resp ?name value]
(assoc-in resp [:headers ?name] (str value)))
(defn content-type
"Returns an updated response with the a Content-Type header corresponding
to the given content-type."
[resp ?content-type]
(header resp "content-type" ?content-type))
(defn find-header
"Looks up a header in a response (or request) case insensitively,
returning the header map entry, or nil if not present."
[resp ^String header-name]
(->> (:headers resp)
(filter #(.equalsIgnoreCase header-name (key %)))
(first)))
(defn get-header
"Looks up a header in a response (or request) case insensitively,
returning the value of the header, or nil if not present."
[resp ^String header-name]
(some-> resp (find-header header-name) val))
(defn update-header
"Looks up a header in a response (or request) case insensitively,
then updates the header with the supplied function and arguments in the
manner of update-in."
[resp header-name f & args]
(let [header-key (or (some-> resp (find-header header-name) key) header-name)]
(update-in resp [:headers header-key] #(apply f % args))))
(defn charset
"Returns an updated response with the supplied charset added to the
Content-Type header."
[resp ?charset]
(update-header resp "content-type"
(fn [?content-type]
(-> (or ?content-type "text/plain")
(s/replace #";\s*charset=[^;]*" "")
(str "; charset=" ?charset)))))
(defn- cookie
[k v {:keys [domain expires]}]
(s/replace
(cond-> (str k "=" v)
domain (str "; domain=" domain ";")
expires (str "; expires=" expires ";"))
";;" ";"))
(defn set-cookie
"Sets a cookie on the response."
[resp {:keys [k v] :as opts}]
(update-in resp [:multiValueHeaders "set-cookie"]
(fn [xv]
(vec (conj xv (cookie k v (dissoc opts :k :v)))))))
(defn origin
[resp ?origin]
(header resp "access-control-allow-origin" ?origin))
(defn credentials
[resp ?creds]
(header resp "access-control-allow-credentials" ?creds))