Skip to content

Commit e972e2e

Browse files
Merge pull request #87 from NeedleInAJayStack/feature/schemaBuilder
Adds a SchemaBuilder type for modular schema creation
2 parents b2ebace + 691e450 commit e972e2e

File tree

15 files changed

+336
-29
lines changed

15 files changed

+336
-29
lines changed

README.md

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -85,44 +85,59 @@ Now we can finally define the GraphQL API with its schema.
8585
struct MessageAPI : API {
8686
let resolver: Resolver
8787
let schema: Schema<Resolver, Context>
88-
89-
init(resolver: Resolver) throws {
90-
self.resolver = resolver
91-
92-
self.schema = try Schema<Resolver, Context> {
93-
Type(Message.self) {
94-
Field("content", at: \.content)
95-
}
96-
97-
Query {
98-
Field("message", at: Resolver.message)
99-
}
88+
}
89+
90+
let api = MessageAPI(
91+
resolver: Resolver()
92+
schema: try! Schema<Resolver, Context> {
93+
Type(Message.self) {
94+
Field("content", at: \.content)
95+
}
96+
97+
Query {
98+
Field("message", at: Resolver.message)
10099
}
101100
}
102-
}
101+
)
103102
```
104103

104+
Schemas may also be created in a modular way using `SchemaBuilder`:
105+
106+
```
107+
let builder = SchemaBuilder(Resolver.self, Context.self)
108+
builder.add(
109+
Type(Message.self) {
110+
Field("content", at: \.content)
111+
}
112+
)
113+
builder.query.add(
114+
Field("message", at: Resolver.message)
115+
)
116+
let schema = try builder.build()
117+
118+
let api = MessageAPI(
119+
resolver: Resolver()
120+
schema: schema
121+
)
122+
```
123+
105124
⭐️ Notice that `API` allows dependency injection. You could pass mocks of `resolver` and `context` when testing, for example.
106125

107126
#### Querying
108127

109-
To query the schema we need to instantiate the api and pass in an EventLoopGroup to feed the execute function alongside the query itself.
128+
To query the schema we need to pass in a NIO EventLoopGroup to feed the execute function alongside the query itself.
110129

111130
```swift
112131
import NIO
113132

114-
let resolver = Resolver()
115-
let context = Context()
116-
let api = try MessageAPI(resolver: resolver)
117133
let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
118-
119134
defer {
120135
try? group.syncShutdownGracefully()
121136
}
122137

123138
api.execute(
124139
request: "{ message { content } }",
125-
context: context,
140+
context: Context(),
126141
on: group
127142
).whenSuccess { result in
128143
print(result)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/// Type-based components (`Enum`, `Input`, `Interface`, `Scalar`, `Type`, `Union`) subclass from this class
2+
open class TypeComponent<Resolver, Context>: Component<Resolver, Context> {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
@resultBuilder
2+
public enum TypeComponentBuilder<Resolver, Context> {
3+
public static func buildExpression(
4+
_ component: TypeComponent<Resolver, Context>
5+
) -> TypeComponent<Resolver, Context> {
6+
component
7+
}
8+
9+
public static func buildBlock(
10+
_ components: TypeComponent<Resolver, Context>...
11+
) -> [TypeComponent<Resolver, Context>] {
12+
components
13+
}
14+
}

Sources/Graphiti/Enum/Enum.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ public final class Enum<
44
Resolver,
55
Context,
66
EnumType: Encodable & RawRepresentable
7-
>: Component<
7+
>: TypeComponent<
88
Resolver,
99
Context
1010
> where EnumType.RawValue == String {

Sources/Graphiti/Input/Input.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ public final class Input<
44
Resolver,
55
Context,
66
InputObjectType: Decodable
7-
>: Component<
7+
>: TypeComponent<
88
Resolver,
99
Context
1010
> {

Sources/Graphiti/Interface/Interface.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import GraphQL
22

3-
public final class Interface<Resolver, Context, InterfaceType>: Component<Resolver, Context> {
3+
public final class Interface<Resolver, Context, InterfaceType>: TypeComponent<
4+
Resolver,
5+
Context
6+
> {
47
let fields: [FieldComponent<InterfaceType, Context>]
58

69
override func update(typeProvider: SchemaTypeProvider, coders: Coders) throws {

Sources/Graphiti/Mutation/Mutation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public final class Mutation<Resolver, Context>: Component<Resolver, Context> {
2727
return map
2828
}
2929

30-
private init(
30+
init(
3131
name: String,
3232
fields: [FieldComponent<Resolver, Context>]
3333
) {

Sources/Graphiti/Query/Query.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public final class Query<Resolver, Context>: Component<Resolver, Context> {
2727
return map
2828
}
2929

30-
private init(
30+
init(
3131
name: String,
3232
fields: [FieldComponent<Resolver, Context>]
3333
) {

Sources/Graphiti/Scalar/Scalar.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import OrderedCollections
66
/// It is **highly** recommended that you do not subclass this type.
77
/// Instead, modify the encoding/decoding behavior through the `MapEncoder`/`MapDecoder` options available through
88
/// `Coders` or a custom encoding/decoding on the `ScalarType` itself.
9-
open class Scalar<Resolver, Context, ScalarType: Codable>: Component<Resolver, Context> {
9+
open class Scalar<Resolver, Context, ScalarType: Codable>: TypeComponent<Resolver, Context> {
1010
// TODO: Change this no longer be an open class
1111

1212
override func update(typeProvider: SchemaTypeProvider, coders: Coders) throws {

Sources/Graphiti/Schema/Schema.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import NIO
44
public final class Schema<Resolver, Context> {
55
public let schema: GraphQLSchema
66

7-
private init(
7+
init(
88
coders: Coders,
99
components: [Component<Resolver, Context>]
1010
) throws {

0 commit comments

Comments
 (0)