Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Nicer descriptions for DecodingErrors
extension DecodingError.Context {
var pathDescription: String {
pathDescription(for: codingPath)
}
func path(including final: CodingKey) -> String {
pathDescription(for: codingPath + [final])
}
private func pathDescription(for path: [CodingKey]) -> String {
guard !path.isEmpty else {
return "root"
}
return path
.enumerated()
.map { (offset, key) -> String in
if let idx = key.intValue {
return "[\(idx)]"
} else {
return offset > 0 ? ".\(key.stringValue)" : key.stringValue
}
}
.joined()
}
}
public struct JSONBodyDecodingError: ReportableError {
let statusCode: StatusCode = .badRequest
let message: String
init<Type>(type: Type.Type, underlyingError: DecodingError?) {
switch underlyingError {
case .dataCorrupted:
self.message = "The endpoint expects a JSON body, which was not valid JSON."
case let .keyNotFound(key, context):
self.message = "The endpoint expects JSON with a value at the \(context.path(including: key)), but it was missing."
case let .typeMismatch(type, context):
var typeName = "\(type)"
if typeName.contains("UnkeyedDecodingContainer") {
typeName = "Array"
} else if typeName.contains("KeyedDecodingContainer") {
typeName = "Object"
}
self.message = "The endpoint expects JSON with a value of type \"\(typeName)\" at the \(context.pathDescription), but a different type was found."
case let .valueNotFound(type, context):
var typeName = "\(type)"
if typeName.contains("UnkeyedDecodingContainer") {
typeName = "Array"
} else if typeName.contains("KeyedDecodingContainer") {
typeName = "Object"
}
self.message = "The endpoint expects JSON with a value of type \"\(typeName)\" at the \(context.pathDescription), but null was found."
default:
self.message = "The endpoint expects JSON, which could not be decoded."
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment