Write type-safe GraphQL services in Haskell
Haskell Other
Latest commit 06b24f1 Feb 3, 2017 @jml committed on GitHub Merge pull request #112 from jml/overloaded-name
Make Name an overloaded string
Permalink
Failed to load latest commit information.
benchmarks Benchmarks for findDuplicates Dec 22, 2016
docs Correct JSON Jan 29, 2017
graphql-wai Update WAI for new API Jan 29, 2017
scripts
src Use OverloadedString for Name in code and tests Feb 3, 2017
tests Use OverloadedString for Name in code and tests Feb 3, 2017
.gitignore Ignore tutorial stack work Dec 22, 2016
.hindent.yaml Initial commit Oct 12, 2016
CHANGELOG.rst
HLint.hs Don't mind if we use `concatMap` instead of `=<<` Jan 29, 2017
LICENSE.Apache-2.0 Fork graphql 0.3 Dec 20, 2016
LICENSE.BSD3 Fork graphql 0.3 Dec 20, 2016
Makefile Ditch the Servant stuff Oct 12, 2016
README.md Update README.md Jan 30, 2017
Setup.hs Initial commit Oct 12, 2016
circle.yml Don't build -Werror by default Jan 30, 2017
examples
graphql-api.cabal Bump v0.1.1 Jan 30, 2017
package.yaml Bump v0.1.1 Jan 30, 2017
stack.yaml

README.md

graphql-api

CircleCI Documentation Status

graphql-api helps you implement a robust GraphQL API in Haskell. By the time a query makes it to your handler you are dealing with strong, static types that make sense for your problem domain. All your handlers are normal Haskell functions because we derive their type signature from the schema. If you have used servant, this will sound familiar.

The library provides type combinators to create a GraphQL schema, and functions to parse and evaluate queries against the schema.

You can find the latest release on hackage.

We implement the GraphQL specification as best as we can in Haskell. We figure they know what they're doing. Even if an alternative API or behaviour looks nicer, we will defer to the spec.

Example

Say we have a simple GraphQL schema like:

type Hello {
  greeting(who: String!): String!
}

which defines a single top-level type Hello which contains a single field, greeting, that takes a single, required argument who.

We can define this schema in Haskell and implement a simple handler like so:

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}

import Data.Text (Text)
import Data.Monoid ((<>))

import GraphQL
import GraphQL.API
import GraphQL.Resolver (Handler)

type Hello = Object "Hello" '[]
  '[ Argument "who" Text :> Field "greeting" Text ]

hello :: Handler IO Hello
hello = pure (\who -> pure ("Hello " <> who))

run :: Text -> IO Response
run = interpretAnonymousQuery @Hello hello

We require GHC 8.0.2 or later for features like the @Hello type application, and for certain bug fixes.

With the code above we can now run a query:

run "{ greeting(who: \"mort\") }"

Which will produce the following GraphQL response:

{
  "data": {
    "greeting": "Hello mort"
  }
}

Status

Our current goal is to gather feedback. We have learned a lot about GraphQL in the course of making this library, but we don't know what a good GraphQL library looks like in Haskell. Please let us know what you think. We won't mind if you file a bug telling us how good the library is.

Because we're still learning, we make no guarantees about API stability, or anything at all really.

We are tracking open problems, missing features & wishlist items in GitHub's issue tracker.

Roadmap

  • Near future:
    • Better error messages (this is really important to us)
    • Full support for recursive data types
    • Close off loose ends in current implementation & gather feedback
  • Medium future:
    • Full schema validation
    • Schema introspection
    • Stabilize public API
  • Long term:
    • Derive client implementations from types
    • Allow users to implement their own type combinators

References

Copyright

All files Copyright (c) 2016-2017 Thomas E. Hunger & Jonathan M. Lange, except:

  • src/GraphQL/Internal/Syntax/AST.hs
  • src/GraphQL/Internal/Syntax/Encoder.hs
  • src/GraphQL/Internal/Syntax/Parser.hs

for which see LICENSE.BSD3 in this repository.