Skip to content

Commit 122c939

Browse files
feature: Adds async/await public APIs
1 parent 283cc4d commit 122c939

File tree

2 files changed

+136
-0
lines changed

2 files changed

+136
-0
lines changed

Sources/GraphQL/GraphQL.swift

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,3 +226,115 @@ public func graphqlSubscribe(
226226
operationName: operationName
227227
)
228228
}
229+
230+
// MARK: Async/Await
231+
232+
#if compiler(>=5.5) && canImport(_Concurrency)
233+
234+
@available(macOS 12, iOS 15, watchOS 8, tvOS 15, *)
235+
/// This is the primary entry point function for fulfilling GraphQL operations
236+
/// by parsing, validating, and executing a GraphQL document along side a
237+
/// GraphQL schema.
238+
///
239+
/// More sophisticated GraphQL servers, such as those which persist queries,
240+
/// may wish to separate the validation and execution phases to a static time
241+
/// tooling step, and a server runtime step.
242+
///
243+
/// - parameter queryStrategy: The field execution strategy to use for query requests
244+
/// - parameter mutationStrategy: The field execution strategy to use for mutation requests
245+
/// - parameter subscriptionStrategy: The field execution strategy to use for subscription requests
246+
/// - parameter instrumentation: The instrumentation implementation to call during the parsing, validating, execution, and field resolution stages.
247+
/// - parameter schema: The GraphQL type system to use when validating and executing a query.
248+
/// - parameter request: A GraphQL language formatted string representing the requested operation.
249+
/// - parameter rootValue: The value provided as the first argument to resolver functions on the top level type (e.g. the query object type).
250+
/// - parameter contextValue: A context value provided to all resolver functions functions
251+
/// - parameter variableValues: A mapping of variable name to runtime value to use for all variables defined in the `request`.
252+
/// - parameter operationName: The name of the operation to use if `request` contains multiple possible operations. Can be omitted if `request` contains only one operation.
253+
///
254+
/// - throws: throws GraphQLError if an error occurs while parsing the `request`.
255+
///
256+
/// - returns: returns a `Map` dictionary containing the result of the query inside the key `data` and any validation or execution errors inside the key `errors`. The value of `data` might be `null` if, for example, the query is invalid. It's possible to have both `data` and `errors` if an error occurs only in a specific field. If that happens the value of that field will be `null` and there will be an error inside `errors` specifying the reason for the failure and the path of the failed field.
257+
public func graphql(
258+
queryStrategy: QueryFieldExecutionStrategy = SerialFieldExecutionStrategy(),
259+
mutationStrategy: MutationFieldExecutionStrategy = SerialFieldExecutionStrategy(),
260+
subscriptionStrategy: SubscriptionFieldExecutionStrategy = SerialFieldExecutionStrategy(),
261+
instrumentation: Instrumentation = NoOpInstrumentation,
262+
schema: GraphQLSchema,
263+
request: String,
264+
rootValue: Any = (),
265+
context: Any = (),
266+
eventLoopGroup: EventLoopGroup,
267+
variableValues: [String: Map] = [:],
268+
operationName: String? = nil
269+
) async throws -> GraphQLResult {
270+
return try await graphql(
271+
queryStrategy: queryStrategy,
272+
mutationStrategy: mutationStrategy,
273+
subscriptionStrategy: subscriptionStrategy,
274+
instrumentation: instrumentation,
275+
schema: schema,
276+
request: request,
277+
rootValue: rootValue,
278+
context: context,
279+
eventLoopGroup: eventLoopGroup,
280+
variableValues: variableValues,
281+
operationName: operationName
282+
).get()
283+
}
284+
285+
@available(macOS 12, iOS 15, watchOS 8, tvOS 15, *)
286+
/// This is the primary entry point function for fulfilling GraphQL subscription
287+
/// operations by parsing, validating, and executing a GraphQL subscription
288+
/// document along side a GraphQL schema.
289+
///
290+
/// More sophisticated GraphQL servers, such as those which persist queries,
291+
/// may wish to separate the validation and execution phases to a static time
292+
/// tooling step, and a server runtime step.
293+
///
294+
/// - parameter queryStrategy: The field execution strategy to use for query requests
295+
/// - parameter mutationStrategy: The field execution strategy to use for mutation requests
296+
/// - parameter subscriptionStrategy: The field execution strategy to use for subscription requests
297+
/// - parameter instrumentation: The instrumentation implementation to call during the parsing, validating, execution, and field resolution stages.
298+
/// - parameter schema: The GraphQL type system to use when validating and executing a query.
299+
/// - parameter request: A GraphQL language formatted string representing the requested operation.
300+
/// - parameter rootValue: The value provided as the first argument to resolver functions on the top level type (e.g. the query object type).
301+
/// - parameter contextValue: A context value provided to all resolver functions
302+
/// - parameter variableValues: A mapping of variable name to runtime value to use for all variables defined in the `request`.
303+
/// - parameter operationName: The name of the operation to use if `request` contains multiple possible operations. Can be omitted if `request` contains only one operation.
304+
///
305+
/// - throws: throws GraphQLError if an error occurs while parsing the `request`.
306+
///
307+
/// - returns: returns a SubscriptionResult containing the subscription observable inside the key `observable` and any validation or execution errors inside the key `errors`. The
308+
/// value of `observable` might be `null` if, for example, the query is invalid. It's not possible to have both `observable` and `errors`. The observable payloads are
309+
/// GraphQLResults which contain the result of the query inside the key `data` and any validation or execution errors inside the key `errors`. The value of `data` might be `null`.
310+
/// It's possible to have both `data` and `errors` if an error occurs only in a specific field. If that happens the value of that field will be `null` and there
311+
/// will be an error inside `errors` specifying the reason for the failure and the path of the failed field.
312+
public func graphqlSubscribe(
313+
queryStrategy: QueryFieldExecutionStrategy = SerialFieldExecutionStrategy(),
314+
mutationStrategy: MutationFieldExecutionStrategy = SerialFieldExecutionStrategy(),
315+
subscriptionStrategy: SubscriptionFieldExecutionStrategy = SerialFieldExecutionStrategy(),
316+
instrumentation: Instrumentation = NoOpInstrumentation,
317+
schema: GraphQLSchema,
318+
request: String,
319+
rootValue: Any = (),
320+
context: Any = (),
321+
eventLoopGroup: EventLoopGroup,
322+
variableValues: [String: Map] = [:],
323+
operationName: String? = nil
324+
) async throws -> SubscriptionResult {
325+
return try await graphqlSubscribe(
326+
queryStrategy: queryStrategy,
327+
mutationStrategy: mutationStrategy,
328+
subscriptionStrategy: subscriptionStrategy,
329+
instrumentation: instrumentation,
330+
schema: schema,
331+
request: request,
332+
rootValue: rootValue,
333+
context: context,
334+
eventLoopGroup: eventLoopGroup,
335+
variableValues: variableValues,
336+
operationName: operationName
337+
).get()
338+
}
339+
340+
#endif

Tests/GraphQLTests/HelloWorldTests/HelloWorldTests.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,28 @@ class HelloWorldTests : XCTestCase {
6262

6363
XCTAssertEqual(result, expected)
6464
}
65+
66+
#if compiler(>=5.5) && canImport(_Concurrency)
67+
68+
@available(macOS 12, iOS 15, watchOS 8, tvOS 15, *)
69+
func testHelloAsync() async throws {
70+
let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
71+
72+
defer {
73+
XCTAssertNoThrow(try group.syncShutdownGracefully())
74+
}
75+
76+
let query = "{ hello }"
77+
let expected = GraphQLResult(data: ["hello": "world"])
78+
79+
let result = try await graphql(
80+
schema: schema,
81+
request: query,
82+
eventLoopGroup: group
83+
)
84+
85+
XCTAssertEqual(result, expected)
86+
}
87+
88+
#endif
6589
}

0 commit comments

Comments
 (0)