Package Exports
- graphql-anywhere
- graphql-anywhere/lib/src/getFromAST
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (graphql-anywhere) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
graphql-anywhere
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?)
resolver
: A single resolver, called for every field on the query.- Signature is:
(fieldName, rootValue, args, context) => any
- Signature is:
document
: A GraphQL document, as generated by the template literal fromgraphql-tag
rootValue
: The root value passed to the resolver when executing the root fieldscontext
: A context object passed to the resolver for every fieldvariables
: A dictionary of variables for the query
Example: Filter a nested object
import gql from 'graphql-tag';
import graphql from 'graphql-anywhere';
// I don't need all this stuff!
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"
}
],
};
// Write a query that gets just the fields we want
const query = gql`
{
title
user {
login
}
labels {
name
}
}
`;
// Define a resolver that just returns a property
const resolver = (fieldName, root) => root[fieldName];
// Filter the data!
const result = graphql(
resolver,
query,
gitHubAPIResponse
);
assert.deepEqual(result, {
"title": "Found a bug",
"user": {
"login": "octocat",
},
"labels": [
{
"name": "bug",
}
],
});
Example: Generate mock data
// Write a query where the fields are types, but we alias them
const query = gql`
{
author {
name: string
age: int
address {
state: string
}
}
}
`;
// Define a resolver that uses the field name to determine the type
// Note that we get the actual name, not the alias, but the alias
// is used to determine the location in the response
const resolver = (fieldName) => ({
string: 'This is a string',
int: 5,
}[fieldName]);
// Generate the object!
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',
},
};
// This resolver is a bit more complex than others, since it has to
// correctly handle the root object, values by ID, and scalar leafs.
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 this field is a reference according to the schema
if (typename && schema[typename] && schema[typename][fieldName]) {
// Get the target type, and get it from entities by ID
const targetType: string = schema[typename][fieldName];
return assign({}, context.entities[targetType][rootValue[fieldName]], {
__typename: targetType,
});
}
// This field is just a scalar
return rootValue[fieldName];
};
const result = graphql(
resolver,
query,
null,
data // pass data as context since we have to access it all the time
);
// This is the non-normalized data, with only the fields we asked for in our query!
assert.deepEqual(result, {
result: [
{
title: 'Some Article',
author: {
name: 'Dan',
},
},
{
title: 'Other Article',
author: {
name: 'Dan',
},
},
],
});
What does this support?
Every GraphQL syntax feature I can think of is supported, as far as I know, including aliases, arguments, variables, inline fragments, named fragments, and skip
/include
directives.
Known limitations:
- The execution engine is synchronous, so you probably shouldn't use this to query your API. Please submit a PR to add promise functionality, and ideally batching support, like
graphql-js
has! Wouldn't it be cool if you could use this to dynamically query a REST API via GraphQL?