Skip to content

Commit 0b70753

Browse files
feat!: Uses swift concurrency under the hood
This removes the NIO dependency. It is breaking because it removes all Swift NIO-isms that were present in the public APIs (like EventLoopFuture and EventLoopGroup argument/return types).
1 parent cedafbc commit 0b70753

38 files changed

+1229
-2200
lines changed

Package.resolved

Lines changed: 5 additions & 32 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@ import PackageDescription
33

44
let package = Package(
55
name: "Graphiti",
6+
platforms: [.macOS(.v10_15), .iOS(.v13), .tvOS(.v13), .watchOS(.v6)],
67
products: [
78
.library(name: "Graphiti", targets: ["Graphiti"]),
89
],
910
dependencies: [
10-
.package(url: "https://github.com/GraphQLSwift/GraphQL.git", from: "3.0.0"),
11+
// TODO: Mainline after merge: https://github.com/GraphQLSwift/GraphQL/pull/166
12+
.package(
13+
url: "https://github.com/NeedleInAJayStack/GraphQL.git",
14+
branch: "feat/swift-concurrency"
15+
),
1116
],
1217
targets: [
1318
.target(name: "Graphiti", dependencies: ["GraphQL"]),

README.md

Lines changed: 9 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Graphiti
1+
# Graphiti
22

33
Graphiti is a Swift library for building GraphQL schemas fast, safely and easily.
44

@@ -86,7 +86,7 @@ struct MessageAPI : API {
8686
let resolver: Resolver
8787
let schema: Schema<Resolver, Context>
8888
}
89-
89+
9090
let api = MessageAPI(
9191
resolver: Resolver()
9292
schema: try! Schema<Resolver, Context> {
@@ -124,7 +124,7 @@ let api = MessageAPI(
124124
resolver: Resolver()
125125
schema: schema
126126
)
127-
```
127+
```
128128

129129
</details>
130130
<details>
@@ -136,7 +136,7 @@ final class ChatSchema: PartialSchema<Resolver, Context> {
136136
public override var types: Types {
137137
Type(Message.self) {
138138
Field("content", at: \.content)
139-
}
139+
}
140140
}
141141

142142
@FieldDefinitions
@@ -152,7 +152,7 @@ let api = MessageAPI(
152152
resolver: Resolver()
153153
schema: schema
154154
)
155-
```
155+
```
156156

157157
</details>
158158

@@ -164,7 +164,7 @@ let chatSchema = PartialSchema<Resolver, Context>(
164164
types: {
165165
Type(Message.self) {
166166
Field("content", at: \.content)
167-
}
167+
}
168168
},
169169
query: {
170170
Field("message", at: Resolver.message)
@@ -178,7 +178,7 @@ let api = MessageAPI(
178178
resolver: Resolver()
179179
schema: schema
180180
)
181-
```
181+
```
182182

183183
</details>
184184

@@ -190,20 +190,10 @@ let api = MessageAPI(
190190

191191
#### Querying
192192

193-
To query the schema we need to pass in a NIO EventLoopGroup to feed the execute function alongside the query itself.
194-
195193
```swift
196-
import NIO
197-
198-
let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
199-
defer {
200-
try? group.syncShutdownGracefully()
201-
}
202-
203194
let result = try await api.execute(
204195
request: "{ message { content } }",
205-
context: Context(),
206-
on: group
196+
context: Context()
207197
)
208198
print(result)
209199
```
@@ -228,27 +218,13 @@ struct Resolver {
228218
}
229219
```
230220

231-
#### NIO resolvers
232-
233-
The resolver functions also support `NIO`-style concurrency. To do so, just add one more parameter with type `EventLoopGroup` to the resolver function and change the return type to `EventLoopFuture<YouReturnType>`. Don't forget to import NIO.
234-
235-
```swift
236-
import NIO
237-
238-
struct Resolver {
239-
func message(context: Context, arguments: NoArguments, group: EventLoopGroup) -> EventLoopFuture<Message> {
240-
group.next().makeSucceededFuture(context.message())
241-
}
242-
}
243-
```
244-
245221
#### Subscription
246222

247223
This library supports GraphQL subscriptions, and supports them through the Swift Concurrency `AsyncThrowingStream` type. See the [Usage Guide](UsageGuide.md#subscriptions) for details.
248224

249225
If you are unable to use Swift Concurrency, you must create a concrete subclass of the `EventStream` class that implements event streaming
250226
functionality. If you don't feel like creating a subclass yourself, you can use the [GraphQLRxSwift](https://github.com/GraphQLSwift/GraphQLRxSwift) repository
251-
to integrate [RxSwift](https://github.com/ReactiveX/RxSwift) observables out-of-the-box. Or you can use that repository as a reference to connect a different
227+
to integrate [RxSwift](https://github.com/ReactiveX/RxSwift) observables out-of-the-box. Or you can use that repository as a reference to connect a different
252228
stream library like [ReactiveSwift](https://github.com/ReactiveCocoa/ReactiveSwift), [OpenCombine](https://github.com/OpenCombine/OpenCombine), or
253229
one that you've created yourself.
254230

Sources/Graphiti/API/API.swift

Lines changed: 2 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import GraphQL
2-
import NIO
32

43
public protocol API {
54
associatedtype Resolver
@@ -12,80 +11,6 @@ public extension API {
1211
func execute(
1312
request: String,
1413
context: ContextType,
15-
on eventLoopGroup: EventLoopGroup,
16-
variables: [String: Map] = [:],
17-
operationName: String? = nil,
18-
validationRules: [(ValidationContext) -> Visitor] = []
19-
) -> EventLoopFuture<GraphQLResult> {
20-
return schema.execute(
21-
request: request,
22-
resolver: resolver,
23-
context: context,
24-
eventLoopGroup: eventLoopGroup,
25-
variables: variables,
26-
operationName: operationName,
27-
validationRules: validationRules
28-
)
29-
}
30-
31-
func execute(
32-
request: GraphQLRequest,
33-
context: ContextType,
34-
on eventLoopGroup: EventLoopGroup,
35-
validationRules: [(ValidationContext) -> Visitor] = []
36-
) -> EventLoopFuture<GraphQLResult> {
37-
return execute(
38-
request: request.query,
39-
context: context,
40-
on: eventLoopGroup,
41-
variables: request.variables,
42-
operationName: request.operationName,
43-
validationRules: validationRules
44-
)
45-
}
46-
47-
func subscribe(
48-
request: String,
49-
context: ContextType,
50-
on eventLoopGroup: EventLoopGroup,
51-
variables: [String: Map] = [:],
52-
operationName: String? = nil,
53-
validationRules: [(ValidationContext) -> Visitor] = []
54-
) -> EventLoopFuture<SubscriptionResult> {
55-
return schema.subscribe(
56-
request: request,
57-
resolver: resolver,
58-
context: context,
59-
eventLoopGroup: eventLoopGroup,
60-
variables: variables,
61-
operationName: operationName,
62-
validationRules: validationRules
63-
)
64-
}
65-
66-
func subscribe(
67-
request: GraphQLRequest,
68-
context: ContextType,
69-
on eventLoopGroup: EventLoopGroup,
70-
validationRules: [(ValidationContext) -> Visitor] = []
71-
) -> EventLoopFuture<SubscriptionResult> {
72-
return subscribe(
73-
request: request.query,
74-
context: context,
75-
on: eventLoopGroup,
76-
variables: request.variables,
77-
operationName: request.operationName,
78-
validationRules: validationRules
79-
)
80-
}
81-
}
82-
83-
public extension API {
84-
@available(macOS 10.15, iOS 15, watchOS 8, tvOS 15, *)
85-
func execute(
86-
request: String,
87-
context: ContextType,
88-
on eventLoopGroup: EventLoopGroup,
8914
variables: [String: Map] = [:],
9015
operationName: String? = nil,
9116
validationRules: [(ValidationContext) -> Visitor] = []
@@ -94,35 +19,29 @@ public extension API {
9419
request: request,
9520
resolver: resolver,
9621
context: context,
97-
eventLoopGroup: eventLoopGroup,
9822
variables: variables,
9923
operationName: operationName,
10024
validationRules: validationRules
101-
).get()
25+
)
10226
}
10327

104-
@available(macOS 10.15, iOS 15, watchOS 8, tvOS 15, *)
10528
func execute(
10629
request: GraphQLRequest,
10730
context: ContextType,
108-
on eventLoopGroup: EventLoopGroup,
10931
validationRules: [(ValidationContext) -> Visitor] = []
11032
) async throws -> GraphQLResult {
11133
return try await execute(
11234
request: request.query,
11335
context: context,
114-
on: eventLoopGroup,
11536
variables: request.variables,
11637
operationName: request.operationName,
11738
validationRules: validationRules
11839
)
11940
}
12041

121-
@available(macOS 10.15, iOS 15, watchOS 8, tvOS 15, *)
12242
func subscribe(
12343
request: String,
12444
context: ContextType,
125-
on eventLoopGroup: EventLoopGroup,
12645
variables: [String: Map] = [:],
12746
operationName: String? = nil,
12847
validationRules: [(ValidationContext) -> Visitor] = []
@@ -131,24 +50,20 @@ public extension API {
13150
request: request,
13251
resolver: resolver,
13352
context: context,
134-
eventLoopGroup: eventLoopGroup,
13553
variables: variables,
13654
operationName: operationName,
13755
validationRules: validationRules
138-
).get()
56+
)
13957
}
14058

141-
@available(macOS 10.15, iOS 15, watchOS 8, tvOS 15, *)
14259
func subscribe(
14360
request: GraphQLRequest,
14461
context: ContextType,
145-
on eventLoopGroup: EventLoopGroup,
14662
validationRules: [(ValidationContext) -> Visitor] = []
14763
) async throws -> SubscriptionResult {
14864
return try await subscribe(
14965
request: request.query,
15066
context: context,
151-
on: eventLoopGroup,
15267
variables: request.variables,
15368
operationName: request.operationName,
15469
validationRules: validationRules

Sources/Graphiti/Connection/Connection.swift

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
import Foundation
22
import GraphQL
3-
import NIO
43

54
public struct Connection<Node> {
65
public let edges: [Edge<Node>]
76
public let pageInfo: PageInfo
87
}
98

10-
@available(macOS 10.15, macCatalyst 13.0, iOS 13.0, tvOS 13, watchOS 6.0, *) // For Identifiable
119
public extension Connection where Node: Identifiable, Node.ID: LosslessStringConvertible {
1210
static func id(_ cursor: String) -> Node.ID? {
1311
cursor.base64Decoded().flatMap { Node.ID($0) }
@@ -18,54 +16,6 @@ public extension Connection where Node: Identifiable, Node.ID: LosslessStringCon
1816
}
1917
}
2018

21-
@available(macOS 10.15, macCatalyst 13.0, iOS 13.0, tvOS 13, watchOS 6.0, *) // For Identifiable
22-
public extension EventLoopFuture where Value: Sequence, Value.Element: Identifiable,
23-
Value.Element.ID: LosslessStringConvertible {
24-
func connection(from arguments: Paginatable) -> EventLoopFuture<Connection<Value.Element>> {
25-
connection(from: arguments, makeCursor: Connection<Value.Element>.cursor)
26-
}
27-
28-
func connection(from arguments: ForwardPaginatable)
29-
-> EventLoopFuture<Connection<Value.Element>> {
30-
connection(from: arguments, makeCursor: Connection<Value.Element>.cursor)
31-
}
32-
33-
func connection(from arguments: BackwardPaginatable)
34-
-> EventLoopFuture<Connection<Value.Element>> {
35-
connection(from: arguments, makeCursor: Connection<Value.Element>.cursor)
36-
}
37-
}
38-
39-
public extension EventLoopFuture where Value: Sequence {
40-
func connection(
41-
from arguments: Paginatable,
42-
makeCursor: @escaping (Value.Element) throws -> String
43-
) -> EventLoopFuture<Connection<Value.Element>> {
44-
flatMapThrowing { value in
45-
try value.connection(from: arguments, makeCursor: makeCursor)
46-
}
47-
}
48-
49-
func connection(
50-
from arguments: ForwardPaginatable,
51-
makeCursor: @escaping (Value.Element) throws -> String
52-
) -> EventLoopFuture<Connection<Value.Element>> {
53-
flatMapThrowing { value in
54-
try value.connection(from: arguments, makeCursor: makeCursor)
55-
}
56-
}
57-
58-
func connection(
59-
from arguments: BackwardPaginatable,
60-
makeCursor: @escaping (Value.Element) throws -> String
61-
) -> EventLoopFuture<Connection<Value.Element>> {
62-
flatMapThrowing { value in
63-
try value.connection(from: arguments, makeCursor: makeCursor)
64-
}
65-
}
66-
}
67-
68-
@available(macOS 10.15, macCatalyst 13.0, iOS 13.0, tvOS 13, watchOS 6.0, *) // For Identifiable
6919
public extension Sequence where Element: Identifiable,
7020
Element.ID: LosslessStringConvertible {
7121
func connection(from arguments: Paginatable) throws -> Connection<Element> {

0 commit comments

Comments
 (0)