Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error extensions support #96

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions Sources/GraphQL/Error/GraphQLError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public struct GraphQLError : Error, Codable {
case message
case locations
case path
case extensions
}

/**
Expand All @@ -29,6 +30,18 @@ public struct GraphQLError : Error, Codable {
* Appears in the result of `description`.
*/
public let locations: [SourceLocation]

/**
* A dictionary containing original error reflection
* to supply additional data from error extensions.
*
* Will reflect only Codable objects.
*
* For more information about supported types look at `AnyCodable` - `init(from:)`
*
* Appears in the result of `description`.
*/
public let extensions: [String: AnyCodable]?

/**
* An array describing the index path into the execution response which
Expand Down Expand Up @@ -92,6 +105,7 @@ public struct GraphQLError : Error, Codable {

self.path = path
self.originalError = originalError
self.extensions = originalError?.reflection
}

public init(
Expand All @@ -106,6 +120,7 @@ public struct GraphQLError : Error, Codable {
self.source = nil
self.positions = []
self.originalError = nil
self.extensions = nil
}

public init(_ error: Error) {
Expand All @@ -120,6 +135,7 @@ public struct GraphQLError : Error, Codable {
message = try container.decode(String.self, forKey: .message)
locations = try container.decode([SourceLocation]?.self, forKey: .locations) ?? []
path = try container.decode(IndexPath.self, forKey: .path)
extensions = try container.decodeIfPresent([String: AnyCodable].self, forKey: .extensions)
}

public func encode(to encoder: Encoder) throws {
Expand All @@ -132,6 +148,10 @@ public struct GraphQLError : Error, Codable {
}

try container.encode(path, forKey: .path)

if let extensions = extensions {
try container.encode(extensions, forKey: .extensions)
}
}
}

Expand Down
35 changes: 35 additions & 0 deletions Sources/GraphQL/Extensions/Codable+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,38 @@ public class AnyEncodable : Encodable {
return try self.encodable.encode(to: encoder)
}
}

public class AnyCodable : Codable {
private let codable: Codable

public init(_ codable: Codable) {
self.codable = codable
}

public func encode(to encoder: Encoder) throws {
return try self.codable.encode(to: encoder)
}

required public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if container.decodeNil() {
self.codable = "Null"
} else if let bool = try? container.decode(Bool.self) {
self.codable = bool
} else if let int = try? container.decode(Int.self) {
self.codable = int
} else if let uint = try? container.decode(UInt.self) {
self.codable = uint
} else if let double = try? container.decode(Double.self) {
self.codable = double
} else if let string = try? container.decode(String.self) {
self.codable = string
} else if let array = try? container.decode([AnyCodable].self) {
codable = array
} else if let dictionary = try? container.decode([String: AnyCodable].self) {
codable = dictionary
} else {
throw DecodingError.dataCorruptedError(in: container, debugDescription: "AnyCodable: can't decode value")
}
}
}
13 changes: 13 additions & 0 deletions Sources/GraphQL/Extensions/Error+Extensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
public extension Error {
var reflection: [String: AnyCodable] {
let errorReflection: Mirror = Mirror(reflecting: self)
return Dictionary(uniqueKeysWithValues: errorReflection.children.lazy.map({ (label: String?, value: Any) -> (String, AnyCodable)? in
guard let key = label,
let codableValue = value as? Codable else {
return nil
}

return (key, AnyCodable(codableValue))
}).compactMap { $0 })
}
}