@@ -11,95 +11,38 @@ public struct Client: Sendable {
1111 self . headers = headers
1212 }
1313
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-
5214 func request(
5315 _ path: String ,
5416 method: HTTPMethod ,
5517 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) ]
6222 }
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+ )
6430 }
6531
6632 func request(
6733 _ path: String ,
6834 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) ]
10239 }
40+ return try await CoderSDK . request (
41+ baseURL: url,
42+ path: path,
43+ method: method,
44+ headers: headers
45+ )
10346 }
10447}
10548
@@ -133,7 +76,7 @@ public struct FieldValidation: Decodable, Sendable {
13376 let detail : String
13477}
13578
136- public enum ClientError : Error {
79+ public enum SDKError : Error {
13780 case api( APIError )
13881 case network( any Error )
13982 case unexpectedResponse( String )
@@ -154,3 +97,110 @@ public enum ClientError: Error {
15497
15598 public var localizedDescription : String { description }
15699}
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