Run a GraphQL query anywhere, without a GraphQL server or a schema. Just pass in one resolver. Use it together with graphql-tag.

npm install graphql-anywhere graphql-tag

I think there are a lot of potentially exciting use cases for a completely standalone and schema-less GraphQL execution engine. We use it in Apollo Client to read data from a Redux store with GraphQL.

Let's come up with some more ideas - below are some use cases to get you started!

API

import graphql from ' graphql-anywhere ' graphql ( resolver , document , rootValue ? , context ? , variables ? , options ? )

resolver : A single resolver, called for every field on the query. Signature is: (fieldName, rootValue, args, context, info) => any

: A single resolver, called for every field on the query. document : A GraphQL document, as generated by the template literal from graphql-tag

: A GraphQL document, as generated by the template literal from rootValue : The root value passed to the resolver when executing the root fields

: The root value passed to the resolver when executing the root fields context : A context object passed to the resolver for every field

: A context object passed to the resolver for every field variables : A dictionary of variables for the query

: A dictionary of variables for the query options : Options for execution

Options

The last argument to the graphql function is a set of graphql-anywhere -specific options.

resultMapper : Transform field results after execution. Signature is: (resultFields, resultRoot) => any

: Transform field results after execution. fragmentMatcher : Decide whether to execute a fragment. Default is to always execute all fragments. Signature is: (rootValue, typeCondition, context) => boolean

: Decide whether to execute a fragment. Default is to always execute all fragments.

Resolver info

info , the 5th argument to the resolver, is an object with supplementary information about execution. Send a PR or open an issue if you need additional information here.

isLeaf : A boolean that is true if this resolver is for a leaf field of the query, i.e. one that doesn't have a sub-selection.

: A boolean that is if this resolver is for a leaf field of the query, i.e. one that doesn't have a sub-selection. resultKey : The key the result of this field will be put under. It's either the field name from the query, or the field alias.

: The key the result of this field will be put under. It's either the field name from the query, or the field alias. directives : An object with information about all directives on this field. It's an object of the format { [directiveName]: { [argumentName]: value }} . So for example a field with @myDirective(hello: "world") will be passed as { myDirective: { hello: 'world' }} . Note that fields can't have multiple directives with the same name, as written in the GraphQL spec.

Utilities

See https://www.apollographql.com/docs/react/advanced/fragments.html for examples of how you might use these.

import { filter } from ' graphql-anywhere ' filter ( doc , data ) ;

doc : a GraphQL document, as generated by the template literal from graphql-tag , typically either a query or a fragment.

: a GraphQL document, as generated by the template literal from , typically either a query or a fragment. data : an object of data to be filtered by the doc

Filter data according to doc .

import { check } from ' graphql-anywhere ' check ( doc , data ) ;

doc : a GraphQL document, as generated by the template literal from graphql-tag , typically either a query or a fragment.

: a GraphQL document, as generated by the template literal from , typically either a query or a fragment. data : an object of data, as may have been filtered by doc .

Check that data is of the form defined by the query or fragment. Throw an exception if not.

import { propType } from ' graphql-anywhere ' X . propTypes = { foo : propType ( doc ) , bar : propType ( doc ) . isRequired , }

doc : a GraphQL document, as generated by the template literal from graphql-tag , typically either a query or a fragment.

Generate a React propType checking function to ensure that the passed prop is in the right form.

Supported GraphQL features

Why do you even need a library for this? Well, running a GraphQL query isn't as simple as just traversing the AST, since there are some pretty neat features that make the language a bit more complex to execute.

Arguments

Arguments Variables

Variables Aliases

Aliases Fragments, both named and inline

Fragments, both named and inline @skip and @include directives

If you come across a GraphQL feature not supported here, please file an issue.

Example: Filter a nested object

import gql from ' graphql-tag ' ; import graphql from ' graphql-anywhere ' ; const gitHubAPIResponse = { " url " : " https://api.github.com/repos/octocat/Hello-World/issues/1347 " , " title " : " Found a bug " , " body " : " I'm having a problem with this. " , " user " : { " login " : " octocat " , " avatar_url " : " https://github.com/images/error/octocat_happy.gif " , " url " : " https://api.github.com/users/octocat " , } , " labels " : [ { " url " : " https://api.github.com/repos/octocat/Hello-World/labels/bug " , " name " : " bug " , " color " : " f29513 " } ] , } ; const query = gql ` { title user { login } labels { name } } ` ; const resolver = ( fieldName , root ) => root [ fieldName ] ; const result = graphql ( resolver , query , gitHubAPIResponse ) ; assert . deepEqual ( result , { " title " : " Found a bug " , " user " : { " login " : " octocat " , } , " labels " : [ { " name " : " bug " , } ] , } ) ;

Example: Generate mock data

const query = gql ` { author { name: string age: int address { state: string } } } ` ; const resolver = ( fieldName ) => ( { string : ' This is a string ' , int : 5 , } [ fieldName ] || ' continue ' ) ; const result = graphql ( resolver , query ) ; assert . deepEqual ( result , { author : { name : ' This is a string ' , age : 5 , address : { state : ' This is a string ' , } , } , } ) ;

Example: Read from a Redux store generated with Normalizr

const data = { result : [ 1 , 2 ] , entities : { articles : { 1 : { id : 1 , title : ' Some Article ' , author : 1 } , 2 : { id : 2 , title : ' Other Article ' , author : 1 } , } , users : { 1 : { id : 1 , name : ' Dan ' } , } , } , } ; const query = gql ` { result { title author { name } } } ` ; const schema = { articles : { author : ' users ' , } , } ; const resolver = ( fieldName , rootValue , args , context ) : any => { if ( ! rootValue ) { return context . result . map ( ( id ) => assign ( { } , context . entities . articles [ id ] , { __typename : ' articles ' , } ) ) ; } const typename = rootValue . __typename ; if ( typename && schema [ typename ] && schema [ typename ] [ fieldName ] ) { const targetType : string = schema [ typename ] [ fieldName ] ; return assign ( { } , context . entities [ targetType ] [ rootValue [ fieldName ] ] , { __typename : targetType , } ) ; } return rootValue [ fieldName ] ; } ; const result = graphql ( resolver , query , null , data ) ; assert . deepEqual ( result , { result : [ { title : ' Some Article ' , author : { name : ' Dan ' , } , } , { title : ' Other Article ' , author : { name : ' Dan ' , } , } , ] , } ) ;

Example: Generate React components

You can use the resultMapper option to convert your results into anything you like. In this case, we convert the result fields into children for a React component: