Skip to content

Commit 52cff3f

Browse files
authored
fix(internal-client): FabricError as response content for error (#32)
1 parent f7f3455 commit 52cff3f

File tree

5 files changed

+88
-66
lines changed

5 files changed

+88
-66
lines changed

.devcontainer/devcontainer.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "Swift 5.6",
3+
"image": "swift:5.6-focal",
4+
"extensions": [
5+
"sswg.swift-lang"
6+
],
7+
"settings": {
8+
"lldb.library": "/usr/lib/liblldb.so"
9+
},
10+
"forwardPorts": [8080, 1337]
11+
}

Sources/YData/Client/InternalClient.swift

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public protocol InternalClient {
1010
var host: String { get }
1111
var port: Int? { get }
1212
var basePath: String? { get }
13-
13+
1414
var httpClient: Vapor.Client { get }
1515
var logger: Logger { get }
1616
}
@@ -22,32 +22,32 @@ public enum InternalClientError: Error {
2222
public extension InternalClient {
2323
var scheme: URI.Scheme { URI.Scheme("http") }
2424
var basePath: String? { nil }
25-
25+
2626
func send<Request: InternalRequest, Response: InternalResponse>(_ request: Request) -> EventLoopFuture<Response> {
2727
let clientRequest = buildClientRequest(for: request)
28-
28+
2929
return httpClient.send(buildClientRequest(for: request))
3030
.always { self.logger.info("response for request \(clientRequest.url): \($0)") }
3131
.mapToInternalResponse()
3232
}
33-
33+
3434
internal func buildClientRequest<R: InternalRequest>(for request: R) -> ClientRequest {
3535
let path = basePath.flatMap { base in request.path.flatMap { "\(base)/\($0)" } ?? base } ?? request.path ?? ""
36-
36+
3737
let query = request.query.flatMap { queries in
3838
queries.compactMap { query -> String? in
3939
guard let value = query.value else { return nil }
40-
40+
4141
guard let escapedValue = value.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {
4242
return nil
4343
}
44-
44+
4545
return "\(query.name)=\(escapedValue)"
4646
}.joined(separator: "&")
4747
}
48-
48+
4949
let url = URI(scheme: scheme, host: host, port: port, path: path, query: query)
50-
50+
5151
var clientRequest = ClientRequest()
5252
request.headers.flatMap { clientRequest.headers = .init($0.map { (key, value) in (key, value) }) }
5353
clientRequest.method = request.method
@@ -64,27 +64,7 @@ private extension EventLoopFuture where Value: InternalResponse {
6464
case (100..<400):
6565
return .success(R(headers: response.headers, status: response.status, body: response.body))
6666
default:
67-
do {
68-
let contentError = try response.content.decode(Internal.ServiceError.self)
69-
return .failure(Internal.ErrorResponse(headers: response.headers,
70-
status: response.status,
71-
message:contentError.message))
72-
} catch DecodingError.keyNotFound {
73-
do {
74-
let contentError = try response.content.decode(String.self)
75-
return .failure(Internal.ErrorResponse(headers: response.headers,
76-
status: response.status,
77-
message: contentError))
78-
} catch {
79-
return .failure(Internal.ErrorResponse(headers: [:],
80-
status: .internalServerError,
81-
message: "failed to decode response with error \(error)"))
82-
}
83-
} catch {
84-
return .failure(Internal.ErrorResponse(headers: [:],
85-
status: .internalServerError,
86-
message: "failed to decode response with error \(error)"))
87-
}
67+
return .failure(Internal.ErrorResponse(response: response))
8868
}
8969
}
9070
}

Sources/YData/Client/InternalRequest.swift

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,26 @@ public extension Internal {
1919

2020
public var body: ByteBuffer?
2121

22-
public init<C: Content>(method: HTTPMethod,
23-
path: String? = nil,
24-
headers: HTTPHeaders? = nil,
25-
query: [URLQueryItem]? = nil,
26-
content: C) throws {
22+
public init<C: Content>(
23+
method: HTTPMethod,
24+
path: String? = nil,
25+
headers: HTTPHeaders? = nil,
26+
query: [URLQueryItem]? = nil,
27+
content: C
28+
) throws {
2729
self.method = method
2830
self.path = path
2931
self.headers = headers
3032
self.query = query
3133
try self.content.encode(content)
3234
}
3335

34-
public init(method: HTTPMethod,
35-
path: String? = nil,
36-
headers: HTTPHeaders? = nil,
37-
query: [URLQueryItem]? = nil) {
36+
public init(
37+
method: HTTPMethod,
38+
path: String? = nil,
39+
headers: HTTPHeaders? = nil,
40+
query: [URLQueryItem]? = nil
41+
) {
3842
self.method = method
3943
self.path = path
4044
self.headers = headers

Sources/YData/Client/InternalResponse+Vapor.swift

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -58,29 +58,17 @@ public extension ClientResponse {
5858
return try content.decode(C.self)
5959
} catch {
6060
throw Internal.ErrorResponse(
61+
content: GenericFabricError(
62+
description: "\(error)",
63+
httpCode: Int(HTTPResponseStatus.internalServerError.code),
64+
name: "DecodingError",
65+
returnValue: -1),
6166
headers: [:],
62-
status: .internalServerError,
63-
message: "failed to decode response \(error)")
67+
status: .internalServerError
68+
)
6469
}
6570
default:
66-
do {
67-
let contentError = try content.decode(Internal.ServiceError.self)
68-
throw Internal.ErrorResponse(
69-
headers: headers,
70-
status: status,
71-
message: contentError.message)
72-
} catch DecodingError.keyNotFound {
73-
let contentError = try content.decode(String.self)
74-
throw Internal.ErrorResponse(
75-
headers: headers,
76-
status: status,
77-
message: contentError)
78-
} catch {
79-
throw Internal.ErrorResponse(
80-
headers: [:],
81-
status: .internalServerError,
82-
message: "failed to decode response with error \(error)")
83-
}
71+
throw Internal.ErrorResponse(response: self)
8472
}
8573
}
8674
}

Sources/YData/Client/InternalResponse.swift

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,52 @@ public extension InternalResponse {
3232

3333
public extension Internal {
3434
struct ErrorResponse: Error {
35-
public let headers: HTTPHeaders
36-
public let status: HTTPResponseStatus
37-
public let message: String
35+
public var headers: HTTPHeaders
36+
public var status: HTTPResponseStatus
37+
public let content: any FabricError
38+
39+
init(content: any FabricError, headers: HTTPHeaders, status: HTTPResponseStatus) {
40+
self.content = content
41+
self.headers = headers
42+
self.status = status
43+
}
44+
45+
init(response: any InternalResponse) {
46+
self.headers = response.headers
47+
var status = response.status
48+
49+
if let fabricError = try? response.content.decode(GenericFabricError.self) {
50+
self.content = fabricError
51+
} else if let serviceError = try? response.content.decode(Internal.ServiceError.self) {
52+
self.content = GenericFabricError(
53+
description: serviceError.message,
54+
httpCode: Int(status.code),
55+
name: "\(Internal.ServiceError.self)",
56+
returnValue: -1
57+
)
58+
} else {
59+
do {
60+
let errorMessage = try response.content.decode(String.self)
61+
62+
self.content = GenericFabricError(
63+
description: errorMessage,
64+
httpCode: Int(response.status.code),
65+
name: "Unknown Error",
66+
returnValue: -1
67+
)
68+
} catch {
69+
status = .internalServerError
70+
self.content = GenericFabricError(
71+
description: "\(error)",
72+
httpCode: Int(response.status.code),
73+
name: "Unknown Error",
74+
returnValue: -1
75+
)
76+
}
77+
}
78+
79+
self.status = status
80+
}
3881
}
3982

4083
struct SuccessResponse: InternalResponse {
@@ -50,10 +93,6 @@ public extension Internal {
5093
}
5194
}
5295

53-
extension Internal.ErrorResponse: AbortError {
54-
public var reason: String { message }
55-
}
56-
5796
public extension Internal.SuccessResponse {
5897
private struct _ContentContainer: ContentContainer {
5998
var body: ByteBuffer?

0 commit comments

Comments
 (0)