Skip to content

Adds GraphQLError extensions #128

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

Merged
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
22 changes: 8 additions & 14 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,21 @@ jobs:

macos:
name: Build and test on macos-latest
runs-on: macOS-latest
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Set code coverage path
run: echo "codecov_path=$(swift test --show-codecov-path)" >> $GITHUB_ENV
- name: Test and publish code coverage to Code Climate
uses: paulofaria/codeclimate-action@master
env:
CC_TEST_REPORTER_ID: ${{secrets.CC_TEST_REPORTER_ID}}
with:
downloadUrl: https://github.com/paulofaria/test-reporter/releases/download/0.9.0/test-reporter-0.9.0-darwin-amd64
coverageCommand: swift test --enable-test-discovery --enable-code-coverage
coverageLocations: ${{ env.codecov_path }}:lcov-json
- uses: swift-actions/setup-swift@v1
- uses: actions/checkout@v3
- name: Test
run: swift test

# ubuntu-latest is ubuntu-22.04 currently. Swift versions older than 5.7 don't have builds for 22.04. https://www.swift.org/download/
ubuntu-old:
name: Build ${{ matrix.swift }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-20.04]
swift: ["5.4", "5.5", "5.6"]
swift: ["5.5", "5.6"]
steps:
- uses: swift-actions/setup-swift@v1
with:
Expand All @@ -60,7 +54,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
swift: ["5.7"]
swift: ["5.7", "5.8"]
steps:
- uses: swift-actions/setup-swift@v1
with:
Expand Down
20 changes: 18 additions & 2 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 Down Expand Up @@ -38,6 +39,12 @@ public struct GraphQLError: Error, Codable {
*/
public let path: IndexPath

/// Reserved for implementors to add additional information to errors
/// however they see fit, and there are no restrictions on its contents.
///
/// See: https://spec.graphql.org/October2021/#sel-HAPHRPZCBiCBzG67F
public let extensions: [String: Map]

/**
* An array of GraphQL AST Nodes corresponding to this error.
*/
Expand Down Expand Up @@ -65,7 +72,8 @@ public struct GraphQLError: Error, Codable {
source: Source? = nil,
positions: [Int] = [],
path: IndexPath = [],
originalError: Error? = nil
originalError: Error? = nil,
extensions: [String: Map] = [:]
) {
self.message = message
self.nodes = nodes
Expand All @@ -92,16 +100,19 @@ public struct GraphQLError: Error, Codable {

self.path = path
self.originalError = originalError
self.extensions = extensions
}

public init(
message: String,
locations: [SourceLocation],
path: IndexPath = []
path: IndexPath = [],
extensions: [String: Map] = [:]
) {
self.message = message
self.locations = locations
self.path = path
self.extensions = extensions
nodes = []
source = nil
positions = []
Expand All @@ -120,6 +131,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: Map].self, forKey: .extensions) ?? [:]
}

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

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

if !extensions.isEmpty {
try container.encode(extensions, forKey: .extensions)
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/GraphQL/Execution/Values.swift
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ func coerceValue(value: Map, type: GraphQLInputType) throws -> Map {
}

// Convert solitary value into single-value array
return .array([try coerceValue(value: value, type: itemType)])
return try .array([coerceValue(value: value, type: itemType)])
}

if let objectType = type as? GraphQLInputObjectType {
Expand Down
2 changes: 1 addition & 1 deletion Sources/GraphQL/Language/Parser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1331,7 +1331,7 @@ func many<T>(
parse: (Lexer) throws -> T
) throws -> [T] {
try expect(lexer: lexer, kind: openKind)
var nodes = [try parse(lexer)]
var nodes = try [parse(lexer)]
while try !skip(lexer: lexer, kind: closeKind) {
try nodes.append(parse(lexer))
}
Expand Down
7 changes: 0 additions & 7 deletions Sources/GraphQL/Map/GraphQLJSONEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -473,11 +473,6 @@ extension JSONEncoderImpl: _SpecialTreatmentEncoder {
return .string(url.absoluteString)
case let decimal as Decimal:
return .number(decimal.description)
case let object as OrderedDictionary<
String,
Encodable
>: // this emits a warning, but it works perfectly
return try wrapObject(object, for: nil)
case let date as Date:
return try wrapDate(date, for: nil)
default:
Expand Down Expand Up @@ -545,8 +540,6 @@ extension _SpecialTreatmentEncoder {
return .string(url.absoluteString)
case let decimal as Decimal:
return .number(decimal.description)
case let object as OrderedDictionary<String, Encodable>:
return try wrapObject(object, for: additionalKey)
default:
let encoder = getEncoder(for: additionalKey)
try encodable.encode(to: encoder)
Expand Down
10 changes: 5 additions & 5 deletions Sources/GraphQL/Map/Map.swift
Original file line number Diff line number Diff line change
Expand Up @@ -701,16 +701,16 @@ extension Map: Codable {

/// A wrapper for dictionary keys which are Strings or Ints.
/// This is copied from Swift core: https://github.com/apple/swift/blob/256a9c5ad96378daa03fa2d5197b4201bf16db27/stdlib/public/core/Codable.swift#L5508
internal struct _DictionaryCodingKey: CodingKey {
internal let stringValue: String
internal let intValue: Int?
struct _DictionaryCodingKey: CodingKey {
let stringValue: String
let intValue: Int?

internal init?(stringValue: String) {
init?(stringValue: String) {
self.stringValue = stringValue
intValue = Int(stringValue)
}

internal init?(intValue: Int) {
init?(intValue: Int) {
stringValue = "\(intValue)"
self.intValue = intValue
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/GraphQL/Utilities/NIO+Extensions.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// DictionaryFuture.swift
// NIO+Extensions.swift
// GraphQL
//
// Created by Jeff Seibert on 3/9/18.
Expand Down
4 changes: 2 additions & 2 deletions Sources/GraphQL/Utilities/ValueFromAST.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ func valueFromAST(
}

// Convert solitary value into single-value array
return .array([
try valueFromAST(
return try .array([
valueFromAST(
valueAST: valueAST,
type: itemType,
variables: variables
Expand Down
8 changes: 6 additions & 2 deletions Tests/GraphQLTests/LanguageTests/ParserTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ class ParserTests: XCTestCase {
XCTAssertEqual(error.locations[0].column, 2)
}

XCTAssertThrowsError(try parse(source: "{ ...MissingOn }\nfragment MissingOn Type\n")) { error in
XCTAssertThrowsError(try parse(
source: "{ ...MissingOn }\nfragment MissingOn Type\n"
)) { error in
guard let error = error as? GraphQLError else {
return XCTFail()
}
Expand Down Expand Up @@ -111,7 +113,9 @@ class ParserTests: XCTestCase {
))
}

XCTAssertThrowsError(try parse(source: "type WithImplementsButNoTypes implements {}")) { error in
XCTAssertThrowsError(try parse(
source: "type WithImplementsButNoTypes implements {}"
)) { error in
guard let error = error as? GraphQLError else {
return XCTFail()
}
Expand Down
24 changes: 18 additions & 6 deletions Tests/GraphQLTests/SubscriptionTests/SubscriptionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ import XCTest
type: GraphQLInt
),
],
resolve: { emailAny, _, _, eventLoopGroup, _ throws -> EventLoopFuture<Any?> in
resolve: { emailAny, _, _, eventLoopGroup, _ throws -> EventLoopFuture<
Any?
> in
guard let email = emailAny as? Email else {
throw GraphQLError(
message: "Source is not Email type: \(type(of: emailAny))"
Expand All @@ -98,7 +100,9 @@ import XCTest
inbox: Inbox(emails: db.emails)
))
},
subscribe: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture<Any?> in
subscribe: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture<
Any?
> in
eventLoopGroup.next().makeSucceededFuture(db.publisher.subscribe())
}
),
Expand All @@ -109,7 +113,9 @@ import XCTest
type: GraphQLInt
),
],
resolve: { emailAny, _, _, eventLoopGroup, _ throws -> EventLoopFuture<Any?> in
resolve: { emailAny, _, _, eventLoopGroup, _ throws -> EventLoopFuture<
Any?
> in
guard let email = emailAny as? Email else {
throw GraphQLError(
message: "Source is not Email type: \(type(of: emailAny))"
Expand All @@ -120,7 +126,9 @@ import XCTest
inbox: Inbox(emails: db.emails)
))
},
subscribe: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture<Any?> in
subscribe: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture<
Any?
> in
eventLoopGroup.next().makeSucceededFuture(db.publisher.subscribe())
}
),
Expand Down Expand Up @@ -192,7 +200,9 @@ import XCTest
resolve: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture<Any?> in
eventLoopGroup.next().makeSucceededFuture(nil)
},
subscribe: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture<Any?> in
subscribe: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture<
Any?
> in
didResolveImportantEmail = true
return eventLoopGroup.next()
.makeSucceededFuture(db.publisher.subscribe())
Expand All @@ -203,7 +213,9 @@ import XCTest
resolve: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture<Any?> in
eventLoopGroup.next().makeSucceededFuture(nil)
},
subscribe: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture<Any?> in
subscribe: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture<
Any?
> in
didResolveNonImportantEmail = true
return eventLoopGroup.next()
.makeSucceededFuture(db.publisher.subscribe())
Expand Down