{"id":14976198,"url":"https://github.com/nerdsupremacist/graphzahl","last_synced_at":"2025-09-21T01:33:33.857Z","repository":{"id":63919084,"uuid":"248804131","full_name":"nerdsupremacist/GraphZahl","owner":"nerdsupremacist","description":"A Framework to implement Declarative, Type-Safe GraphQL Server APIs using Runtime Magic 🎩","archived":false,"fork":false,"pushed_at":"2022-03-05T10:02:07.000Z","size":3876,"stargazers_count":144,"open_issues_count":16,"forks_count":9,"subscribers_count":7,"default_branch":"develop","last_synced_at":"2025-02-01T07:31:51.566Z","etag":null,"topics":["declarative","graphql","graphql-server","reflection","swift","type-safe"],"latest_commit_sha":null,"homepage":"https://quintero.io/GraphZahl/","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nerdsupremacist.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":["nerdsupremacist"]}},"created_at":"2020-03-20T16:37:26.000Z","updated_at":"2024-12-20T17:09:03.000Z","dependencies_parsed_at":"2023-01-14T14:00:24.752Z","dependency_job_id":null,"html_url":"https://github.com/nerdsupremacist/GraphZahl","commit_stats":null,"previous_names":[],"tags_count":46,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nerdsupremacist%2FGraphZahl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nerdsupremacist%2FGraphZahl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nerdsupremacist%2FGraphZahl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nerdsupremacist%2FGraphZahl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nerdsupremacist","download_url":"https://codeload.github.com/nerdsupremacist/GraphZahl/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238536121,"owners_count":19488661,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["declarative","graphql","graphql-server","reflection","swift","type-safe"],"created_at":"2024-09-24T13:53:29.512Z","updated_at":"2025-09-21T01:33:28.801Z","avatar_url":"https://github.com/nerdsupremacist.png","language":"Swift","funding_links":["https://github.com/sponsors/nerdsupremacist"],"categories":[],"sub_categories":[],"readme":"![low effort logo](https://github.com/nerdsupremacist/GraphZahl/raw/develop/logo.png)\n\n# GraphZahl (Alpha)\n![Swift](https://github.com/nerdsupremacist/GraphZahl/workflows/Swift/badge.svg) ![Documentation](https://github.com/nerdsupremacist/GraphZahl/workflows/Documentation/badge.svg) [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fnerdsupremacist%2FGraphZahl%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/nerdsupremacist/GraphZahl) [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fnerdsupremacist%2FGraphZahl%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/nerdsupremacist/GraphZahl)\n\nCreate the best GraphQL APIs ever using Swift. GraphZahl is a Swift Framework that let's you write your Server the simplest way possible! With a magic, Codable-like API.\n\nHere are the main reasons, why you could like it:\n\n- 📝 Declarative\n- 📦 Compositable and extendable\n- 🔐 Type-Safety\n- 🕓 ZERO Boilerplate\n- 😍 Familiar and Intuitive Codable-like Feel\n- 🤪 Amazing for Quick Prototyping\n\n## TL;DR?\n\nLet's cut the chase and write our Hello World! \n\n```swift\n// Create a GraphQLSchema\nenum HelloWorld: GraphQLSchema {\n\n    // Describe the Query Type \n    class Query: QueryType {\n        func greeting(name: String) -\u003e String {\n            return \"Hello, \\(name)\"\n        }\n    }\n    \n}\n\n// Run a query using .perform\nlet result = HelloWorld.perform(request: \"...\")\n```\n\nAnd you can even connect it to GraphiQL and test it:\n\n![graphiql](https://github.com/nerdsupremacist/GraphZahl/raw/develop/demo/helloworld.png)\n*left: a query for data* **|** *middle: the returned json from our API*  **|** *right: our server API reference*\n\n**Let's break that down!**\n\nEvery GraphQL API begins with a root Schema where you define the Query Type and Mutation Type:\n\n- Query Type (Mandatory): Describes all the read operations that can be done\n- Mutation Type (Optional): Descripes all the write operations\n\nFor now we'll focus on the Query Type. \nGraphZahl will now look at any properties and functions that can be served in GraphQL, and will offer those as fields in your API.\n\nIn our example this means that it will find the function `greeting` and see that all the inputs and outputs are availanle as GraphQL Types and register it. Super easy 😍!\n\n## Installation\n### Swift Package Manager\n\nYou can install GraphZahl via [Swift Package Manager](https://swift.org/package-manager/) by adding the following line to your `Package.swift`:\n\n```swift\nimport PackageDescription\n\nlet package = Package(\n    [...]\n    dependencies: [\n        .package(url: \"https://github.com/nerdsupremacist/GraphZahl.git\", from: \"0.1.0-alpha.\")\n        \n        // It is recommended to use GraphZahl alongside Vapor\n        .package(url: \"https://github.com/nerdsupremacist/graphzahl-vapor-support.git\", from: \"0.1.0-alpha.\")\n    ]\n)\n```\n\n## Usage\n\nMost users of GraphZahl need to understand the six main provided protocols:\n\n- [GraphQLObject](#graphqlobject---reference):  A type that is composed from multiple properties and functions\n- [GraphQLSchema](#graphqlobject---reference):  The root of any API\n- [GraphQLScalar](#graphqlscalar---reference):  A singular value\n- [GraphQLEnum](#graphqlenum----reference): An simple enum that is RawRepresentable with String\n- [GraphQLUnion](#graphqlunion----reference): An enum where every case has an associated value that is a GraphQLObject\n- [GraphQLInputObject](#graphqlinputobject---reference): A struct that you expect as an argument to a funtion\n\nAs well as the extensions that enable you to get the most of GraphZahl alongside other common server-side libraries like Vapor and Fluent.\n\n### GraphQLObject - [Reference](https://quintero.io/GraphZahl/Protocols/GraphQLObject.html)\n\nYou can provide any class you want by simply making it implement  `GraphQLObject`. \n\nAnd voila 😍 !!!! You don't have to implement anything. GraphZahl will do all the magic for you:\n\n- Every property that is either:\n    a. a GraphQL Object, \n    a. Scalar \n    a. Enum\n    a. or Union\n\nwill be available via GraphQL. Zero hassle. Crazy!!!\n\n- Every method where:\n    a. every input is a Scalar, Enum or Input Object\n    a. the return type is either:\n        a. a GraphQL Object, \n        a. Scalar \n        a. Enum\n        a. or Union\n\nis now also available! Just like that. Awesome!!!\n\n**Note:** when it comes to GraphQL Types GraphZahl also supports Optionals, Arrays and Futures out of the box, thanks to Conditional Conformance.\n\n**Let's try it:**\n\nWe define our class. With some properties and methods:\n\n```swift\nclass MyObject: GraphQLObject {\n    let greeting = \"Hello World!\"\n    let favouriteNumber = 42\n\n    func count(to number: Int) -\u003e String {\n        return (0..\u003cnumber).map(String.init).joined(separator: \", \")\n    }\n}\n```\n\nAnd we can see it appear in our API:\n\n![](https://github.com/nerdsupremacist/GraphZahl/raw/develop/demo/object.png)\n*left: a query for the data of MyObject*  **|** *middle: the returned json from our API*  **|** *right: the type definition of MyObject*\n\nYour object can also return nested objects:\n\n```swift\nclass OtherObject: GraphQLObject {\n    let number: Int\n    \n    init(number: Int) {\n        self.number = number\n    }\n}\n\nclass MyObject: GraphQLObject {\n    ...\n    \n    let other = OtherObject(number: 1337)\n    let others = [OtherObject(number: 0), OtherObject(number: 1)] // Arrays also work\n}\n```\n\nAnd you can see the results immediately:\n\n![](https://github.com/nerdsupremacist/GraphZahl/raw/develop/demo/nestedobject.png)\n\n### GraphQLSchema - [Reference](https://quintero.io/GraphZahl/Protocols/GraphQLSchema.html)\n\nA Schema is basically the namespace where you define two objects: A Query and a Mutation Type.\nThe query and mutation behave like regular `GraphQLObject`s. All the features mentioned above will be included out of the box.\n\nThe QueryType is mandatory and always has to be defined! If your API doesn't need Mutations, then you're done.\n\n**What if you want to make data user dependent?**\n\nThat's why Query and Mutation Types come with an extra constraint (for simplicity this was omitted in the snippets before).\nThey have what we call an associated `ViewerContext` and need an initializer with that ViewerContext. \n*Note: the ViewerContext of the Query and the Mutation have to Match.*\n\nFor example a Todo App might look like this:\n\n```swift\nenum TodoApp: GraphQLSchema {\n    typealias ViewerContext = LoggedInUser?\n\n    class Query: QueryType {\n        let user: LoggedInUser?\n        \n        func myTodos() -\u003e [Todo]? {\n            return user?.todosFromDB()\n        }\n\n        required init(viewerContext user: LoggedInUser?) {\n            self.user = user\n        }\n    }\n    \n    class Mutation: MutationType {\n        let user: LoggedInUser?\n        \n        func deleteTodo(id: UUID) -\u003e Todo? {\n            return user?.todos.find(id: id).delete()\n        }\n\n        required init(viewerContext user: LoggedInUser?) {\n            self.user = user\n        }\n    }\n}\n```\n\nIf you don't need a Viewer Context just set it to `Void`:\n\n```swift\nenum HelloWorld: GraphQLSchema {\n    typealias ViewerContext = Void\n\n    class Query: QueryType {\n        func greeting(name: String) -\u003e String {\n            return \"Hello, \\(name)\"\n        }\n\n        required init(viewerContext: Void) { }\n    }\n}\n```\n\n### GraphQLScalar - [Reference](https://quintero.io/GraphZahl/Protocols/GraphQLScalar.html)\n\nIf you have a value that can be represented as a standard Scalar Value, you can return that value as well, with the added Type Safety benefit, of not mixing it with the standard types. \n\nTo implement a `GraphQLScalar` you need to be able to encode and decode it as a `ScalarValue` (String, Number, Bool)   \n\nFor example if you want to return URLs you can implement it in an extension:\n\n```swift\nextension URL: GraphQLScalar {\n    public init(scalar: ScalarValue) throws {\n        // attempt to read a string and read a url from it\n        guard let url = URL(string: try scalar.string()) else {\n            throw ...\n        }\n        self = url\n    }\n\n    public func encodeScalar() throws -\u003e ScalarValue {\n        // delegate encoding to absolute string\n        return try absoluteString.encodeScalar()\n    }\n}\n```\n\nAnd presto! Every time a URL comes up in an Object, it will be made available:\n\n```swift\nenum HelloWorld: GraphQLSchema {\n    class Query: QueryType {\n        let url = URL(string: \"https://github.com/nerdsupremacist/GraphZahl\")\n    }\n}\n```\n\n![](https://github.com/nerdsupremacist/GraphZahl/raw/develop/demo/urlscalar.png)\n\nYou can do this with virtually all kinds of types: Dates in the format of your choice, Percentages, HTML Text, whatever you want.\n\n### GraphQLEnum  - [Reference](https://quintero.io/GraphZahl/Protocols/GraphQLEnum.html)\n\nThe last one is the simplest case. If you want to support an enum in your API, it has to be RawRepresentable with String and implement `GraphQLEnum`.\n\nIf your enum is `CaseIterable` that's it!\n\n```swift\nenum Envirornment: String, CaseIterable, GraphQLEnum {\n    case production\n    case development\n    case testing\n}\n```\n\nIf you want to compute your Enum Cases yourself you can implement the `cases` function.\n\n### GraphQLUnion  - [Reference](https://quintero.io/GraphZahl/Protocols/GraphQLUnion.html)\n\nGraphZahl supports Union Types. To implement a Union Type you just have to implement an enum where every case has an associated type that is an Object\n\n```swift\nenum SearchResult: GraphQLUnion {\n    case user(User)\n    case page(Page)\n    case group(Group)\n}\n\nclass Query: QueryType {\n    func search(term: String) -\u003e [SearchResult] {\n        return [\n            .user(user),\n            .page(page),\n            .group(group),\n        ]\n    }\n}\n```\n\n### GraphQLInputObject - [Reference](https://quintero.io/GraphZahl/Protocols/GraphQLInputObject.html)\n\nIf you want to take specific structs as arguments for functions you can make them conform to `GraphQLInputObject`\n\n```swift\nenum Order: String, CaseIterable, GraphQLEnum {\n    case ascending\n    case descending\n}\n\nstruct Options: GraphQLInputObject {\n    let safeSearch: Bool\n    let order: Order\n}\n\nclass Query: QueryType {\n    func search(term: String,\n                arguments: Options = Options(safeSearch: true, order: .ascending)) -\u003e [SearchResult] {\n                \n        return [...]\n    }\n}\n```\n\n### Subclassing Support\n\nGraphZahl supports subclassing, but due to Subclassing not being available in GraphQL, it is abstracted as an extra Interface.\n\nFor example:\n\n```swift\nclass A: GraphQLObject {\n    ...\n}\n\nclass B: A {\n    ...\n}\n```\n\nwill be represented as the interface `A` and the concrete types `__A` and `B`:\n\n```graphql\n// Interface that displays the output of any A\ninterface A {\n    ...\n}\n\n// An instance of the superclass A\ntype __A implements A {\n    ...\n}\n\n// An instance of the subclass B\ntype B implements A {\n    ...\n}\n```\n\n### KeyPath Support\n\nIf you take KeyPaths as an argument of a function, GraphZahl will create an enum mapping to all the properties with the same type.\n\nFor example:\n\n```swift\nclass SearchResult: GraphQLObject {\n    let relevance: Int\n    let popularity: Int\n    let name: String\n}\n\nclass Schema: GraphQLSchema {\n    class Query: QueryType {\n        func search(term: String,\n                    sortBy: KeyPath\u003cSearchResult, Int\u003e) -\u003e [SearchResult] {\n\n            return [SearchResult]().sort { $0[keyPath: sortBy] \u003c $1[keyPath: sortBy] }\n        }\n    }\n}\n```\n\nAnd the outputed definition is:\n\n```graphql\ntype Query {\n  search(sortBy: SearchResultField!, term: String!): [SearchResult!]!\n}\n\ntype SearchResult {\n  name: String!\n  popularity: Int!\n  relevance: Int!\n}\n\nenum SearchResultField {\n  Relevance\n  Popularity\n}\n```\n\n## Extensions and Plugins\n\nThere's also some extensions on top of GraphZahl to add support for different scenarios that are not necessarily the norm:\n\n### Vapor Support (Recommended)\n\nTo serve your API via Vapor, you can use [graphzahl-vapor-support](https://github.com/nerdsupremacist/graphzahl-vapor-support):\n\n```swift\nenum HelloWorld: GraphQLSchema {\n    class Query: QueryType {\n        func greeting(name: String) -\u003e String {\n            return \"Hello, \\(name)\"\n        }\n    }\n}\n\n// Add the API to the Routes of your Vapor App\napp.routes.graphql(path: \"api\", \"graphql\", use: HelloWorld.self)\n```\n\nAnd you can even add GraphiQL:\n\n```swift\napp.routes.graphql(path: \"api\", \"graphql\", use: HelloWorld.self, includeGraphiQL: true)\n```\n\n### Fluent Support\n\nTo use Fluent Types and Models in your API, you can use [graphzahl-fluent-support](https://github.com/nerdsupremacist/graphzahl-fluent-support):\n\n```swift\nenum API: GraphQLSchema {\n    typealias ViewerContext = Database\n\n    class Query: QueryType {\n        let database: Database\n\n        // QueryBuilders are supported with additional paging API\n        func todos() -\u003e QueryBuilder\u003cTodo\u003e {\n            return Todo.query(on: database)\n        }\n\n        required init(viewerContext database: Database) {\n            self.database = database\n        }\n    }\n    \n    ...\n}\n```\n\nIt adds support for:\n\n- QueryBuilder\u003cT\u003e\n- @Parent\n- @Children\n- @Siblings\n- @Field\n- @ID\n\n## Deploy\n\n### Heroku\n\nIf you're deploying to Heroku, it's super simple. You'll need 2 things:\n\n*1. Add the build pack*\n\nAdd the build pack to heroku:\n\n```bash\nheroku buildpacks:set nerdsupremacist/graph-zahl\n```\n\n*2. Add a Procfile*\n\nIn our Repo we will add a Procfile that will tell Heroku the starting point of our app:\n\nFor example, where the Target of our API is called `MyServer` and is using Vapor:\n\n```\nweb: MyServer serve --env production --hostname 0.0.0.0 --port $PORT\n```\n\nYou can also take some inspiration from the Deployment documentation for [Vapor](https://docs.vapor.codes/3.0/deploy/heroku/).\n\n### Building for Linux\n\nIf you're building a GraphZahl app for Linux, you'll need to add `-E` linker flag. For example:\n\n```bash\nswift build -Xlinker -E {OTHER_FLAGS} -c debug\n```\n\n## Known Issues\n\n- Due to issues with combinatorics the amount of arguments for a method has been limited\n- Calling methods hasn't been tested against every argument and return type combination possible. If you encounter any crashes or failures, please open an issue\n\n## Contributions\nContributions are welcome and encouraged!\n\n## Related Work\n\n![](https://github.com/nerdsupremacist/Graphaello/raw/develop/logo.png)\n\nGraphZahl works best when coupled with [Graphaello](https://github.com/nerdsupremacist/Graphaello) on the Client Side. Graphaello enables you to use GraphQL directly from your SwiftUI Views.\n\n## Learn\nGraphZahl is named after Count von Count from Sesame Street but in German \"Graf Zahl\".\n\nGraphZahl uses [GraphQLSwift](https://github.com/GraphQLSwift/GraphQL), [Runtime](https://github.com/wickwirew/Runtime) and [Swift NIO](https://www.github.com/apple/swift-nio) under the Hood.\nIf you are looking for an alternative check out [Graphiti](https://github.com/GraphQLSwift/Graphiti), which is more verbose and complex to use, but offers you more control and better performance.\n\nThis is currenlty a research project. More details about how it works, will be published later.\nThis was very difficult to build, so trust me, I really want to talk in detail about it... ;)\n\n## License\nGraphZahl is available under the MIT license. See the LICENSE file for more info.\n\nThis project is being done under the supervision of the Chair for Applied Software Enginnering at the Technical University of Munich. The chair has everlasting rights to use and maintain this tool.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnerdsupremacist%2Fgraphzahl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnerdsupremacist%2Fgraphzahl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnerdsupremacist%2Fgraphzahl/lists"}