Git Product home page Git Product logo

garphunql's Introduction

Garphunql Build Status Coverage Status

Garphunql is a Golang client library for GraphQL. It supports building queries in a type-safe way, then submitting them to the server and automatically unmarshaling the responses.

Usage

Getting a Client

Garphunql's functionality is provided as methods on a Client object. You instantiate a client with the NewClient function, providing the server URL and any number of headers. Here's an example of making a client to talk to the Github GraphQL API. (In all the examples here, garphunql has been imported with the gql alias.):

package main

import (
  "fmt"

  gql "github.com/btubbs/garphunql"
)

func main() {
	client := gql.NewClient(
		"https://api.github.com/graphql",
		gql.Header("Authorization", "bearer aidee6gahPe1baeth8tikeijeeth0aedaehe"),
	)
  // ...
}

Making a simple query

Once you have a client you can query for data using the client's Query method. The Query method takes a field, which you can construct with the Field function, passing it a name, the sub-fields you want to get back, and a destination that the results should be unmarshaled into:

type User struct {
	Name     string `json:"name"`
	Location string `json:"location"`
}

func simpleQuery(client *gql.Client) {
	var me User
	meField := gql.Field("viewer",
		gql.Field("name"),
		gql.Field("location"),
		gql.Dest(&me),
	)
	err := client.Query(meField)
	fmt.Println(err, me)
}

Passing arguments to fields

Some GraphQL fields take arguments. Garphunql supports querying those fields by passing in one or more Arg calls to Field. Here we query Github for another user, passing in a value for the login argument:

func queryWithArguments(client *gql.Client) {
	var zach User
	zachField := gql.Field("user",
		gql.Arg("login", "zachabrahams"),
		gql.Field("name"),
		gql.Field("location"),
		gql.Dest(&zach),
	)
	err := client.Query(zachField)
	fmt.Println(err, zach)
}

More deeply nested fields

GraphQL can have fields within fields within fields, etc. This example shows a label field nested inside a permissions field nested inside a licenses field (which is also automatically nested inside a query field before Garphunql sends it over the wire):

func deeplyNestedFields(client *gql.Client) {
	var licenses []License
	licensesField := gql.Field("licenses",
		gql.Field("name"),
		gql.Field("permissions",
      gql.Field("label"),
    ),
	)
	err := client.Query(
		licensesField(gql.Dest(&licenses)),
	)
	fmt.Println(err, licenses)
}

Querying multiple fields at once

GraphQL lets you query any number of fields at the same time. Similarly, Garphunql lets you pass in any number of Field calls to Query. The fields will all be bundled together and sent to the server as sub-fields of the top-level "query" field. When the server's response is received, each piece of the payload will be unmarshaled into the appropriate destination:

func multipleQueries(client *gql.Client) {
	var me User
	var zach User
	meField := gql.Field("viewer",
		gql.Field("name"),
		gql.Field("location"),
		gql.Dest(&me),
	)
	zachField := gql.Field("user",
		gql.Arg("login", "zachabrahams"),
		gql.Field("name"),
		gql.Field("location"),
		gql.Dest(&zach),
	)
	err := client.Query(meField, zachField)
	fmt.Println(err, me, zach)
}

Re-using fields with late binding

You might want to query the same field multiple times with different arguments. Garphunql lets you partially define a field with the options shared between your calls, then call it later with more arguments to customize it:

func lateBoundFields(client *gql.Client) {
	var pedro User
	var sean User
	unboundUserField := gql.Field("user",
		gql.Field("name"),
		gql.Field("location"),
	)
	err := client.Query(
		unboundUserField(gql.Arg("login", "steenzout"), gql.Dest(&pedro)),
		unboundUserField(gql.Arg("login", "sophisticasean"), gql.Dest(&sean)),
	)
	fmt.Println(err, pedro, sean)
}

There's one more thing to note about that example. We made two queries to the user field. Normally GraphQL would require you to provide an alias for at least one of them so that they could be differentiated in the response payload. Garphunql automatically detected the name collision while building the query and set an alias for the second user field behind the scenes.

Handling resolver errors

In a GraphQL server, every field is populated by a "resolver". Because you can query multiple fields at once, it's possible for some of their resolvers to succeed, while others fail. In this case, the server will return null for the failed fields, and add objects to the "errors" element of the response payload. Garphunql bundles those errors into a multierror and returns it as the result of the Query call, while still populating the destination variables of the fields that succeeded:

func errorHandling(client *gql.Client) {
	var me User
	var nobody User
	meField := gql.Field("viewer",
		gql.Field("name"),
		gql.Field("location"),
		gql.Dest(&me),
	)
	userField := gql.Field("user",
		gql.Arg("login", "TOTALLY FAKE USER"),
		gql.Field("name"),
		gql.Field("location"),
		gql.Dest(&nobody),
	)
	err := client.Query(
		meField,
		userField,
	)
	fmt.Println(err, me, nobody)
}

The function above will print the error returned by Github (* Could not resolve to a User with the login of 'TOTALLY FAKE USER'.), as well as printing the populated me and the empty nobody.

Mutations

In addition to the Query method, the Garphunql client provides a Mutation method. It works identically, except that you may only provide a single top-level field.

TODO

  • request variables
  • input objects
  • ... on syntax

garphunql's People

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

Forkers

t-costello

garphunql's Issues

Add a Dest field to Field (and deprecate Q)

If we had a Dest field on Field then we could just pass a slice of Fields to QueryFields instead of a slice of the Q objects, and we wouldn't need the Q objects at all.

The thing that would be slightly dirty about it is that Dest would be required for all top-level fields, but forbidden for any more deeply nested fields.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.