Skip to content

Commit

Permalink
feat(graphql): Generate fragment types from schema file
Browse files Browse the repository at this point in the history
When providing Hops with a GraphQL schema file the command
`hops graphql introspect` will try to generate the fragment types
(required for querying fragments on unions or intersections) from the
provided file.
If this file does not exist, it will try to generate the fragment types
by querying the GraphQL server specified via "graphqlUri".
  • Loading branch information
ZauberNerd committed Mar 26, 2018
1 parent 9d1dc74 commit 5d86841
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 57 deletions.
16 changes: 12 additions & 4 deletions packages/graphql/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,20 @@ Generally, you will use hops-react exactly as you would use a well configured [A

## Configuration

Add your GraphQL endpoint to your Hops config - usually, this means adding a line with your GraphQL endpoint's full URL to your project's `package.json` file:
The following configuration options are available when using this package:

| Field | Type | Required | Description |
| ------------------- | -------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `graphqlUri` | `String` | yes | The full URI to your GraphQL endpoint. This will be used when making requests or [generating the introspection result](#CLI) |
| `graphqlSchemaFile` | `String` | no | Path to your GraphQL schema file - defaults to `./schema.graphql`. If set this will be used to [generate the introspection result](#CLI) |

Example:

```json
{
"config": {
"graphqlUri": "https://www.graphqlhub.com/graphql"
"hops": {
"graphqlUri": "https://www.graphqlhub.com/graphql",
"graphqlSchemaFile": "./my-schema.graphql"
}
}
```
Expand All @@ -34,7 +42,7 @@ For more elaborate (e.g. environment specific configs), please refer to the [hop

## CLI

To allow you to work with fragments on interfaces or unions with GraphQL, you need to provide additional information derived from your actual schema to the client. To fetch and supply that info, please run the command provided by this package in your project's root folder:
To allow you to work with [fragments on interfaces or unions](https://github.com/apollographql/apollo-client/blob/master/docs/source/recipes/fragment-matching.md#using-fragments-on-unions-and-interfaces) with GraphQL, you need to provide additional information derived from your actual schema to the client. To fetch and supply that info, please run the command provided by this package in your project's root folder:

```bash
hops graphql introspect
Expand Down
91 changes: 54 additions & 37 deletions packages/graphql/lib/fragments.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,66 @@
/* global fetch */
'use strict';

require('isomorphic-fetch');
var fs = require('fs');

var fetch = require('isomorphic-fetch');
var pify = require('pify');
var graphql = require('graphql').graphql;
var makeExecutableSchema = require('graphql-tools').makeExecutableSchema;

var hopsConfig = require('hops-config');

var fragmentsFile = require('./util').getFragmentsFile();

module.exports = function fetchFragments() {
return fetch(hopsConfig.graphqlUri, {
function writeFragmentTypesFile(result) {
result.data.__schema.types = result.data.__schema.types.filter(function(t) {
return t.possibleTypes !== null;
});
return pify(fs.writeFile)(fragmentsFile, JSON.stringify(result.data));
}

function executeRemoteQuery(graphqlUri, query) {
return fetch(graphqlUri, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
query: [
/* eslint-disable indent */
' {',
' __schema {',
' types {',
' kind',
' name',
' possibleTypes {',
' name',
' }',
' }',
' }',
' }',
/* eslint-enable indent */
].join('\n'),
}),
})
.then(result => result.json())
.then(result => {
var filteredData = result.data.__schema.types.filter(function(type) {
return type.possibleTypes !== null;
});
result.data.__schema.types = filteredData;
return new Promise(function(resolve, reject) {
fs.writeFile(fragmentsFile, JSON.stringify(result.data), err => {
if (err) {
reject(err);
} else {
resolve(fragmentsFile);
}
});
});
body: JSON.stringify({ query: query }),
}).then(function(result) {
return result.json();
});
}

function executeLocalQuery(schemaFile, query) {
return pify(fs.readFile)(schemaFile, 'utf-8')
.then(function(schema) {
return makeExecutableSchema({ typeDefs: schema });
})
.then(function(executableSchema) {
return graphql(executableSchema, query);
});
}

var query = [
'{',
' __schema {',
' types {',
' kind',
' name',
' possibleTypes {',
' name',
' }',
' }',
' }',
'}',
].join('\n');

module.exports = function generateFragmentTypes() {
return pify(fs.access)(hopsConfig.graphqlSchemaFile)
.then(
function() {
return executeLocalQuery(hopsConfig.graphqlSchemaFile, query);
},
function() {
return executeRemoteQuery(hopsConfig.graphqlUri, query);
}
)
.then(writeFragmentTypesFile);
};
24 changes: 12 additions & 12 deletions packages/graphql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,32 @@
"name": "hops-graphql",
"version": "10.2.0",
"description": "React and GraphQL implementation for Hops",
"keywords": [
"hops",
"react",
"graphql"
],
"keywords": ["hops", "react", "graphql"],
"license": "MIT",
"bin": {
"hops-graphql": "commands/graphql.js"
},
"main": "node.js",
"browser": "dom.js",
"files": [
"node.js",
"dom.js",
"commands",
"lib"
],
"files": ["node.js", "dom.js", "commands", "lib"],
"dependencies": {
"apollo-cache-inmemory": "^1.1.5",
"apollo-client": "^2.2.0",
"apollo-link-http": "^1.3.2",
"graphql": "^0.12.3",
"isomorphic-fetch": "^2.2.1"
"graphql-tools": "^2.20.0",
"isomorphic-fetch": "^2.2.1",
"pify": "^3.0.0"
},
"peerDependencies": {
"graphql-tag": "^2.5.0",
"hops-react": "10.2.0-rc.0",
"react": ">=15.0.0 <17.0.0",
"react-apollo": "^2.0.0"
},
"devDependencies": {
"graphql-tag": "^2.5.0",
"hops-react": "10.2.0-rc.0",
"react": ">=15.0.0 <17.0.0",
"react-apollo": "^2.0.0"
}
Expand Down
47 changes: 43 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ apollo-link@^1.0.0, apollo-link@^1.2.1:
apollo-utilities "^1.0.0"
zen-observable-ts "^0.8.6"

apollo-utilities@^1.0.0, apollo-utilities@^1.0.10:
apollo-utilities@^1.0.0, apollo-utilities@^1.0.1, apollo-utilities@^1.0.10:
version "1.0.10"
resolved "https://registry.yarnpkg.com/apollo-utilities/-/apollo-utilities-1.0.10.tgz#0c35696891d4fa28d76768e0f7249d63c6da08b9"

Expand Down Expand Up @@ -2350,6 +2350,10 @@ depd@^1.1.0, depd@~1.1.1, depd@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"

deprecated-decorator@^0.1.6:
version "0.1.6"
resolved "https://registry.yarnpkg.com/deprecated-decorator/-/deprecated-decorator-0.1.6.tgz#00966317b7a12fe92f3cc831f7583af329b86c37"

des.js@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc"
Expand Down Expand Up @@ -3491,10 +3495,20 @@ graphql-anywhere@^4.1.7:
dependencies:
apollo-utilities "^1.0.10"

graphql-tag@^2.6.1:
graphql-tag@^2.5.0, graphql-tag@^2.6.1:
version "2.8.0"
resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.8.0.tgz#52cdea07a842154ec11a2e840c11b977f9b835ce"

graphql-tools@^2.20.0:
version "2.23.1"
resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-2.23.1.tgz#23f43000e2b9dc5a89920fe846fc5f71a320efdb"
dependencies:
apollo-link "^1.2.1"
apollo-utilities "^1.0.1"
deprecated-decorator "^0.1.6"
iterall "^1.1.3"
uuid "^3.1.0"

graphql@^0.12.3:
version "0.12.3"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-0.12.3.tgz#11668458bbe28261c0dcb6e265f515ba79f6ce07"
Expand Down Expand Up @@ -3702,6 +3716,23 @@ home-or-tmp@^2.0.0:
os-homedir "^1.0.0"
os-tmpdir "^1.0.1"

hops-config@10.2.0-rc.0:
version "10.2.0-rc.0"
resolved "https://registry.yarnpkg.com/hops-config/-/hops-config-10.2.0-rc.0.tgz#dd3721e9c7b492e0629beaa65e0e2c9301c2ddfb"
dependencies:
cosmiconfig "^4.0.0"
is-plain-object "^2.0.4"
lodash.mergewith "^4.6.1"
pkg-dir "^2.0.0"

hops-react@10.2.0-rc.0:
version "10.2.0-rc.0"
resolved "https://registry.yarnpkg.com/hops-react/-/hops-react-10.2.0-rc.0.tgz#3c99d2b9ed85b775e76dc10fdcab0a74b426307f"
dependencies:
hops-config "10.2.0-rc.0"
mixinable "1.3.0"
serialize-javascript "^1.4.0"

hosted-git-info@^2.1.4, hosted-git-info@^2.5.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.6.0.tgz#23235b29ab230c576aab0d4f13fc046b0b038222"
Expand Down Expand Up @@ -4289,6 +4320,10 @@ iterall@1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.1.3.tgz#1cbbff96204056dde6656e2ed2e2226d0e6d72c9"

iterall@^1.1.3:
version "1.2.2"
resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.2.2.tgz#92d70deb8028e0c39ff3164fdbf4d8b088130cd7"

jest-changed-files@^22.4.3:
version "22.4.3"
resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-22.4.3.tgz#8882181e022c38bd46a2e4d18d44d19d90a90fb2"
Expand Down Expand Up @@ -5248,6 +5283,10 @@ mixin-deep@^1.2.0:
for-in "^1.0.2"
is-extendable "^1.0.1"

mixinable@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/mixinable/-/mixinable-1.3.0.tgz#08c99ef94c7a601f2334dd6e7f097d0695750ec1"

mixinable@1.5.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/mixinable/-/mixinable-1.5.2.tgz#efeae46e0452452a538c1d668bc15f98ca379981"
Expand Down Expand Up @@ -6571,7 +6610,7 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.1.7:
minimist "^1.2.0"
strip-json-comments "~2.0.1"

react-apollo@^2.0.4:
react-apollo@^2.0.0, react-apollo@^2.0.4:
version "2.1.0"
resolved "https://registry.yarnpkg.com/react-apollo/-/react-apollo-2.1.0.tgz#b94c4aca513776d90c368f20a65f99e98fdfea17"
dependencies:
Expand Down Expand Up @@ -6648,7 +6687,7 @@ react-test-renderer@^16.0.0:
object-assign "^4.1.1"
prop-types "^15.6.0"

react@^16.0.0:
"react@>=15.0.0 <17.0.0", react@^16.0.0:
version "16.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba"
dependencies:
Expand Down

0 comments on commit 5d86841

Please sign in to comment.