GraphQLKit
Easy setup of a GraphQL server with Vapor. It uses the GraphQL implementation of Graphiti.
Features
- Arguments, operation name and query support
- Normal access to the
Request
object as in normal Vapor request handlers - Accept JSON in the body of a POST request as the GraphQL query
- POST and GET support
- [ ] Accept
application/graphql
content type requests - Downloadable schema file
- Multi-Resolver support
Installation
import PackageDescription
let package = Package(
dependencies: [
.package(url: "https://github.com/alexsteinerde/graphql-kit.git", from: "2.0.0"),
],
targets: [
.target(name: "App", dependencies: ["GraphQLKit"]),
...
]
)
Getting Started
Define your schema
This package is setup to accept only Request
objects as the context object for the schema. This gives the opportunity to access all functionality that Vapor provides, for example authentication, service management and database access. To see an example implementation please have a look at the vapor-graphql-template
repository.
This package only provides the needed functions to register an existing GraphQL schema on a Vapor application. To define your schema please refer to the Graphiti documentations.
But by including this package some other helper functions are exposed:
Async Resolver
An EventLoopGroup
parameter is no longer required for async resolvers as the Request
context object already provides access to it's EventLoopGroup
attribute eventLoop
.
// Instead of adding an unnecessary parameter
func getAllTodos(store: Request, arguments: NoArguments, _: EventLoopGroup) throws -> EventLoopFuture<[Todo]> {
Todo.query(on: store).all()
}
// You don't need to provide the eventLoopGroup parameter even when resolving a future.
func getAllTodos(store: Request, arguments: NoArguments) throws -> EventLoopFuture<[Todo]> {
Todo.query(on: store).all()
}
Enums
It automatically resolves all cases of an enum if the type conforms to CaseIterable
.
enum TodoState: String, CaseIterable {
case open
case done
case forLater
}
Enum(TodoState.self),
Parent
, Children
and Siblings
Vapor has the functionality to fetch an objects parent, children or siblings automatically with @Parent
, @Children
and @Siblings
types. To integrate this into GraphQL, GraphQLKit provides extensions to the Field
type that lets you use the parent, children or siblings property as a keypath. Fetching of those related objects is then done automatically.
⚠️ Loading related objects in GraphQL has the N+1 problem. A solution would be to build a DataLoader package for Swift. But this hasn't been done yet.
final class User: Model {
...
@Children(for: \.$user)
var todos: [Todo]
...
}
final class Todo: Model {
...
@Parent(key: "user_id")
var user: User
@Siblings(through: TodoTag.self, from: \.$todo, to: \.$tag)
public var tags: [Tag]
...
}
// Schema types
Type(User.self) {
Field("todos", with: \.$todos)
}
Type(Todo.self) {
Field("user", with: \.$user)
Field("tags", with: \.$tags)
}
Register the schema on the application
In your configure.swift
file call the register(graphQLSchema: Schema<YourResolver, Request>, withResolver: YourResolver)
on your Application
instance. By default this registers the GET and POST endpoints at /graphql
. But you can also pass the optional parameter at:
and override the default value.
// Register the schema and it's resolver.
app.register(graphQLSchema: todoSchema, withResolver: TodoAPI())
License
This project is released under the MIT license. See LICENSE for details.
Contribution
You can contribute to this project by submitting a detailed issue or by forking this project and sending a pull request. Contributions of any kind are very welcome :)