Skip to content

Commit 8b3ee9b

Browse files
committed
add custom header support
1 parent 84936d0 commit 8b3ee9b

File tree

3 files changed

+35
-30
lines changed

3 files changed

+35
-30
lines changed

Coder Desktop/CoderSDK/Client.swift

+25-26
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ import Foundation
33
public struct Client {
44
public let url: URL
55
public var token: String?
6+
public var headers: [HTTPHeader]
67

7-
public init(url: URL, token: String? = nil) {
8+
public init(url: URL, token: String? = nil, headers: [HTTPHeader] = []) {
89
self.url = url
910
self.token = token
11+
self.headers = headers
1012
}
1113

1214
static let decoder: JSONDecoder = {
@@ -21,20 +23,17 @@ public struct Client {
2123
return enc
2224
}()
2325

24-
func request<T: Encodable & Sendable>(
25-
_ path: String,
26+
private func doRequest(
27+
path: String,
2628
method: HTTPMethod,
27-
body: T? = nil
29+
body: Data? = nil
2830
) async throws(ClientError) -> HTTPResponse {
2931
let url = self.url.appendingPathComponent(path)
3032
var req = URLRequest(url: url)
3133
if let token { req.addValue(token, forHTTPHeaderField: Headers.sessionToken) }
3234
req.httpMethod = method.rawValue
33-
do {
34-
if let body { req.httpBody = try Client.encoder.encode(body) }
35-
} catch {
36-
throw .encodeFailure
37-
}
35+
for header in headers { req.addValue(header.value, forHTTPHeaderField: header.header) }
36+
req.httpBody = body
3837
let data: Data
3938
let resp: URLResponse
4039
do {
@@ -48,25 +47,25 @@ public struct Client {
4847
return HTTPResponse(resp: httpResponse, data: data, req: req)
4948
}
5049

51-
func request(
50+
func request<T: Encodable & Sendable>(
5251
_ path: String,
53-
method: HTTPMethod
52+
method: HTTPMethod,
53+
body: T
5454
) async throws(ClientError) -> HTTPResponse {
55-
let url = self.url.appendingPathComponent(path)
56-
var req = URLRequest(url: url)
57-
if let token { req.addValue(token, forHTTPHeaderField: Headers.sessionToken) }
58-
req.httpMethod = method.rawValue
59-
let data: Data
60-
let resp: URLResponse
55+
let encodedBody: Data?
6156
do {
62-
(data, resp) = try await URLSession.shared.data(for: req)
57+
encodedBody = try Client.encoder.encode(body)
6358
} catch {
64-
throw .network(error)
59+
throw .encodeFailure(error)
6560
}
66-
guard let httpResponse = resp as? HTTPURLResponse else {
67-
throw .unexpectedResponse(data)
68-
}
69-
return HTTPResponse(resp: httpResponse, data: data, req: req)
61+
return try await doRequest(path: path, method: method, body: encodedBody)
62+
}
63+
64+
func request(
65+
_ path: String,
66+
method: HTTPMethod
67+
) async throws(ClientError) -> HTTPResponse {
68+
return try await doRequest(path: path, method: method)
7069
}
7170

7271
func responseAsError(_ resp: HTTPResponse) -> ClientError {
@@ -119,7 +118,7 @@ public enum ClientError: Error {
119118
case api(APIError)
120119
case network(any Error)
121120
case unexpectedResponse(Data)
122-
case encodeFailure
121+
case encodeFailure(any Error)
123122

124123
public var description: String {
125124
switch self {
@@ -129,8 +128,8 @@ public enum ClientError: Error {
129128
return error.localizedDescription
130129
case let .unexpectedResponse(data):
131130
return "Unexpected or non HTTP response: \(data)"
132-
case .encodeFailure:
133-
return "Failed to encode body"
131+
case let .encodeFailure(error):
132+
return "Failed to encode body: \(error)"
134133
}
135134
}
136135
}

Coder Desktop/CoderSDK/HTTP.swift

+5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ public struct HTTPResponse {
44
let req: URLRequest
55
}
66

7+
public struct HTTPHeader {
8+
let header: String
9+
let value: String
10+
}
11+
712
enum HTTPMethod: String, Equatable, Hashable, Sendable {
813
case get = "GET"
914
case post = "POST"

Coder Desktop/CoderSDKTests/CoderSDKTests.swift

+5-4
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,23 @@ struct CoderSDKTests {
2727

2828
let url = URL(string: "https://example.com")!
2929
let token = "fake-token"
30-
let client = Client(url: url, token: token)
30+
let client = Client(url: url, token: token, headers: [.init(header: "X-Test-Header", value: "foo")])
3131
var mock = try Mock(
3232
url: url.appending(path: "api/v2/users/johndoe"),
3333
contentType: .json,
3434
statusCode: 200,
3535
data: [.get: Client.encoder.encode(user)]
3636
)
37-
var tokenSent = false
37+
var correctHeaders = false
3838
mock.onRequestHandler = OnRequestHandler { req in
39-
tokenSent = req.value(forHTTPHeaderField: Headers.sessionToken) == token
39+
correctHeaders = req.value(forHTTPHeaderField: Headers.sessionToken) == token &&
40+
req.value(forHTTPHeaderField: "X-Test-Header") == "foo"
4041
}
4142
mock.register()
4243

4344
let retUser = try await client.user(user.username)
4445
#expect(user == retUser)
45-
#expect(tokenSent)
46+
#expect(correctHeaders)
4647
}
4748

4849
@Test

0 commit comments

Comments
 (0)