npm package: @rmosolgo/graphql-anywhere
Description: Run GraphQL queries with no schema and just one resolver
Author: Sashko Stubailo
Latest version: 4.1.30-alpha.0

# graphql-anywhere

[![npm version](https://badge.fury.io/js/graphql-anywhere.svg)](https://badge.fury.io/js/graphql-anywhere)
[![Build Status](https://travis-ci.org/apollographql/graphql-anywhere.svg?branch=master)](https://travis-ci.org/apollostack/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](https://github.com/apollographql/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](https://github.com/apollostack/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

```js
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`
- `document`: A GraphQL document, as generated by the template literal from `graphql-tag`
- `rootValue`: The root value passed to the resolver when executing the root fields
- `context`: A context object passed to the resolver for every field
- `variables`: 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`
- `fragmentMatcher`: Decide whether to execute a fragment. Default is to always execute all fragments.
    - Signature is: `(rootValue, typeCondition, context) => boolean`

#### 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.
- `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.
- `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.

```js
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.
- `data`: an object of data to be filtered by the `doc`

Filter `data` according to `doc`.


```js
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.
- `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.

```js
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.

- [x] Arguments
- [x] Variables
- [x] Aliases
- [x] Fragments, both named and inline
- [x] `@skip` and `@include` directives

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

<a id="filter"></a>
## Example: Filter a nested object

```js
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",
    }
  ],
});
```

<a id="mock"></a>
## Example: Generate mock data

```js
// 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] || 'continue');

// 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',
    },
  },
});
```
<a id="normalizr"></a>
## Example: Read from a Redux store generated with Normalizr

```js
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',
      },
    },
  ],
});
```

## 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:

```js
const resolver = (fieldName, root, args) => {
  if (fieldName === 'text') {
    return args.value;
  }

  return createElement(fieldName, args);
};

const reactMapper = (childObj, root) => {
  const reactChildren = Object.keys(childObj).map(key => childObj[key]);

  if (root) {
    return cloneElement(root, root.props, ...reactChildren);
  }

  return reactChildren[0];
};

function gqlToReact(query): any {
  return graphql(
    resolver,
    query,
    '',
    null,
    null,
    { resultMapper: reactMapper },
  );
}

const query = gql`
  {
    div {
      s1: span(id: "my-id") {
        text(value: "This is text")
      }
      s2: span
    }
  }
`;

assert.equal(
  renderToStaticMarkup(gqlToReact(query)),
  '<div><span id="my-id">This is text</span><span></span></div>'
);
```