GraphQL server with a focus on ease of use

Overview

graphql-go Sourcegraph Build Status GoDoc

The goal of this project is to provide full support of the GraphQL draft specification with a set of idiomatic, easy to use Go packages.

While still under heavy development (internal APIs are almost certainly subject to change), this library is safe for production use.

Features

  • minimal API
  • support for context.Context
  • support for the OpenTracing standard
  • schema type-checking against resolvers
  • resolvers are matched to the schema based on method sets (can resolve a GraphQL schema with a Go interface or Go struct).
  • handles panics in resolvers
  • parallel execution of resolvers
  • subscriptions

Roadmap

We're trying out the GitHub Project feature to manage graphql-go's development roadmap. Feedback is welcome and appreciated.

(Some) Documentation

Basic Sample

package main

import (
        "log"
        "net/http"

        graphql "github.com/graph-gophers/graphql-go"
        "github.com/graph-gophers/graphql-go/relay"
)

type query struct{}

func (_ *query) Hello() string { return "Hello, world!" }

func main() {
        s := `
                type Query {
                        hello: String!
                }
        `
        schema := graphql.MustParseSchema(s, &query{})
        http.Handle("/query", &relay.Handler{Schema: schema})
        log.Fatal(http.ListenAndServe(":8080", nil))
}

To test:

$ curl -XPOST -d '{"query": "{ hello }"}' localhost:8080/query

Resolvers

A resolver must have one method or field for each field of the GraphQL type it resolves. The method or field name has to be exported and match the schema's field's name in a non-case-sensitive way. You can use struct fields as resolvers by using SchemaOpt: UseFieldResolvers(). For example,

opts := []graphql.SchemaOpt{graphql.UseFieldResolvers()}
schema := graphql.MustParseSchema(s, &query{}, opts...)

When using UseFieldResolvers schema option, a struct field will be used only when:

  • there is no method for a struct field
  • a struct field does not implement an interface method
  • a struct field does not have arguments

The method has up to two arguments:

  • Optional context.Context argument.
  • Mandatory *struct { ... } argument if the corresponding GraphQL field has arguments. The names of the struct fields have to be exported and have to match the names of the GraphQL arguments in a non-case-sensitive way.

The method has up to two results:

  • The GraphQL field's value as determined by the resolver.
  • Optional error result.

Example for a simple resolver method:

func (r *helloWorldResolver) Hello() string {
	return "Hello world!"
}

The following signature is also allowed:

func (r *helloWorldResolver) Hello(ctx context.Context) (string, error) {
	return "Hello world!", nil
}

Schema Options

  • UseStringDescriptions() enables the usage of double quoted and triple quoted. When this is not enabled, comments are parsed as descriptions instead.
  • UseFieldResolvers() specifies whether to use struct field resolvers.
  • MaxDepth(n int) specifies the maximum field nesting depth in a query. The default is 0 which disables max depth checking.
  • MaxParallelism(n int) specifies the maximum number of resolvers per request allowed to run in parallel. The default is 10.
  • Tracer(tracer trace.Tracer) is used to trace queries and fields. It defaults to trace.OpenTracingTracer.
  • ValidationTracer(tracer trace.ValidationTracer) is used to trace validation errors. It defaults to trace.NoopValidationTracer.
  • Logger(logger log.Logger) is used to log panics during query execution. It defaults to exec.DefaultLogger.
  • DisableIntrospection() disables introspection queries.

Custom Errors

Errors returned by resolvers can include custom extensions by implementing the ResolverError interface:

type ResolverError interface {
	error
	Extensions() map[string]interface{}
}

Example of a simple custom error:

type droidNotFoundError struct {
	Code    string `json:"code"`
	Message string `json:"message"`
}

func (e droidNotFoundError) Error() string {
	return fmt.Sprintf("error [%s]: %s", e.Code, e.Message)
}

func (e droidNotFoundError) Extensions() map[string]interface{} {
	return map[string]interface{}{
		"code":    e.Code,
		"message": e.Message,
	}
}

Which could produce a GraphQL error such as:

{
  "errors": [
    {
      "message": "error [NotFound]: This is not the droid you are looking for",
      "path": [
        "droid"
      ],
      "extensions": {
        "code": "NotFound",
        "message": "This is not the droid you are looking for"
      }
    }
  ],
  "data": null
}

Examples

Companies that use this library

Issues
  • Support subscriptions

    Support subscriptions

    This addresses the subscription part of #15.

    Please look through subscription_test.go which has an example subscription resolver implemented.

    I've left // TODO: ... markers where I feel the implementation could be improved, though not sure how.

    Missing from this PR is tracing for the execution of each query.

    I've put together a graphQL server that supports subscriptions as a proof of concept based on these changes (though it might be out of sync since this PR is changing)

    opened by matiasanaya 35
  • Use Struct Field Resolver instead of Method

    Use Struct Field Resolver instead of Method

    This fixes #28. Essentially, it reduces lot of boilerplate code by making use of struct field as resolvers instead of creating methods for each struct field.

    Now, methods are required only when

    1. a struct implements a GraphQL interface. In this case, you create methods for fields which overlap
    2. a struct exposes a GraphQL field that accepts additional arguments i.e., first: Int, last: Int etc.
    3. there is GraphQL union type

    By using struct fields as resolvers, one could also benefit from DRY codebase by not having a pair of a struct which look the same (one for GraphQL and one for DB)

    Does this break existing API?

    No. This change is completely transparent and you can continue using your existing codebase.

    Can I still continue using methods as resolvers?

    Yes, by default, it uses method resolvers.

    How can I use struct fields as resolvers?

    When invoking graphql.ParseSchema() or graphql.MustParseSchema() to parse the schema, you pass in graphql.UseFieldResolvers() as an argument. For an example, take a look at ./example/social/server/server.go

    Additional Notes

    • also fixes #124
    • for an example, take a look at ./example/social/social.go & ./example/social/server/server.go
    • Unit tests are missing
    opened by salman-ahmad 28
  • Handle separate schemas?

    Handle separate schemas?

    Hello,

    Is there a (good) way to handle several separate schemas (modularization)? As it is, only a single schema can be parsed by this lib. I have several schemas split in several files.

    Thanks, Howe

    opened by howesteve 22
  • Feature Request: Schema Stitching. Combining multiple schemas into one

    Feature Request: Schema Stitching. Combining multiple schemas into one

    Hi,

    are there any plan for implemente this feature or similar??

    Thanks a lot for all yours work.

    Ref: https://dev-blog.apollodata.com/graphql-schema-stitching-8af23354ac37

    help wanted 
    opened by arquio 20
  • Update handler to follow best practices

    Update handler to follow best practices

    It would be really cool if relay.Handler can be updated to support the best practices outlined here: http://graphql.org/learn/serving-over-http/

    For example, it would be nice to support both GET and POST and deal with different Content-Types.

    I think the handler from graphql-go can be used as a reference as it is pretty complete: https://github.com/graphql-go/handler/blob/master/handler.go

    opened by F21 19
  • Use field as resolver instead of method.

    Use field as resolver instead of method.

    Would it be possible to use a struct field as a resolver instead of always using methods? Most of my methods are just simple getters so it would be convenient to allow resolver to default to field. Then I could implement method only when I need special logic.

    opened by nicksrandall 16
  • roadmap

    roadmap

    Hello,

    It would be great to see how feature compliant is this library with the graphql spec. Is it possible to maintain an issue or project to get an idea of when one can use certain feature.

    thanks. bsr

    opened by bsr203 16
  • Use Struct Field Resolver instead of Method

    Use Struct Field Resolver instead of Method

    This fixes #28. Essentially, it reduces lot of boilerplate code by making use of struct field as resolvers instead of creating methods for each struct field.

    Now, methods are required only when

    1. a struct implements a GraphQL interface. In this case, you create methods for fields which overlap
    2. a struct exposes a GraphQL field that accepts additional arguments i.e., first: Int, last: Int etc.
    3. there is GraphQL union type

    By using struct fields as resolvers, one could also benefit from DRY codebase by not having a pair of a struct which look the same (one for GraphQL and one for DB)

    Does this break existing API?

    No. This change is completely transparent and you can continue using your existing codebase.

    Can I still continue using methods as resolvers?

    Yes, by default, it uses method resolvers. Even when UseFieldResolvers() is turned on, the method is given higher priority than the field. When there is no method, the field will be used if there is any.

    How can I use struct fields as resolvers?

    When invoking graphql.ParseSchema() or graphql.MustParseSchema() to parse the schema, you pass in graphql.UseFieldResolvers() as an argument. For an example, take a look at ./example/social/server/server.go

    Additional Notes

    • for an example, take a look at ./example/social/social.go & ./example/social/server/server.go
    • Unit tests are missing
    opened by salman-ahmad 15
  • POC: custom error handlers

    POC: custom error handlers

    This proof of concept will likely need changes before it can be merged but I hope it can serve as a starting point for a conversation around how we can elegantly handle errors in this library.

    This change gives users an optional hook to handle errors. Access to this hook opens up the door for several use cases:

    • Send more information rich errors to the client (related to #37) like sending error codes or other data related to error.
    • Single place to filter out "non-user-safe" errors from being sent to the client.
    • Integrate/send errors created in my resolves or graphql to a logging/monitoring service.

    One benefit of this approach is that it is non-breaking. Users are able to "opt-in" when needed.

    opened by nicksrandall 15
  • implement sql.Scanner and driver.Value for graphql.ID type

    implement sql.Scanner and driver.Value for graphql.ID type

    This makes graphql.ID type implement sql.Scanner and driver.Valuer. This simplifies the data structures that I'm using so that they can implement the types that graphql likes but can also be marshaled into the DB.

    opened by nicksrandall 12
  • Adding new Engine API that allows users to implement custom resolvers.

    Adding new Engine API that allows users to implement custom resolvers.

    Yeah i know it's kinda of a big change. But it does pack lots of new features. If you guys think it's merge worthy I'll take the time rebase on the latest master to pick up recent changes.

    opened by chirino 10
  • Scalar can be decorated with an undeclared directive

    Scalar can be decorated with an undeclared directive

    The schema below raise an error. name is decorated with an undeclared directive.

    type User {
        name: String! @undeclareddirective
    }
    
    panic: graphql: directive "undeclareddirective" not found
    

    But, the schema below does not raise an error. scalar S is decorated with an undeclared directive.

    scalar S @undeclareddirective
    

    Is this a bug? The same is true not only for scalar, but also for argument, interface, etc. The two schemas below also do not raise errors.

    type Query {
        hello(name: String! @undeclareddirective): String!
    }
    
    interface I @undeclareddirective {
        name: String!
    }
    
    opened by roaris 0
  • Return an error if a schema has repeated directives without the repeatable keyword

    Return an error if a schema has repeated directives without the repeatable keyword

    It was reported in https://github.com/graph-gophers/graphql-go/pull/502 that this library doesn't enforce uniqueness of non-repeatable directives. This is a bug and such a restriction needs to be enforced unless the repeatable keyword is present in the directive definition.

    For example, if we are given two directives:

    directive @repeatabledirective repeatable on SCALAR
    directive @otherdirective on SCALAR
    

    Then only the first one (i.e. @repeatabledirective) can be repeated multiple times on the same scalar type. If we repeat the @otherdirective more than once, then that should result in an error.

    The issue is considered resolved when only directives declared as repeatable can be repeated.

    bug help wanted good first issue 
    opened by pavelnikolov 0
  • Any plans to support enisdenjo/graphql-ws?

    Any plans to support enisdenjo/graphql-ws?

    opened by gerarts 1
  • Validation slows on high number of aliases

    Validation slows on high number of aliases

    Hey there! I'm using v.1.3.0 of this library to query a high number (say 2000) of the same thing:

    query slots($blocknum: Long!) {
      slot0: block (number: $blocknum) {
        account(address: "...") { storage (slot: "...")}
      },
        slot1: block (number: $blocknum) {
        account(address: "...") { storage (slot: "...")}
      },
        slot2: block (number: $blocknum) {
        account(address: "...") { storage (slot: "...")}
      },
      ....
      slot2000: block (number: $blocknum) {
        account(address: "...") { storage (slot: "...")}
      }
    }
    

    And noticed this becomes way slower than splitting this query into pages of 100 each. I narrowed down the slowdown to the first loop of Validate. I'd appreciate if you could take a look and see why this is happening.

    opened by s1na 5
  • Add an example of using graphql.ID

    Add an example of using graphql.ID

    Add an example of using graphql.ID. More specifically creating one from an integer and extracting an int value out of it. All examples must be placed in the /examples/ folder in the root of this project.

    help wanted good first issue 
    opened by pavelnikolov 0
Releases(v1.4.0)
  • v1.4.0(Apr 10, 2022)

    What's Changed

    • [FEATURE] Add OpenTelemetry Support by @steve-gray in https://github.com/graph-gophers/graphql-go/pull/493
    • [FEATURE] Apollo Federation Spec: Fetch service capabilities by @aeramu in https://github.com/graph-gophers/graphql-go/pull/507
    • [FEATURE] add support for repeatable directives by @speezepearson in https://github.com/graph-gophers/graphql-go/pull/502
    • [BUGFIX] Fix parseObjectDef will terminate when object has bad syntax (#491) by @cnnrrss in https://github.com/graph-gophers/graphql-go/pull/500
    • [BUGFIX] Fix remove checkNilCase test helper function by @cnnrrss in https://github.com/graph-gophers/graphql-go/pull/504
    • [BUGFIX] Fix example/social code by @roaris in https://github.com/graph-gophers/graphql-go/pull/510
    • [EXAMPLE] Add graphql.Time example by @roaris in https://github.com/graph-gophers/graphql-go/pull/508
    • [BUGFIX] Fix lint error by @pavelnikolov in https://github.com/graph-gophers/graphql-go/pull/512
    • [REFACTOR] Refactor tracing packages by @pavelnikolov in https://github.com/graph-gophers/graphql-go/pull/513

    Full Changelog: https://github.com/graph-gophers/graphql-go/compare/v1.3.0...v1.4.0

    Source code(tar.gz)
    Source code(zip)
  • v1.3.0(Jan 18, 2022)

    • [FEATURE] Support scalar Map type #467
    • [FEATURE] Support custom panic handler #468
    • [TESTS] Add more tests for variable validation #470
    • [FEATURE] Support interfaces implementing interfaces #471
    • [BUG] Support parsing nanoseconds time properly #486
    • [BUG] Fix a bug in maxDepth fragment spread logic #492
    Source code(tar.gz)
    Source code(zip)
  • v1.2.0(Sep 13, 2021)

  • v1.1.0(Apr 30, 2021)

    • [FEATURE] Add types package #437
    • [FEATURE] Expose packer.Unmarshaler as decode.Unmarshaler to the public #450
    • [FEATURE] Add location fields to type definitions #454
    • [FEATURE] errors.Errorf preserves original error similar to fmt.Errorf #456
    • [BUGFIX] Fix duplicated __typename in response (fixes #369) #443
    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Apr 11, 2021)

Owner
A group of gophers collaborating on GraphQL
null
GraphJin - Build APIs in 5 minutes with GraphQL. An instant GraphQL to SQL compiler.

GraphJin - Build APIs in 5 minutes GraphJin gives you a high performance GraphQL API without you having to write any code. GraphQL is automagically co

Vikram Rangnekar 2k May 4, 2022
GQLEngine is the best productive solution for implementing a GraphQL server 🚀

GQLEngine is the best productive solution for implementing a graphql server for highest formance examples starwars: https://github.com/gqlengine/starw

null 88 Apr 24, 2022
go generate based graphql server library

gqlgen What is gqlgen? gqlgen is a Go library for building GraphQL servers without any fuss. gqlgen is based on a Schema first approach — You get to D

99designs 7.5k May 19, 2022
Fast :zap: reverse proxy in front of any GraphQL server for caching, securing and monitoring.

Fast ⚡ reverse proxy in front of any GraphQL server for caching, securing and monitoring. Features ?? Caching RFC7234 compliant HTTP Cache. Cache quer

GBox Proxy 11 May 12, 2022
A collection of Go packages for creating robust GraphQL APIs

api-fu api-fu (noun) (informal) Mastery of APIs. ?? Packages The top level apifu package is an opinionated library that aims to make it as easy as pos

Chris 42 Apr 27, 2022
graphql parser + utilities

graphql utilities for dealing with GraphQL queries in Go. This package focuses on actually creating GraphQL servers and expects you to describe your s

Travis Cline 55 Mar 18, 2022
An implementation of GraphQL for Go / Golang

graphql An implementation of GraphQL in Go. Follows the official reference implementation graphql-js. Supports: queries, mutations & subscriptions. Do

null 8.5k May 13, 2022
Convert Golang Struct To GraphQL Object On The Fly

Straf Convert Golang Struct To GraphQL Object On The Fly Easily Create GraphQL Schemas Example Converting struct to GraphQL Object type UserExtra stru

Roshan Mehta 33 May 8, 2022
⚡️ A Go framework for rapidly building powerful graphql services

Thunder is a Go framework for rapidly building powerful graphql servers. Thunder has support for schemas automatically generated from Go types, live q

null 1.5k May 11, 2022
gqlanalysis makes easy to develop static analysis tools for GraphQL in Go.

gqlanalysis gqlanalysis defines the interface between a modular static analysis for GraphQL in Go. gqlanalysis is inspired by go/analysis. gqlanalysis

null 34 Apr 11, 2022
Tools to write high performance GraphQL applications using Go/Golang.

graphql-go-tools Sponsors WunderGraph Are you looking for a GraphQL e2e data fetching solution? Supports frameworks like NextJS, type safety with gene

Jens Neuse 340 May 8, 2022
Go monolith with embedded microservices including GRPC,REST,GraphQL and The Clean Architecture.

GoArcc - Go monolith with embedded microservices including GRPC,REST, graphQL and The Clean Architecture. Description When you start writing a Go proj

Deqode 78 May 14, 2022
GraphQL implementation for click house in Go.

clickhouse-graphql-go GraphQL implementation for clickhouse in Go. This package stores real time streaming websocket data in clickhouse and uses Graph

Rakesh R 6 Jan 14, 2022
GraphQL parser comparison in different languages

graphql-parser-bench Parsing a schema or document can be a critical part of the application, especially if you have to care about latency. This is the

Dustin Deus 21 Apr 11, 2022
A simple Go, GraphQL, and PostgreSQL starter template

Simple Go/GraphQL/PostgreSQL template Purpose Have a good starting point for any project that needs a graphql, go, and postgres backend. It's a very l

Chris 0 Jan 8, 2022
A GraphQL complete example using Golang And PostgreSQL

GraphQL with Golang A GraphQL complete example using Golang & PostgreSQL Installation Install the dependencies go get github.com/graphql-go/graphql go

Santo Shakil 1 Jan 7, 2022
This app is an attempt towards using go lang with graphql data fetch in react front end.

go_movies _A React js + GraphQL supported with backend in GoLang. This app is an attempt towards using go lang with graphql data fetch in react front

Abhijit Mukherjee 0 Dec 7, 2021
proof-of-concept minimal GraphQL service for LTV

LTV GraphQL Proof-of-Concept This is a barebones proof-of-concept of a possible GraphQL implementation that interacts with Core. It includes a few ver

Nick Kelley 1 Jan 4, 2022
Learn GraphQL with THE [email protected] SHINY COLORS.

faaaar Learn GraphQL with THE [email protected] SHINY COLORS. Getting Started The following is a simple example which get information about 20-year-old idols

tokizo 0 Mar 6, 2022