You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
These improve documentation clarity and provide concrete examples for developers to understand the exact GraphQL-to-Swift mappings. In particular:
- Reorganize Design section into separate "Design Philosophy" and "GraphQL to Swift Type Mappings" sections
- Add examples showing GraphQL schema definitions alongside their generated Swift code for all type categories
- Clarify enum type generation: explicitly state they are Swift enums with String raw values
- Add direct links to example projects (HelloWorldServer and StarWars) in Quick Start
- Remove prescriptive language about type conversions in favor of objective API documentation
- Include implementation examples for Object Types showing protocol flexibility
As you build the `Query`, `Mutation`, and `Subscription` types and their resolution logic, you will be forced to define a concrete type for every reachable GraphQL result, according to its generated protocol:
87
+
As you build the `Query`, `Mutation`, and `Subscription` types and their resolution logic, you will be forced to define a concrete type for every reachable GraphQL type, according to its generated protocol:
86
88
87
89
```swift
88
90
structQuery: GraphQLGenerated.Query {
@@ -126,62 +128,243 @@ let result = try await graphql(schema: schema, request: "{ users { name email }
126
128
print(result)
127
129
```
128
130
129
-
## Design
131
+
## Design Philosophy
130
132
131
-
All generated types other than `GraphQLContext` and scalar types are namespaced inside of `GraphQLGenerated` to minimize polluting the inheriting package's type namespace.
133
+
This generator is designed with the following guiding principles:
132
134
133
-
### Root Types
134
-
GraphQL root types (Query, Mutation, and Subscription) are modeled as Swift protocols with static method for each GraphQL field. The user must implement these types and provide them to the `buildGraphQLSchema` function via the `Resolvers` typealiases.
135
+
-**Protocol-based flexibility**: GraphQL types are generated as Swift protocols (except where concrete types are needed), allowing you to implement backing types however you want - structs, actors, classes, or any combination.
136
+
-**Explicit over implicit**: No default resolvers based on reflection. While more verbose, this provides better performance and clearer schema evolution handling.
137
+
-**Type safety**: Leverage Swift's type system to ensure compile-time conformance with your GraphQL schema.
138
+
-**Namespace isolation**: All generated types (except `GraphQLContext` and custom scalars) are namespaced inside `GraphQLGenerated` to avoid polluting your package's type namespace.
139
+
140
+
## GraphQL to Swift Type Mappings
141
+
142
+
This section describes how each GraphQL type is converted to Swift code, with concrete examples from the [HelloWorldServer](Examples/HelloWorldServer) example. Note that all generated types are namespaced inside `GraphQLGenerated`
143
+
144
+
### Root Types (Query, Mutation, Subscription)
145
+
146
+
GraphQL root types are generated as Swift protocols with static methods for each field.
GraphQL object types are modeled as Swift protocols with a method for each GraphQL field. This allows the Swift implementation to be very flexible. Internally, GraphQL passes result objects directly through to subsequent resolvers. By only specifying the interface, we allow the backing types to be incredibly dynamic - they can be simple codable structs or complex stateful actors, reference or values types, or any other type configuration, as long as they conform to the generated protocol.
138
181
139
-
Furthermore, by only referencing protocols, we can have multiple Swift types back a particular GraphQL type, and can easily mock portions of the schema. As an example, consider the following schema snippet:
182
+
GraphQL object types are generated as Swift protocols with instance methods for each field. This allows for flexible implementations - you can use structs, actors, classes, or any other type that conforms to the protocol.
This package does not provide default resolvers based on reflection of the type's properties. While this can cause the conformance code to be more verbose, it was chosen to improve performance and better handle schema evolution.
227
+
Because these are protocols, you can have multiple implementations of the same GraphQL type (useful for testing or different data sources):
GraphQL interfaces are modeled as a Swift protocol with required methods for each GraphQL field. Implementing objects and interfaces are marked as requiring conformance to the interface protocol.
241
+
242
+
GraphQL interfaces are generated as Swift protocols with required methods for each field. Types implementing the interface will have their protocol marked as conforming to the interface protocol.
GraphQL union types are modeled as a Swift marker protocol, with no required properties or functions. The members of the union have their generated Swift protocol marked as conforming to the to the union protocol.
271
+
272
+
GraphQL union types are generated as Swift marker protocols with no required properties or methods. Union member types have their protocols marked as conforming to the union protocol.
GraphQL input object types are modeled as a concrete Swift struct with a property for each of the GraphQL fields.
305
+
306
+
GraphQL input object types are generated as concrete Swift structs with properties for each field. These are `Codable` and `Sendable`.
307
+
308
+
**GraphQL:**
309
+
```graphql
310
+
inputUserInfo {
311
+
id: ID!
312
+
name: String!
313
+
email: EmailAddress!
314
+
age: Int
315
+
role: Role = USER
316
+
}
317
+
```
318
+
319
+
**GeneratedSwift:**
320
+
```swift
321
+
structUserInfo: Codable, Sendable {
322
+
letid: String
323
+
letname: String
324
+
letemail: GraphQLScalars.EmailAddress
325
+
letage: Int?
326
+
letrole: Role?
327
+
}
328
+
```
178
329
179
330
### Enum Types
180
-
GraphQL enum types are modeled as a concrete Swift enum with a string case for each the GraphQL cases.
331
+
332
+
GraphQL enum types are generated as concrete Swift enums with raw `String` values. Each GraphQL enum case becomes a Swift enum case with its raw value matching the GraphQL case name.
333
+
334
+
**GraphQL:**
335
+
```graphql
336
+
enumRole {
337
+
ADMIN
338
+
USER
339
+
GUEST
340
+
}
341
+
```
342
+
343
+
**Generated Swift:**
344
+
```swift
345
+
enumRole: String, Codable, Sendable {
346
+
caseadmin="ADMIN"
347
+
caseuser="USER"
348
+
caseguest="GUEST"
349
+
}
350
+
```
351
+
352
+
These generated enums can be used directly in your code without any additional implementation.
181
353
182
354
### Scalar Types
183
-
GraphQL scalar types are not modeled by the generator. They are simply referenced as `GraphQLScalars.<name>`, and you are expected to define the type and conform it to `GraphQLScalar`. Since GraphQL uses a different serialization system than Swift, you should be sure that the type's conformance to Swift's `Codable` and GraphQL's `GraphQLScalar` agree on a representation. Here is an example that represents an email address as a raw String:
184
355
356
+
GraphQL scalar types are not generated by the plugin. Instead, they are referenced as `GraphQLScalars.<name>`, and you must define the type and conform it to `GraphQLScalar`.
357
+
358
+
**GraphQL:**
359
+
```graphql
360
+
scalarEmailAddress
361
+
362
+
typeUser {
363
+
email: EmailAddress!
364
+
}
365
+
```
366
+
367
+
**RequiredImplementation:**
185
368
```swift
186
369
extensionGraphQLScalars {
187
370
structEmailAddress: GraphQLScalar {
@@ -191,15 +374,15 @@ extension GraphQLScalars {
191
374
self.email = email
192
375
}
193
376
194
-
//Codability conformance. Represent simply as `email` string.
0 commit comments