@@ -104,13 +104,17 @@ public struct AWSHTTPResponse: Sendable {
104
104
case . byteBuffer( let buffer) :
105
105
switch serviceConfig. serviceProtocol {
106
106
case . restjson:
107
- apiError = try ? JSONDecoder ( ) . decode ( RESTJSONError . self, from: buffer)
107
+ let jsonDecoder = JSONDecoder ( )
108
+ jsonDecoder. userInfo [ . awsErrorMap] = serviceConfig. errorType
109
+ apiError = try ? jsonDecoder. decode ( RESTJSONError . self, from: buffer)
108
110
if apiError? . code == nil {
109
111
apiError? . code = self . headers [ " x-amzn-errortype " ] . first
110
112
}
111
113
112
114
case . json:
113
- apiError = try ? JSONDecoder ( ) . decode ( JSONError . self, from: buffer)
115
+ let jsonDecoder = JSONDecoder ( )
116
+ jsonDecoder. userInfo [ . awsErrorMap] = serviceConfig. errorType
117
+ apiError = try ? jsonDecoder. decode ( JSONError . self, from: buffer)
114
118
115
119
case . query:
116
120
let xmlDocument = try ? XML . Document ( buffer: buffer)
@@ -119,15 +123,19 @@ public struct AWSHTTPResponse: Sendable {
119
123
element = errors
120
124
}
121
125
guard let errorElement = element. elements ( forName: " Error " ) . first else { break }
122
- apiError = try ? XMLDecoder ( ) . decode ( XMLQueryError . self, from: errorElement)
126
+ var xmlDecoder = XMLDecoder ( )
127
+ xmlDecoder. userInfo [ . awsErrorMap] = serviceConfig. errorType
128
+ apiError = try ? xmlDecoder. decode ( XMLQueryError . self, from: errorElement)
123
129
124
130
case . restxml:
125
131
let xmlDocument = try ? XML . Document ( buffer: buffer)
126
132
guard var element = xmlDocument? . rootElement ( ) else { break }
127
133
if let error = element. elements ( forName: " Error " ) . first {
128
134
element = error
129
135
}
130
- apiError = try ? XMLDecoder ( ) . decode ( XMLQueryError . self, from: element)
136
+ var xmlDecoder = XMLDecoder ( )
137
+ xmlDecoder. userInfo [ . awsErrorMap] = serviceConfig. errorType
138
+ apiError = try ? xmlDecoder. decode ( XMLQueryError . self, from: element)
131
139
132
140
case . ec2:
133
141
let xmlDocument = try ? XML . Document ( buffer: buffer)
@@ -136,7 +144,9 @@ public struct AWSHTTPResponse: Sendable {
136
144
element = errors
137
145
}
138
146
guard let errorElement = element. elements ( forName: " Error " ) . first else { break }
139
- apiError = try ? XMLDecoder ( ) . decode ( XMLQueryError . self, from: errorElement)
147
+ var xmlDecoder = XMLDecoder ( )
148
+ xmlDecoder. userInfo [ . awsErrorMap] = serviceConfig. errorType
149
+ apiError = try ? xmlDecoder. decode ( XMLQueryError . self, from: errorElement)
140
150
}
141
151
}
142
152
if let errorMessage = apiError, var code = errorMessage. code {
@@ -158,7 +168,8 @@ public struct AWSHTTPResponse: Sendable {
158
168
message: errorMessage. message,
159
169
responseCode: self . status,
160
170
headers: self . headers,
161
- additionalFields: errorMessage. additionalFields
171
+ additionalFields: errorMessage. additionalFields,
172
+ extendedError: errorMessage. extendedError
162
173
)
163
174
164
175
if let errorType = serviceConfig. errorType {
@@ -181,17 +192,30 @@ public struct AWSHTTPResponse: Sendable {
181
192
}
182
193
183
194
/// Error used by XML output
184
- private struct XMLQueryError : Codable , APIError {
195
+ private struct XMLQueryError : Decodable , APIError {
185
196
var code : String ?
186
197
let message : String
187
198
let additionalFields : [ String : String ]
199
+ let extendedError : AWSErrorShape ?
188
200
189
201
init ( from decoder: Decoder ) throws {
190
202
// use `ErrorCodingKey` so we get extract additional keys from `container.allKeys`
191
203
let container = try decoder. container ( keyedBy: ErrorCodingKey . self)
192
- self . code = try container. decodeIfPresent ( String . self, forKey: . init( " Code " ) )
204
+ let code = try container. decodeIfPresent ( String . self, forKey: . init( " Code " ) )
205
+ // Remove namespace from error code
206
+ self . code = code? . split ( separator: " # " ) . last. map { String ( $0) }
193
207
self . message = try container. decode ( String . self, forKey: . init( " Message " ) )
194
208
209
+ if let code = self . code,
210
+ let errorMapping = decoder. userInfo [ . awsErrorMap] as? AWSServiceErrorType . Type ,
211
+ let errorType = errorMapping. errorCodeMap [ code]
212
+ {
213
+ let container = try decoder. singleValueContainer ( )
214
+ self . extendedError = try ? container. decode ( errorType)
215
+ } else {
216
+ self . extendedError = nil
217
+ }
218
+
195
219
var additionalFields : [ String : String ] = [ : ]
196
220
for key in container. allKeys {
197
221
guard key. stringValue != " Code " , key. stringValue != " Message " else { continue }
@@ -203,19 +227,31 @@ public struct AWSHTTPResponse: Sendable {
203
227
}
204
228
}
205
229
206
- /// Error used by JSON output
207
230
private struct JSONError : Decodable , APIError {
208
231
var code : String ?
209
232
let message : String
210
233
let additionalFields : [ String : String ]
234
+ let extendedError : AWSErrorShape ?
211
235
212
236
init ( from decoder: Decoder ) throws {
213
237
// use `ErrorCodingKey` so we get extract additional keys from `container.allKeys`
214
238
let container = try decoder. container ( keyedBy: ErrorCodingKey . self)
215
- self . code = try container. decodeIfPresent ( String . self, forKey: . init( " __type " ) )
239
+ let code = try container. decodeIfPresent ( String . self, forKey: . init( " __type " ) )
240
+ // Remove namespace from error code
241
+ self . code = code? . split ( separator: " # " ) . last. map { String ( $0) }
216
242
self . message =
217
243
try container. decodeIfPresent ( String . self, forKey: . init( " message " ) ) ?? container. decode ( String . self, forKey: . init( " Message " ) )
218
244
245
+ let errorMapping = decoder. userInfo [ . awsErrorMap]
246
+ if let code = self . code,
247
+ let errorMapping = errorMapping as? AWSServiceErrorType . Type ,
248
+ let errorType = errorMapping. errorCodeMap [ code]
249
+ {
250
+ let container = try decoder. singleValueContainer ( )
251
+ self . extendedError = try ? container. decode ( errorType)
252
+ } else {
253
+ self . extendedError = nil
254
+ }
219
255
var additionalFields : [ String : String ] = [ : ]
220
256
for key in container. allKeys {
221
257
guard key. stringValue != " __type " , key. stringValue != " message " , key. stringValue != " Message " else { continue }
@@ -232,14 +268,27 @@ public struct AWSHTTPResponse: Sendable {
232
268
var code : String ?
233
269
let message : String
234
270
let additionalFields : [ String : String ]
271
+ let extendedError : AWSErrorShape ?
235
272
236
273
init ( from decoder: Decoder ) throws {
237
274
// use `ErrorCodingKey` so we get extract additional keys from `container.allKeys`
238
275
let container = try decoder. container ( keyedBy: ErrorCodingKey . self)
239
- self . code = try container. decodeIfPresent ( String . self, forKey: . init( " code " ) )
276
+ let code = try container. decodeIfPresent ( String . self, forKey: . init( " code " ) )
277
+ // Remove namespace from error code
278
+ self . code = code? . split ( separator: " # " ) . last. map { String ( $0) }
240
279
self . message =
241
280
try container. decodeIfPresent ( String . self, forKey: . init( " message " ) ) ?? container. decode ( String . self, forKey: . init( " Message " ) )
242
281
282
+ if let code = self . code,
283
+ let errorMapping = decoder. userInfo [ . awsErrorMap] as? AWSServiceErrorType . Type ,
284
+ let errorType = errorMapping. errorCodeMap [ code]
285
+ {
286
+ let container = try decoder. singleValueContainer ( )
287
+ self . extendedError = try ? container. decode ( errorType)
288
+ } else {
289
+ self . extendedError = nil
290
+ }
291
+
243
292
var additionalFields : [ String : String ] = [ : ]
244
293
for key in container. allKeys {
245
294
guard key. stringValue != " code " , key. stringValue != " message " , key. stringValue != " Message " else { continue }
@@ -276,6 +325,7 @@ private protocol APIError {
276
325
var code : String ? { get set }
277
326
var message : String { get }
278
327
var additionalFields : [ String : String ] { get }
328
+ var extendedError : AWSErrorShape ? { get }
279
329
}
280
330
281
331
extension XML . Document {
@@ -284,3 +334,7 @@ extension XML.Document {
284
334
try self . init ( string: xmlString)
285
335
}
286
336
}
337
+
338
+ extension CodingUserInfoKey {
339
+ public static var awsErrorMap : Self { . init( rawValue: " soto.awsErrorMap " ) ! }
340
+ }
0 commit comments