/
http.cljc
84 lines (67 loc) · 2.99 KB
/
http.cljc
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
(ns com.wsscode.pathom.diplomat.http
(:require [clojure.spec.alpha :as s]
[com.wsscode.pathom.misc :as p.misc]
[com.fulcrologic.guardrails.core :refer [>def >defn >fdef => | <- ?]]))
(>def ::encode-type (s/with-gen keyword? #(s/gen #{::transit+json ::edn ::json})))
(>def ::url string?)
(>def ::method #{::get ::head ::post ::put ::patch ::delete ::connect ::options})
;; HTTP driver should always normalize the header name from HTTP-Case to :lower-case-keyword.
;; HTTP1.1 use HTTP-Case, HTTP2 use lower-case. Always normalize it a good aproach used by
;; pedestal and many others.
;; A header can be sent multiple times. So it should be a coll-of values.
;; Multiple values are supported both in java.net.http(req/res) and js/fetch(res).
(>def ::headers (s/map-of string? (s/coll-of string?)))
;; content-type will generate a header on request. it can be overwriten by passing a explicit content-type
;; key on headers map. The driver will use this to convert ::form-params into ::body
;; If absent, the driver should use ::body with no transformation and ::form-params will be ignored
;; If it's a raw string, it will generate the header, but the driver should use raw ::body
(>def ::content-type (s/or :pre-defined ::encode-type :raw string?))
;; accept will generate a header on request. it can be overwriten by passing a explicit accept
;; key on headers map. The driver will use this to convert the response from server into ::body
;; If it's a raw string, it will just generate the header.
;; If absent or a raw string, the driver can (or not) use the content-type from response-header to convert.
(>def ::accept (s/or :pre-defined ::encode-type :raw string?))
;; Will say how to turn ::form-params into body on request and how to parse the response body.
;; If content-type and/or accept are specifieds as :pre-defined, they will be preferred.
(>def ::as ::encode-type)
;; Used to generate ::body basead on ::content-type on request.
;; Usualy a clojure data-structure
(>def ::form-params any?)
;; enable/disable tracing
(>def ::debug? boolean?)
;; On request, usually string, bytes, buffer or a writer.
;; On response, should be a clojure data-structure.
(>def ::body any?)
(>def ::request
(s/keys
:req [::url]
:opt [::method
::headers
::content-type
::accept
::as
::form-params
::debug?
::body]))
(>def ::response
(s/keys
:req [::status]
:opt [::headers
::body]))
(>def ::driver fn?)
(defn request
([{::keys [driver] :as request}]
(driver request))
([{::keys [driver] :as request} url]
(driver (assoc request ::url url)))
([{::keys [driver] :as request} url config]
(driver (merge request {::url url} config))))
(defn request-method [{::keys [method form-params]}]
(or (some-> method name)
(if form-params "post" "get")))
(defn encode-type->header [encode-type]
(cond
(string? encode-type)
encode-type
(keyword? encode-type)
(str "application/" (name encode-type))))