Skip to content

Commit 13fbbc8

Browse files
committed
[Experiment] Client error mapper
1 parent c118c19 commit 13fbbc8

File tree

1 file changed

+58
-43
lines changed

1 file changed

+58
-43
lines changed

Sources/OpenAPIRuntime/Interface/UniversalClient.swift

Lines changed: 58 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -38,31 +38,38 @@ import struct Foundation.URL
3838
/// The middlewares to be invoked before the transport.
3939
public var middlewares: [any ClientMiddleware]
4040

41+
/// An error mapping closure to allow customizing the error thrown by the client.
42+
public var errorMapper: (@Sendable (ClientError) -> any Error)?
43+
4144
/// Internal initializer that takes an initialized `Converter`.
4245
internal init(
4346
serverURL: URL,
4447
converter: Converter,
4548
transport: any ClientTransport,
46-
middlewares: [any ClientMiddleware]
49+
middlewares: [any ClientMiddleware],
50+
errorMapper: (@Sendable (ClientError) -> any Error)?
4751
) {
4852
self.serverURL = serverURL
4953
self.converter = converter
5054
self.transport = transport
5155
self.middlewares = middlewares
56+
self.errorMapper = errorMapper
5257
}
5358

5459
/// Creates a new client.
5560
public init(
5661
serverURL: URL = .defaultOpenAPIServerURL,
5762
configuration: Configuration = .init(),
5863
transport: any ClientTransport,
59-
middlewares: [any ClientMiddleware] = []
64+
middlewares: [any ClientMiddleware] = [],
65+
errorMapper: (@Sendable (ClientError) -> any Error)? = nil
6066
) {
6167
self.init(
6268
serverURL: serverURL,
6369
converter: Converter(configuration: configuration),
6470
transport: transport,
65-
middlewares: middlewares
71+
middlewares: middlewares,
72+
errorMapper: errorMapper
6673
)
6774
}
6875

@@ -135,57 +142,65 @@ import struct Foundation.URL
135142
underlyingError: underlyingError
136143
)
137144
}
138-
let (request, requestBody): (HTTPRequest, HTTPBody?) = try await wrappingErrors {
139-
try serializer(input)
140-
} mapError: { error in
141-
makeError(error: error)
142-
}
143-
var next: @Sendable (HTTPRequest, HTTPBody?, URL) async throws -> (HTTPResponse, HTTPBody?) = {
144-
(_request, _body, _url) in
145-
try await wrappingErrors {
146-
try await transport.send(_request, body: _body, baseURL: _url, operationID: operationID)
145+
do {
146+
let (request, requestBody): (HTTPRequest, HTTPBody?) = try await wrappingErrors {
147+
try serializer(input)
147148
} mapError: { error in
148-
makeError(
149-
request: request,
150-
requestBody: requestBody,
151-
baseURL: baseURL,
152-
error: RuntimeError.transportFailed(error)
153-
)
149+
makeError(error: error)
154150
}
155-
}
156-
for middleware in middlewares.reversed() {
157-
let tmp = next
158-
next = { (_request, _body, _url) in
151+
var next: @Sendable (HTTPRequest, HTTPBody?, URL) async throws -> (HTTPResponse, HTTPBody?) = {
152+
(_request, _body, _url) in
159153
try await wrappingErrors {
160-
try await middleware.intercept(
161-
_request,
162-
body: _body,
163-
baseURL: _url,
164-
operationID: operationID,
165-
next: tmp
166-
)
154+
try await transport.send(_request, body: _body, baseURL: _url, operationID: operationID)
167155
} mapError: { error in
168156
makeError(
169157
request: request,
170158
requestBody: requestBody,
171159
baseURL: baseURL,
172-
error: RuntimeError.middlewareFailed(middlewareType: type(of: middleware), error)
160+
error: RuntimeError.transportFailed(error)
173161
)
174162
}
175163
}
176-
}
177-
let (response, responseBody): (HTTPResponse, HTTPBody?) = try await next(request, requestBody, baseURL)
178-
return try await wrappingErrors {
179-
try await deserializer(response, responseBody)
180-
} mapError: { error in
181-
makeError(
182-
request: request,
183-
requestBody: requestBody,
184-
baseURL: baseURL,
185-
response: response,
186-
responseBody: responseBody,
187-
error: error
188-
)
164+
for middleware in middlewares.reversed() {
165+
let tmp = next
166+
next = { (_request, _body, _url) in
167+
try await wrappingErrors {
168+
try await middleware.intercept(
169+
_request,
170+
body: _body,
171+
baseURL: _url,
172+
operationID: operationID,
173+
next: tmp
174+
)
175+
} mapError: { error in
176+
makeError(
177+
request: request,
178+
requestBody: requestBody,
179+
baseURL: baseURL,
180+
error: RuntimeError.middlewareFailed(middlewareType: type(of: middleware), error)
181+
)
182+
}
183+
}
184+
}
185+
let (response, responseBody): (HTTPResponse, HTTPBody?) = try await next(request, requestBody, baseURL)
186+
return try await wrappingErrors {
187+
try await deserializer(response, responseBody)
188+
} mapError: { error in
189+
makeError(
190+
request: request,
191+
requestBody: requestBody,
192+
baseURL: baseURL,
193+
response: response,
194+
responseBody: responseBody,
195+
error: error
196+
)
197+
}
198+
} catch {
199+
if let errorMapper, let clientError = error as? ClientError {
200+
throw errorMapper(clientError)
201+
} else {
202+
throw error
203+
}
189204
}
190205
}
191206
}

0 commit comments

Comments
 (0)