fluentgraphql

package module
v0.0.0-...-9162f39 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 6, 2022 License: MIT Imports: 4 Imported by: 1

README

Go Reference Go Report Card codecov

fluentgraphql

This package wraps the graphql-go/graphql implementation to provide a "fluent" pattern for constructing GraphQL queries in Go. This can be valuable in situations where dynamic queries are desired: when the fields of a GraphQL query (or mutation) are not known until runtime. For most other use cases, plain query strings or a helper library such as this should be sufficient.

package main

import (
    fgql "github.com/mergestat/fluentgraphql"
)

func main() {
    fgql.NewQuery().Scalar("hello").Root().String() // { hello }
}

Basic Usage

go get github.com/mergestat/fluentgraphql

import (
    fgql "github.com/mergestat/fluentgraphql"
)

The package name is fluentgraphql, but we alias it here to fgql which is more concise. A query or mutation is started like so:

    q := fgql.NewQuery() // a new query builder
    m := fgql.NewMutation() // a new mutation builder

A query can be constructed with calls to builder methods, such as in the following example. See this file for more thorough examples.

/*
    query HeroComparison($first: Int = 3) {
        leftComparison: hero(episode: EMPIRE) {
        ...comparisonFields
        }
        rightComparison: hero(episode: JEDI) {
        ...comparisonFields
        }
    }

    fragment comparisonFields on Character {
        name
        friendsConnection(first: $first) {
        totalCount
        edges {
            node {
            name
            }
        }
        }
    }
*/
q = fgql.NewQuery(
    fgql.WithName("HeroComparison"),
    fgql.WithVariableDefinitions(
        fgql.NewVariableDefinition("first", "Int", false, fgql.NewIntValue(3)),
    ),
).
    Selection("hero",
        fgql.WithAlias("leftComparison"),
        fgql.WithArguments(fgql.NewArgument("episode", fgql.NewEnumValue("EMPIRE"))),
    ).FragmentSpread("comparisonFields").
    Parent().
    Selection("hero",
        fgql.WithAlias("rightComparison"),
        fgql.WithArguments(fgql.NewArgument("episode", fgql.NewEnumValue("JEDI"))),
    ).FragmentSpread("comparisonFields").
    Root().
    Fragment("comparisonFields", "Character").
    Scalar("name").
    Selection("friendsConnection", fgql.WithArguments(fgql.NewArgument("first", fgql.NewVariableValue("first")))).
    Scalar("totalCount").
    Selection("edges").Selection("node").Scalar("name").
    Root().String()
fmt.Println(q)

Note the call to .Root().String(). Root() traverses the builder tree back to the root, so that when String() is called, the entire query is printed as a string.

Batching Requests

A use case where a fluent interface is valuable is when dynamically generating a "batch" of queries to make to a GraphQL API. For instance, in the github-batch-request example, we can build a query that retrieves the stargazerCount field of multiple, arbitrary repositories at once. This allows us to batch multiple lookups into a single HTTP request, avoiding multiple round-trip requests.

q := fgql.NewQuery()

// iterate over the list of repos and add a selection to the query for each one
for i, repo := range repoList {
    split := strings.Split(repo, "/")
    owner := split[0]
    name := split[1]

    q.Selection("repository", fgql.WithAlias(fmt.Sprintf("repo_%d", i)), fgql.WithArguments(
        fgql.NewArgument("owner", fgql.NewStringValue(owner)),
        fgql.NewArgument("name", fgql.NewStringValue(name)),
    )).
        Selection("owner").Scalar("login").Parent().
        Scalar("name").Scalar("stargazerCount")
}

Produces a query that looks something like:

{
  repo_0: repository(owner: "marko-js", name: "marko") {
    owner {
      login
    }
    name
    stargazerCount
  }
  repo_1: repository(owner: "mithriljs", name: "mithril.js") {
    owner {
      login
    }
    name
    stargazerCount
  }
  repo_2: repository(owner: "angular", name: "angular") {
    owner {
      login
    }
    name
    stargazerCount
  }
  ...
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewArgument

func NewArgument(name string, val *Value) *argument

NewArgument constructs a new argument with a value

func NewObjectValueField

func NewObjectValueField(fieldName string, value *Value) *objectValueField

NewObjectValueField returns a field for an object value

func NewVariableDefinition

func NewVariableDefinition(name string, varType string, required bool, defaultVal *Value) *variableDefinition

NewVariableDefinition defines a new variable definition

func WithAlias

func WithAlias(alias string) selectionOption

WithAlias is an option for specifying a selection alias

func WithArguments

func WithArguments(args ...*argument) selectionOption

WithArguments is a selection option for specifying arguments

func WithName

func WithName(name string) operationOption

WithName specifies a name for the operation

func WithVariableDefinitions

func WithVariableDefinitions(vars ...*variableDefinition) operationOption

WithVariableDefinitions is an operation option for declaring variable definitions

Types

type Selection

type Selection struct {
	// contains filtered or unexported fields
}

func NewMutation

func NewMutation(options ...operationOption) *Selection

NewMutation returns a selection builder for a new GraphQL mutation. mutation { ... }

func NewQuery

func NewQuery(options ...operationOption) *Selection

NewQuery returns a selection builder for a new GraphQL query. query { ... }

func (*Selection) Fragment

func (s *Selection) Fragment(name, typeCondition string) *Selection

Fragment adds a fragement definition

func (*Selection) FragmentSpread

func (s *Selection) FragmentSpread(name string) *Selection

FragmentSpread adds a fragement spread

func (*Selection) InlineFragment

func (s *Selection) InlineFragment(typeCondition string) *Selection

InlineFragment adds an inline fragment to the current selection

func (*Selection) Parent

func (s *Selection) Parent() *Selection

Parent returns the parent of this selection. If it's the root, will return nil.

func (*Selection) Root

func (s *Selection) Root() *Selection

Root traverses all parents of the current selection until the root

func (*Selection) Scalar

func (s *Selection) Scalar(fieldName string, options ...selectionOption) *Selection

Scalar adds a scalar field to the current selection

func (*Selection) Selection

func (s *Selection) Selection(fieldName string, options ...selectionOption) *Selection

Selection adds a subselection to the current selection

func (*Selection) String

func (s *Selection) String() string

String returns the selection as a GraphQL query string

type Value

type Value struct {
	// contains filtered or unexported fields
}

Value represents a GraphQL value

func NewBooleanValue

func NewBooleanValue(val bool) *Value

NewBooleanValue returns a boolean value

func NewEnumValue

func NewEnumValue(val string) *Value

NewEnumValue returns an enum value

func NewFloatValue

func NewFloatValue(val float64) *Value

NewFloatValue returns a float value

func NewIntValue

func NewIntValue(val int) *Value

NewIntValue returns an integer value

func NewListValue

func NewListValue(values ...*Value) *Value

NewListValue returns a list value

func NewObjectValue

func NewObjectValue(values ...*objectValueField) *Value

NewObjectValue returns an object value

func NewStringValue

func NewStringValue(val string) *Value

NewStringValue returns a string value

func NewVariableValue

func NewVariableValue(name string) *Value

NewVariableValue returns a variable value

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL