@@ -11,95 +11,38 @@ public struct Client: Sendable {
11
11
self . headers = headers
12
12
}
13
13
14
- static let decoder : JSONDecoder = {
15
- var dec = JSONDecoder ( )
16
- dec. dateDecodingStrategy = . iso8601withOptionalFractionalSeconds
17
- return dec
18
- } ( )
19
-
20
- static let encoder : JSONEncoder = {
21
- var enc = JSONEncoder ( )
22
- enc. dateEncodingStrategy = . iso8601withFractionalSeconds
23
- return enc
24
- } ( )
25
-
26
- private func doRequest(
27
- path: String ,
28
- method: HTTPMethod ,
29
- body: Data ? = nil
30
- ) async throws ( ClientError) -> HTTPResponse {
31
- let url = url. appendingPathComponent ( path)
32
- var req = URLRequest ( url: url)
33
- if let token { req. addValue ( token, forHTTPHeaderField: Headers . sessionToken) }
34
- req. httpMethod = method. rawValue
35
- for header in headers {
36
- req. addValue ( header. value, forHTTPHeaderField: header. name)
37
- }
38
- req. httpBody = body
39
- let data : Data
40
- let resp : URLResponse
41
- do {
42
- ( data, resp) = try await URLSession . shared. data ( for: req)
43
- } catch {
44
- throw . network( error)
45
- }
46
- guard let httpResponse = resp as? HTTPURLResponse else {
47
- throw . unexpectedResponse( String ( data: data, encoding: . utf8) ?? " <non-utf8 data> " )
48
- }
49
- return HTTPResponse ( resp: httpResponse, data: data, req: req)
50
- }
51
-
52
14
func request(
53
15
_ path: String ,
54
16
method: HTTPMethod ,
55
17
body: some Encodable & Sendable
56
- ) async throws ( ClientError) -> HTTPResponse {
57
- let encodedBody : Data ?
58
- do {
59
- encodedBody = try Client . encoder. encode ( body)
60
- } catch {
61
- throw . encodeFailure( error)
18
+ ) async throws ( SDKError) -> HTTPResponse {
19
+ var headers = headers
20
+ if let token {
21
+ headers += [ . init( name: Headers . sessionToken, value: token) ]
62
22
}
63
- return try await doRequest ( path: path, method: method, body: encodedBody)
23
+ return try await CoderSDK . request (
24
+ baseURL: url,
25
+ path: path,
26
+ method: method,
27
+ headers: headers,
28
+ body: body
29
+ )
64
30
}
65
31
66
32
func request(
67
33
_ path: String ,
68
34
method: HTTPMethod
69
- ) async throws ( ClientError) -> HTTPResponse {
70
- try await doRequest ( path: path, method: method)
71
- }
72
-
73
- func responseAsError( _ resp: HTTPResponse ) -> ClientError {
74
- do {
75
- let body = try decode ( Response . self, from: resp. data)
76
- let out = APIError (
77
- response: body,
78
- statusCode: resp. resp. statusCode,
79
- method: resp. req. httpMethod!,
80
- url: resp. req. url!
81
- )
82
- return . api( out)
83
- } catch {
84
- return . unexpectedResponse( String ( data: resp. data, encoding: . utf8) ?? " <non-utf8 data> " )
85
- }
86
- }
87
-
88
- // Wrapper around JSONDecoder.decode that displays useful error messages from `DecodingError`.
89
- func decode< T> ( _: T . Type , from data: Data ) throws ( ClientError) -> T where T: Decodable {
90
- do {
91
- return try Client . decoder. decode ( T . self, from: data)
92
- } catch let DecodingError . keyNotFound( _, context) {
93
- throw . unexpectedResponse( " Key not found: \( context. debugDescription) " )
94
- } catch let DecodingError . valueNotFound( _, context) {
95
- throw . unexpectedResponse( " Value not found: \( context. debugDescription) " )
96
- } catch let DecodingError . typeMismatch( _, context) {
97
- throw . unexpectedResponse( " Type mismatch: \( context. debugDescription) " )
98
- } catch let DecodingError . dataCorrupted( context) {
99
- throw . unexpectedResponse( " Data corrupted: \( context. debugDescription) " )
100
- } catch {
101
- throw . unexpectedResponse( String ( data: data. prefix ( 1024 ) , encoding: . utf8) ?? " <non-utf8 data> " )
35
+ ) async throws ( SDKError) -> HTTPResponse {
36
+ var headers = headers
37
+ if let token {
38
+ headers += [ . init( name: Headers . sessionToken, value: token) ]
102
39
}
40
+ return try await CoderSDK . request (
41
+ baseURL: url,
42
+ path: path,
43
+ method: method,
44
+ headers: headers
45
+ )
103
46
}
104
47
}
105
48
@@ -133,7 +76,7 @@ public struct FieldValidation: Decodable, Sendable {
133
76
let detail : String
134
77
}
135
78
136
- public enum ClientError : Error {
79
+ public enum SDKError : Error {
137
80
case api( APIError )
138
81
case network( any Error )
139
82
case unexpectedResponse( String )
@@ -154,3 +97,110 @@ public enum ClientError: Error {
154
97
155
98
public var localizedDescription : String { description }
156
99
}
100
+
101
+ let decoder : JSONDecoder = {
102
+ var dec = JSONDecoder ( )
103
+ dec. dateDecodingStrategy = . iso8601withOptionalFractionalSeconds
104
+ return dec
105
+ } ( )
106
+
107
+ let encoder : JSONEncoder = {
108
+ var enc = JSONEncoder ( )
109
+ enc. dateEncodingStrategy = . iso8601withFractionalSeconds
110
+ return enc
111
+ } ( )
112
+
113
+ func doRequest(
114
+ baseURL: URL ,
115
+ path: String ,
116
+ method: HTTPMethod ,
117
+ headers: [ HTTPHeader ] = [ ] ,
118
+ body: Data ? = nil
119
+ ) async throws ( SDKError) -> HTTPResponse {
120
+ let url = baseURL. appendingPathComponent ( path)
121
+ var req = URLRequest ( url: url)
122
+ req. httpMethod = method. rawValue
123
+ for header in headers {
124
+ req. addValue ( header. value, forHTTPHeaderField: header. name)
125
+ }
126
+ req. httpBody = body
127
+ let data : Data
128
+ let resp : URLResponse
129
+ do {
130
+ ( data, resp) = try await URLSession . shared. data ( for: req)
131
+ } catch {
132
+ throw . network( error)
133
+ }
134
+ guard let httpResponse = resp as? HTTPURLResponse else {
135
+ throw . unexpectedResponse( String ( data: data, encoding: . utf8) ?? " <non-utf8 data> " )
136
+ }
137
+ return HTTPResponse ( resp: httpResponse, data: data, req: req)
138
+ }
139
+
140
+ func request(
141
+ baseURL: URL ,
142
+ path: String ,
143
+ method: HTTPMethod ,
144
+ headers: [ HTTPHeader ] = [ ] ,
145
+ body: some Encodable & Sendable
146
+ ) async throws ( SDKError) -> HTTPResponse {
147
+ let encodedBody : Data
148
+ do {
149
+ encodedBody = try encoder. encode ( body)
150
+ } catch {
151
+ throw . encodeFailure( error)
152
+ }
153
+ return try await doRequest (
154
+ baseURL: baseURL,
155
+ path: path,
156
+ method: method,
157
+ headers: headers,
158
+ body: encodedBody
159
+ )
160
+ }
161
+
162
+ func request(
163
+ baseURL: URL ,
164
+ path: String ,
165
+ method: HTTPMethod ,
166
+ headers: [ HTTPHeader ] = [ ]
167
+ ) async throws ( SDKError) -> HTTPResponse {
168
+ try await doRequest (
169
+ baseURL: baseURL,
170
+ path: path,
171
+ method: method,
172
+ headers: headers
173
+ )
174
+ }
175
+
176
+ func responseAsError( _ resp: HTTPResponse ) -> SDKError {
177
+ do {
178
+ let body = try decode ( Response . self, from: resp. data)
179
+ let out = APIError (
180
+ response: body,
181
+ statusCode: resp. resp. statusCode,
182
+ method: resp. req. httpMethod!,
183
+ url: resp. req. url!
184
+ )
185
+ return . api( out)
186
+ } catch {
187
+ return . unexpectedResponse( String ( data: resp. data, encoding: . utf8) ?? " <non-utf8 data> " )
188
+ }
189
+ }
190
+
191
+ // Wrapper around JSONDecoder.decode that displays useful error messages from `DecodingError`.
192
+ func decode< T: Decodable > ( _: T . Type , from data: Data ) throws ( SDKError) -> T {
193
+ do {
194
+ return try decoder. decode ( T . self, from: data)
195
+ } catch let DecodingError . keyNotFound( _, context) {
196
+ throw . unexpectedResponse( " Key not found: \( context. debugDescription) " )
197
+ } catch let DecodingError . valueNotFound( _, context) {
198
+ throw . unexpectedResponse( " Value not found: \( context. debugDescription) " )
199
+ } catch let DecodingError . typeMismatch( _, context) {
200
+ throw . unexpectedResponse( " Type mismatch: \( context. debugDescription) " )
201
+ } catch let DecodingError . dataCorrupted( context) {
202
+ throw . unexpectedResponse( " Data corrupted: \( context. debugDescription) " )
203
+ } catch {
204
+ throw . unexpectedResponse( String ( data: data. prefix ( 1024 ) , encoding: . utf8) ?? " <non-utf8 data> " )
205
+ }
206
+ }
0 commit comments