├── .gitignore
├── js
├── queries
│ └── StoreQueries.js
├── components
│ ├── About.js
│ ├── NoMatch.js
│ ├── App.js
│ ├── posts
│ │ ├── Post.js
│ │ ├── PostShow.js
│ │ └── PostList.js
│ └── people
│ │ ├── PersonShow.js
│ │ └── PersonList.js
├── mutations
│ └── CreatePostMutation.js
└── app.js
├── .babelrc
├── app.json
├── README.md
├── .tern-project
├── server
├── index.js
├── dev.js
└── data
│ ├── database.js
│ ├── methods.js
│ └── schema.js
├── scripts
├── seed.js
└── updateSchema.js
├── webpack.config.js
├── public
└── index.html
├── webpack.config.prod.js
├── LICENSE.txt
├── package.json
└── data
└── schema.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 | .DS_Store
4 | data/schema.graphql
5 | data/*.sqlite
6 | public/assets/*
7 | dist
8 |
--------------------------------------------------------------------------------
/js/queries/StoreQueries.js:
--------------------------------------------------------------------------------
1 | import Relay from 'react-relay';
2 |
3 | export default {
4 | store: () => Relay.QL`query { store }`,
5 | };
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-0", "react"],
3 | "env": {
4 | "development": {
5 | "presets": ["react-hmre"]
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/js/components/About.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const About = () => (
4 |
Rendering About component
5 | );
6 |
7 | export default About;
--------------------------------------------------------------------------------
/js/components/NoMatch.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const NoMatch = () => (
4 | Rendering NoMatch component
5 | );
6 |
7 | export default NoMatch;
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "apps" : [{
3 | "name" : "react-relay",
4 | "script" : "./server/dev.js",
5 | "watch" : "./server",
6 | "log_date_format" : "YYYY-MM-DD HH:mm Z",
7 | "exec_interpreter": "babel-node",
8 | "exec_mode": "fork"
9 | }]
10 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React starter kit with Graphql, Relay and Sequelize
2 |
3 | ```
4 | git clone https://github.com/doabit/react-relay-graphql-starter-kit.git
5 | npm install
6 | ```
7 |
8 | ## Development
9 |
10 | ```
11 | npm run db:seed
12 | npm run update-schema
13 | npm run start-dev
14 | ```
15 |
16 | ## Production
17 |
18 | ```
19 | npm run build
20 | npm run start
21 | ```
22 |
23 | open `http://localhost:3000`
--------------------------------------------------------------------------------
/.tern-project:
--------------------------------------------------------------------------------
1 | {
2 | "ecmaVersion": 6,
3 | "libs": [],
4 | "loadEagerly": [
5 | "js/**/*.js"
6 | ],
7 | "dontLoad": [
8 | "node_modules/**/*.js"
9 | ],
10 | "plugins": {
11 | "complete_strings": {},
12 | "node": {},
13 | "lint": {},
14 | "angular": {},
15 | "requirejs": {},
16 | "modules": {},
17 | "es_modules": {},
18 | "doc_comment": {
19 | "fullDocs": true
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/js/components/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Link} from 'react-router';
3 |
4 | class App extends React.Component {
5 | render() {
6 | return (
7 |
8 |
9 | - People
10 | - Posts
11 | - About
12 |
13 | {this.props.children}
14 |
15 | )
16 | }
17 | }
18 |
19 | export default App;
--------------------------------------------------------------------------------
/server/index.js:
--------------------------------------------------------------------------------
1 | import express from 'express';
2 | import graphQLHTTP from 'express-graphql';
3 | import Schema from './data/schema';
4 | import { graphql } from 'graphql';
5 |
6 | const APP_PORT = 3000;
7 | const app = express();
8 |
9 | app.use(express.static('public'));
10 |
11 | app.use('/graphql', graphQLHTTP({
12 | schema: Schema,
13 | graphiql: true
14 | }));
15 |
16 | app.listen(APP_PORT, (err) => {
17 | if(err) {
18 | throw err;
19 | }
20 | console.log(`App is now running on http://localhost:${APP_PORT}`);
21 | });
22 |
--------------------------------------------------------------------------------
/js/components/posts/Post.js:
--------------------------------------------------------------------------------
1 | import {Link} from 'react-router';
2 | import React from 'react';
3 | import Relay from 'react-relay';
4 |
5 | class Post extends React.Component {
6 | render() {
7 | const {post} = this.props;
8 | return (
9 |
10 | {post.title}
11 |
12 | );
13 | }
14 | }
15 |
16 | export default Relay.createContainer(Post, {
17 | fragments: {
18 | post: () => Relay.QL`
19 | fragment on Post {
20 | id
21 | title
22 | }
23 | `,
24 | }
25 | });
26 |
--------------------------------------------------------------------------------
/scripts/seed.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 | import Faker from 'faker';
3 |
4 | import { Conn, Post, Person } from '../server/data/database';
5 |
6 | Conn.sync({force: true}).then(() => {
7 | _.times(10, (i) => {
8 | return Person.create({
9 | firstName: Faker.name.firstName(),
10 | lastName: Faker.name.lastName(),
11 | email: Faker.internet.email()
12 | }).then(person => {
13 | return person.createPost({
14 | title: `Sample title by ${person.firstName}`,
15 | content: 'this is content'
16 | });
17 | });
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/js/components/people/PersonShow.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Relay from 'react-relay';
3 |
4 | class PersonShow extends React.Component {
5 | render() {
6 | const {person} = this.props;
7 | return (
8 |
9 |
Person {person.firstName} {person.lastName}
10 |
Email: {person.email}
11 |
12 | );
13 | }
14 | }
15 |
16 | export default Relay.createContainer(PersonShow, {
17 | fragments: {
18 | person: () => Relay.QL`
19 | fragment on Person {
20 | id
21 | firstName
22 | email
23 | }
24 | `,
25 | }
26 | });
27 |
--------------------------------------------------------------------------------
/js/components/posts/PostShow.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Relay from 'react-relay';
3 |
4 | class PostShow extends React.Component {
5 | render() {
6 | const {post} = this.props;
7 | return (
8 |
9 |
post {post.id} {post.title}
10 |
Author: {post.person.firstName} {post.person.lastName}
11 |
{post.content}
12 |
13 | );
14 | }
15 | }
16 |
17 | export default Relay.createContainer(PostShow, {
18 | fragments: {
19 | post: () => Relay.QL`
20 | fragment on Post {
21 | person{
22 | firstName
23 | lastName
24 | }
25 | id
26 | title
27 | content
28 | }
29 | `,
30 | }
31 | });
32 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const webpack = require('webpack');
3 |
4 | module.exports = {
5 | devtool: 'cheap-module-eval-source-map',
6 | entry: [
7 | 'webpack-hot-middleware/client',
8 | './js/app'
9 | ],
10 | output: {
11 | path: path.join(__dirname, 'public/assets'),
12 | filename: 'bundle.js',
13 | publicPath: '/assets/'
14 | },
15 | plugins: [
16 | new webpack.HotModuleReplacementPlugin(),
17 | new webpack.NoErrorsPlugin()
18 | ],
19 | module: {
20 | loaders: [
21 | {
22 | test: /\.js$/,
23 | exclude: /node_modules/,
24 | include: path.join(__dirname, 'js'),
25 | loader: 'babel',
26 | query: {plugins: ['./build/babelRelayPlugin']},
27 | }
28 | ]
29 | }
30 | };
31 |
--------------------------------------------------------------------------------
/server/dev.js:
--------------------------------------------------------------------------------
1 | import webpack from 'webpack';
2 | import config from '../webpack.config';
3 | import express from 'express';
4 | import graphQLHTTP from 'express-graphql';
5 | import Schema from './data/schema';
6 | import { graphql } from 'graphql';
7 |
8 | const APP_PORT = 3000;
9 | const app = express();
10 | const compiler = webpack(config);
11 |
12 | app.use(require('webpack-dev-middleware')(compiler, {
13 | publicPath: config.output.publicPath,
14 | hot: true,
15 | contentBase: './public',
16 | historyApiFallback: true
17 | }));
18 |
19 | app.use(require('webpack-hot-middleware')(compiler));
20 |
21 | app.use(express.static('public'));
22 |
23 | app.use('/graphql', graphQLHTTP({
24 | schema: Schema,
25 | graphiql: true
26 | }));
27 |
28 | app.listen(APP_PORT, (err2) => {
29 | if(err2) {
30 | throw err2;
31 | }
32 | console.log(`App is now running on http://localhost:${APP_PORT}`);
33 | });
34 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React relay graphql starter kit
7 |
8 |
9 |
10 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/webpack.config.prod.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const webpack = require('webpack');
3 |
4 | module.exports = {
5 | devtool: 'source-map',
6 | entry: [
7 | './js/app'
8 | ],
9 | output: {
10 | path: path.join(__dirname, 'public/assets'),
11 | filename: 'bundle.js',
12 | publicPath: '/assets/'
13 | },
14 | plugins: [
15 | new webpack.optimize.OccurenceOrderPlugin(),
16 | new webpack.DefinePlugin({
17 | 'process.env': {
18 | 'NODE_ENV': JSON.stringify('production')
19 | }
20 | }),
21 | new webpack.optimize.UglifyJsPlugin({
22 | compressor: {
23 | warnings: false
24 | }
25 | })
26 | ],
27 | module: {
28 | loaders: [
29 | {
30 | test: /\.js$/,
31 | exclude: /node_modules/,
32 | include: path.join(__dirname, 'js'),
33 | loader: 'babel',
34 | query: {plugins: ['./build/babelRelayPlugin']},
35 | }
36 | ]
37 | }
38 | };
39 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015 doabit
2 |
3 | MIT License
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining
6 | a copy of this software and associated documentation files (the
7 | "Software"), to deal in the Software without restriction, including
8 | without limitation the rights to use, copy, modify, merge, publish,
9 | distribute, sublicense, and/or sell copies of the Software, and to
10 | permit persons to whom the Software is furnished to do so, subject to
11 | the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be
14 | included in all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/server/data/database.js:
--------------------------------------------------------------------------------
1 | import Sequelize from 'sequelize';
2 | import path from 'path';
3 |
4 | const Conn = new Sequelize('development', null, null, {
5 | dialect: 'sqlite',
6 | storage: path.join(__dirname, '../../data/development.sqlite')
7 | });
8 |
9 | const Person = Conn.define('person', {
10 | // type: {
11 | // type: new Sequelize.VIRTUAL(Sequelize.STRING),
12 | // get() {
13 | // return 'Person';
14 | // }
15 | // },
16 | firstName: {
17 | type: Sequelize.STRING,
18 | allowNull: false
19 | },
20 | lastName: {
21 | type: Sequelize.STRING,
22 | allowNull: false
23 | },
24 | email: {
25 | type: Sequelize.STRING,
26 | allowNull: false,
27 | validate: {
28 | isEmail: true
29 | }
30 | }
31 | });
32 |
33 | const Post = Conn.define('post', {
34 | // type: {
35 | // type: new Sequelize.VIRTUAL(Sequelize.STRING),
36 | // get() {
37 | // return 'Post';
38 | // }
39 | // },
40 | title: {
41 | type: Sequelize.STRING,
42 | allowNull: false
43 | },
44 | content: {
45 | type: Sequelize.STRING,
46 | allowNull: false
47 | }
48 | });
49 |
50 | Person.hasMany(Post);
51 | Post.belongsTo(Person);
52 |
53 | module.exports = {
54 | Conn, Person, Post
55 | };
56 |
--------------------------------------------------------------------------------
/js/mutations/CreatePostMutation.js:
--------------------------------------------------------------------------------
1 | import Relay from "react-relay";
2 |
3 | class CreatePostMutation extends Relay.Mutation {
4 | getMutation() {
5 | return Relay.QL`
6 | mutation { createPost }
7 | `;
8 | }
9 |
10 | getVariables() {
11 | return {
12 | title: this.props.title,
13 | content: this.props.content,
14 | person: this.props.person
15 | }
16 | }
17 |
18 | getFatQuery() {
19 | return Relay.QL`
20 | fragment on CreatePostPayload {
21 | postEdge
22 | store { posts }
23 | }
24 | `;
25 | }
26 |
27 | getConfigs() {
28 | return [
29 | // {
30 | // type: 'FIELDS_CHANGE',
31 | // fieldIDs: {
32 | // store: this.props.store.id
33 | // }
34 | // },
35 | {
36 | type: 'RANGE_ADD',
37 | parentName: 'store',
38 | parentID: this.props.store.id,
39 | connectionName: 'posts',
40 | edgeName: 'postEdge',
41 | rangeBehaviors: {
42 | '': 'prepend',
43 | },
44 | }]
45 | }
46 |
47 | // getOptimisticResponse() {
48 | // return {
49 | // postEdge: {
50 | // node: {
51 | // title: this.props.title,
52 | // content: this.props.content,
53 | // }
54 | // },
55 | // store: {
56 | // id: this.props.store.id
57 | // },
58 | // }
59 | // }
60 | }
61 |
62 | export default CreatePostMutation;
63 |
--------------------------------------------------------------------------------
/js/components/people/PersonList.js:
--------------------------------------------------------------------------------
1 | import {IndexLink, Link} from 'react-router';
2 | import React from 'react';
3 | import Relay from 'react-relay';
4 |
5 |
6 | class PersonList extends React.Component {
7 | render() {
8 | var currentNumber = this.props.relay.variables.limit;
9 | var buttonStyle = {};
10 | if (!this.props.store.people.pageInfo.hasNextPage) {
11 | buttonStyle.display = 'none';
12 | }
13 |
14 | return (
15 |
16 |
People list
17 |
18 | {this.props.store.people.edges.map(edge =>
19 | -
20 | {edge.node.firstName}
21 |
22 | )}
23 |
24 |
29 |
30 | );
31 | }
32 | }
33 |
34 | export default Relay.createContainer(PersonList, {
35 | initialVariables: {
36 | limit: 5
37 | },
38 | fragments: {
39 | store: () => Relay.QL`
40 | fragment on Store {
41 | people(first: $limit){
42 | edges{
43 | node{
44 | id
45 | firstName
46 | lastName
47 | email
48 | }
49 | },
50 | pageInfo {
51 | hasNextPage
52 | }
53 | }
54 | }
55 | `,
56 | },
57 | });
58 |
--------------------------------------------------------------------------------
/scripts/updateSchema.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env babel-node --optional es7.asyncFunctions
2 | /**
3 | * This file provided by Facebook is for non-commercial testing and evaluation
4 | * purposes only. Facebook reserves all rights not expressly granted.
5 | *
6 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
7 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
8 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
9 | * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
10 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
11 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12 | */
13 |
14 | import fs from 'fs';
15 | import path from 'path';
16 | import Schema from '../server/data/schema';
17 | import { graphql } from 'graphql';
18 | import { introspectionQuery, printSchema } from 'graphql/utilities';
19 |
20 | // Save JSON of full schema introspection for Babel Relay Plugin to use
21 | (async () => {
22 | var result = await (graphql(Schema, introspectionQuery));
23 | if (result.errors) {
24 | console.error(
25 | 'ERROR introspecting schema: ',
26 | JSON.stringify(result.errors, null, 2)
27 | );
28 | } else {
29 | fs.writeFileSync(
30 | path.join(__dirname, '../data/schema.json'),
31 | JSON.stringify(result, null, 2)
32 | );
33 | }
34 | })();
35 |
36 |
37 | // Save user readable type system shorthand of schema
38 | fs.writeFileSync(
39 | path.join(__dirname, '../data/schema.graphql'),
40 | printSchema(Schema)
41 | );
42 |
--------------------------------------------------------------------------------
/js/app.js:
--------------------------------------------------------------------------------
1 | // import 'babel-core/polyfill';
2 | import React from 'react';
3 | import ReactDOM from 'react-dom';
4 | import Relay from 'react-relay';
5 |
6 | import {createHashHistory} from 'history';
7 | import {IndexRoute, Route} from 'react-router';
8 | import {RelayRouter} from 'react-router-relay';
9 |
10 | import App from './components/App';
11 | import About from './components/About';
12 | import PersonList from './components/people/PersonList';
13 | import PersonShow from './components/people/PersonShow';
14 | import PostList from './components/posts/PostList';
15 | import PostShow from './components/posts/PostShow';
16 |
17 | import NoMatch from './components/NoMatch';
18 |
19 | import StoreQueries from './queries/StoreQueries';
20 |
21 | const PersonQueries = {
22 | person: () => Relay.QL`query { node(id: $id) }`
23 | };
24 |
25 | const PostQueries = {
26 | post: () => Relay.QL`query { node(id: $id) }`
27 | };
28 |
29 | ReactDOM.render(
30 |
31 |
33 |
37 |
42 |
47 |
52 |
57 |
58 |
59 |
60 | ,
61 | document.getElementById('root')
62 | );
63 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-relay-graphql-starter-kit",
3 | "version": "1.0.0",
4 | "description": "React starter kit with relay, graphql and sequelize",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/doabit/react-relay-graphql-starter-kit.git"
8 | },
9 | "main": "server.js",
10 | "scripts": {
11 | "clean": "rm -rf dist public/assets && mkdir dist",
12 | "start": "node ./dist/index.js",
13 | "start-dev": "babel-node ./server/dev.js",
14 | "build:webpack": "NODE_ENV=production webpack --config webpack.config.prod.js --progress --colors",
15 | "build:server": "babel -d ./dist ./server",
16 | "build": "npm run clean && npm run build:webpack && npm run build:server",
17 | "update-schema": "babel-node ./scripts/updateSchema.js",
18 | "db:seed": "babel-node ./scripts/seed.js"
19 | },
20 | "keywords": [
21 | "React",
22 | "Graphql",
23 | "Relay",
24 | "Sequelize",
25 | "Babel 6"
26 | ],
27 | "author": "doabit",
28 | "license": "MIT",
29 | "dependencies": {
30 | "express": "^4.13.3",
31 | "express-graphql": "^0.4.5",
32 | "graphql": "^0.4.14",
33 | "graphql-relay": "^0.3.5",
34 | "history": "^1.13.1",
35 | "lodash": "^3.10.1",
36 | "react": "^0.14.3",
37 | "react-dom": "^0.14.3",
38 | "react-relay": "^0.6.1",
39 | "react-router": "^1.0.2",
40 | "react-router-relay": "^0.8.0",
41 | "sequelize": "^3.14.2",
42 | "faker": "^3.0.1",
43 | "sqlite3": "^3.1.1"
44 | },
45 | "devDependencies": {
46 | "babel-core": "^6.3.17",
47 | "babel-loader": "^6.2.0",
48 | "babel-preset-es2015": "^6.3.13",
49 | "babel-preset-react": "^6.3.13",
50 | "babel-preset-stage-0": "^6.3.13",
51 | "babel-relay-plugin": "^0.6.3",
52 | "babel-preset-react-hmre": "^1.0.1",
53 | "webpack": "^1.12.9",
54 | "webpack-dev-middleware": "^1.4.0",
55 | "webpack-hot-middleware": "^2.6.0"
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/server/data/methods.js:
--------------------------------------------------------------------------------
1 | // From https://github.com/MattMcFarland/sequelize-relay/blob/master/src/data/methods.js
2 |
3 | /* @flow */
4 |
5 | type SequelizeClass = {
6 | findAll: Function
7 | }
8 |
9 | type Attributes = Object;
10 | type SequelizeModel = {
11 | type: String,
12 | dataValues: Attributes
13 | }
14 |
15 | /**
16 | * Converts an array of instances to an array of
17 | * objects.
18 | * @param instances
19 | * @param withMethods {Boolean} false by default.
20 | * @returns {Array.}
21 | */
22 | export function getArrayData(
23 | instances: Array,
24 | withMethods: boolean = false
25 | ): Array {
26 |
27 | if (withMethods) {
28 | return [].concat(...instances);
29 | } else {
30 | return [].concat(instances.map(model => {
31 | return Object.assign({}, {
32 | type: model.type
33 | }, {
34 | ...model.dataValues
35 | });
36 | }));
37 | }
38 | }
39 |
40 |
41 | /**
42 | * Returns an `Array` of
43 | * instances that are of the passed-in `Class`.
44 | * @param SeqClass
45 | * @returns {Array.}
46 | */
47 | export function getModelsByClass(
48 | SeqClass: SequelizeClass
49 | ): Array {
50 | return SeqClass.findAll();
51 | }
52 |
53 |
54 |
55 | /**
56 | * First, it internally resolves an an `Array` of
57 | * instances that are of the passed-in `Class`.
58 | * Then it converts the array into a **promised** `Array` of
59 | * objects.
60 | * @param SeqClass
61 | * @param withMethods {Boolean} false by default.
62 | * @returns {Array.}
63 | */
64 | export function resolveArrayByClass(
65 | SeqClass: SequelizeClass,
66 | withMethods: boolean = false
67 | ): Promise> {
68 | return new Promise((resolve, reject) => {
69 | resolveModelsByClass(SeqClass).then(m => {
70 | resolve(getArrayData(m, withMethods));
71 | }).catch(reject);
72 | });
73 |
74 | }
75 |
76 |
77 |
78 | /**
79 | * Converts a promised `Array` of instances into a
80 | * **promised** `Array` of objects.
81 | * @param instances
82 | * @param withMethods {Boolean} false by default.
83 | * @returns {Promise>}
84 | */
85 | export function resolveArrayData(
86 | instances: Promise>,
87 | withMethods: boolean = false
88 | ): Promise> {
89 | return new Promise((resolve, reject) => {
90 | instances.then((models) => {
91 | resolve(getArrayData(models, withMethods));
92 | }).catch(reject);
93 | });
94 | }
95 |
96 |
97 | /**
98 | * Returns a **promised** `Array` of objects by `Class`.
99 | *
100 | * @param SeqClass
101 | * @returns {Promise>}
102 | */
103 | export function resolveModelsByClass(
104 | SeqClass: SequelizeClass
105 | ): Promise> {
106 | return SeqClass.findAll();
107 | }
--------------------------------------------------------------------------------
/js/components/posts/PostList.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Relay from 'react-relay';
3 | import Post from './Post';
4 | import CreatePostMutation from "../../mutations/CreatePostMutation";
5 |
6 | class PostList extends React.Component {
7 | // constructor(props) {
8 | // super(props);
9 | // }
10 | handleSubmit = (e) => {
11 | e.preventDefault();
12 | let onSuccess = () => {
13 | console.log("Create post success");
14 | };
15 | let onFailure = (transaction) => {
16 | var error = transaction.getError() || new Error('Mutation failed.');
17 | console.error(error);
18 | };
19 |
20 | Relay.Store.commitUpdate(
21 | new CreatePostMutation({
22 | title: this.refs.newTitle.value,
23 | content: this.refs.newContent.value,
24 | person: this.refs.newPerson.value,
25 | store: this.props.store
26 | }),
27 | {onFailure, onSuccess}
28 | );
29 | this.refs.newTitle.value = "";
30 | this.refs.newContent.value = "";
31 | };
32 |
33 | render() {
34 | let currentNumber = this.props.relay.variables.first;
35 | var buttonStyle = {};
36 | if (!this.props.store.posts.pageInfo.hasNextPage) {
37 | buttonStyle.display = 'none';
38 | }
39 |
40 | return (
41 |
42 |
Post List
43 |
44 | {this.props.store.posts.edges.map(edge =>
45 |
46 | )}
47 |
48 |
56 |
57 |
86 |
87 |
88 | );
89 | }
90 | }
91 |
92 | export default Relay.createContainer(PostList, {
93 | initialVariables: {
94 | first: 5
95 | },
96 | fragments: {
97 | store: () => Relay.QL`
98 | fragment on Store {
99 | id
100 | people(first: 10){
101 | edges{
102 | node{
103 | id
104 | firstName
105 | lastName
106 | email
107 | }
108 | }
109 | }
110 |
111 | posts(first: $first){
112 | edges{
113 | node{
114 | id
115 | ${Post.getFragment('post')}
116 | }
117 | },
118 | pageInfo {
119 | hasNextPage
120 | }
121 | }
122 | }
123 | `,
124 | },
125 | });
126 |
--------------------------------------------------------------------------------
/server/data/schema.js:
--------------------------------------------------------------------------------
1 | import {
2 | GraphQLObjectType,
3 | GraphQLInt,
4 | GraphQLString,
5 | GraphQLList,
6 | GraphQLSchema,
7 | GraphQLNonNull
8 | } from 'graphql';
9 |
10 | import {
11 | Post,
12 | Person
13 | } from './database';
14 |
15 | import {
16 | fromGlobalId,
17 | globalIdField,
18 | nodeDefinitions,
19 | connectionArgs,
20 | connectionDefinitions,
21 | offsetToCursor,
22 | cursorForObjectInConnection,
23 | // connectionFromArray,
24 | connectionFromPromisedArray,
25 | mutationWithClientMutationId
26 | } from 'graphql-relay';
27 |
28 |
29 | import {
30 | getArrayData,
31 | getModelsByClass,
32 | resolveArrayByClass,
33 | resolveArrayData,
34 | resolveModelsByClass
35 | } from './methods';
36 |
37 | const _ = require('lodash');
38 |
39 | var {nodeInterface, nodeField} = nodeDefinitions(
40 | (globalId) => {
41 | var {type, id} = fromGlobalId(globalId);
42 | switch (type) {
43 | case 'Person':
44 | return Person.findById(id);
45 | case 'Post':
46 | return Post.findById(id);
47 | case 'Store':
48 | return store;
49 | default:
50 | return null;
51 | }
52 | },
53 | (obj) => {
54 | if (obj instanceof Person.Instance) {
55 | return PersonType;
56 | } else if (obj instanceof Post.Instance) {
57 | return PostType;
58 | } else if (obj instanceof Store) {
59 | return StoreType;
60 | } else {
61 | return null;
62 | }
63 | }
64 | );
65 |
66 | const PersonType = new GraphQLObjectType({
67 | name: 'Person',
68 | description: 'This response a Person',
69 | interfaces: [nodeInterface],
70 | fields: () => {
71 | return {
72 | id: globalIdField('Person'),
73 | firstName: {
74 | type: GraphQLString,
75 | resolve(person) {
76 | return person.firstName
77 | }
78 | },
79 | lastName: {
80 | type: GraphQLString,
81 | resolve(person) {
82 | return person.lastName
83 | }
84 | },
85 | email: {
86 | type: GraphQLString,
87 | resolve(person) {
88 | return person.email
89 | }
90 | },
91 | posts: {
92 | type: postConnection,
93 | args: connectionArgs,
94 | resolve: (person, args) => {
95 | return connectionFromPromisedArray(
96 | resolveArrayData(person.getPosts(), true), args
97 | )
98 | }
99 | }
100 | // posts: {
101 | // type: new GraphQLList(PostType),
102 | // resolve(person) {
103 | // console.log(person)
104 | // return person.getPosts()
105 | // }
106 | // }
107 | };
108 | }
109 | });
110 |
111 |
112 | const PostType = new GraphQLObjectType({
113 | name: 'Post',
114 | description: 'This response Post',
115 | interfaces: [nodeInterface],
116 | fields: () => {
117 | return {
118 | id: globalIdField('Post'),
119 | title: {
120 | type: GraphQLString,
121 | resolve(post) {
122 | return post.title
123 | }
124 | },
125 | content: {
126 | type: GraphQLString,
127 | resolve(post) {
128 | return post.content
129 | }
130 | },
131 | person: {
132 | type: PersonType,
133 | resolve(post) {
134 | // return Person.findById(post.personId)
135 | return post.getPerson();
136 | }
137 | }
138 | };
139 | }
140 | });
141 |
142 | const {
143 | connectionType: postConnection,
144 | edgeType: postEdge
145 | } = connectionDefinitions({name: 'Post', nodeType: PostType});
146 |
147 | const {
148 | connectionType: personConnection,
149 | edgeType: personEdge
150 | } = connectionDefinitions({name: 'Person', nodeType: PersonType});
151 |
152 | const StoreType = new GraphQLObjectType({
153 | name: 'Store',
154 | interfaces: [nodeInterface],
155 | fields: () => ({
156 | id: globalIdField("Store"),
157 | people: {
158 | type: personConnection,
159 | args: connectionArgs,
160 | resolve: (root, args) => {
161 | return connectionFromPromisedArray(
162 | resolveArrayData(Person.findAll(), true), args
163 | )
164 | }
165 | },
166 | posts: {
167 | type: postConnection,
168 | args: connectionArgs,
169 | resolve: (_, args) => {
170 | return connectionFromPromisedArray(
171 | resolveArrayData(Post.findAll(), true), args
172 | )
173 | }
174 | }
175 | }),
176 | });
177 |
178 | class Store {}
179 | // Mock data
180 | let store = new Store();
181 |
182 | const Query = new GraphQLObjectType({
183 | name: 'Query',
184 | fields: {
185 | node: nodeField,
186 | store: {
187 | type: StoreType,
188 | resolve: () => store,
189 | },
190 | },
191 | });
192 |
193 |
194 | const createPostMutation = mutationWithClientMutationId({
195 | name: 'CreatePost',
196 |
197 | inputFields: {
198 | title: { type: new GraphQLNonNull(GraphQLString) },
199 | content: { type: new GraphQLNonNull(GraphQLString) },
200 | person: { type: new GraphQLNonNull(GraphQLString) },
201 | },
202 |
203 | // outputFields: {
204 | // postEdge: {
205 | // type: postEdge,
206 | // resolve: ({obj}) => {
207 | // console.log("obj")
208 | //
209 | // // return { node: obj.ops[0], cursor: obj.insertedId }
210 | // }
211 | // },
212 | // store: {
213 | // type: StoreType,
214 | // resolve: () => store
215 | // }
216 | // },
217 |
218 | outputFields: {
219 | postEdge: {
220 | type: postEdge,
221 | resolve: ({newPost, cursor}) => {
222 | return {
223 | cursor,
224 | node: newPost
225 | }
226 | // return Post.findAll()
227 | // .then(posts => {
228 | // return {
229 | // cursor,
230 | // node: newPost
231 | // }
232 | // })
233 | }
234 | },
235 | store: {
236 | type: StoreType,
237 | resolve: () => store
238 | }
239 | },
240 |
241 | mutateAndGetPayload: ({title, content, person}) => {
242 | const {type, id} = fromGlobalId(person);
243 | return Post.create({title: title, content: content, personId: id})
244 | .then(newPost => {
245 | return Post.findAll().then(posts => {
246 | return {
247 | newPost,
248 | cursor: offsetToCursor(
249 | _.findIndex(posts, post => post.id === newPost.id)
250 | )
251 | }
252 | })
253 | })
254 | }
255 |
256 | // mutateAndGetPayload: ({title, content}) => {
257 | // console.log(title);
258 | // Post.create({
259 | // personId: 1,
260 | // title: title,
261 | // content: content
262 | // }).then( post =>{
263 | // console.log(post.id);
264 | // return {post};
265 | // });
266 | // let localPostId = post.id
267 | // return {localPostId}
268 | // return db.collection("links").insertOne({
269 | // title,
270 | // content,
271 | // createdAt: Date.now()
272 | // });
273 | // }
274 | });
275 |
276 | const Schema = new GraphQLSchema({
277 | query: Query,
278 | mutation: new GraphQLObjectType({
279 | name: 'Mutation',
280 | fields: () => ({
281 | createPost: createPostMutation
282 | })
283 | })
284 | });
285 |
286 | export default Schema;
287 |
--------------------------------------------------------------------------------
/data/schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "data": {
3 | "__schema": {
4 | "queryType": {
5 | "name": "Query"
6 | },
7 | "mutationType": {
8 | "name": "Mutation"
9 | },
10 | "subscriptionType": null,
11 | "types": [
12 | {
13 | "kind": "OBJECT",
14 | "name": "Query",
15 | "description": null,
16 | "fields": [
17 | {
18 | "name": "node",
19 | "description": "Fetches an object given its ID",
20 | "args": [
21 | {
22 | "name": "id",
23 | "description": "The ID of an object",
24 | "type": {
25 | "kind": "NON_NULL",
26 | "name": null,
27 | "ofType": {
28 | "kind": "SCALAR",
29 | "name": "ID",
30 | "ofType": null
31 | }
32 | },
33 | "defaultValue": null
34 | }
35 | ],
36 | "type": {
37 | "kind": "INTERFACE",
38 | "name": "Node",
39 | "ofType": null
40 | },
41 | "isDeprecated": false,
42 | "deprecationReason": null
43 | },
44 | {
45 | "name": "store",
46 | "description": null,
47 | "args": [],
48 | "type": {
49 | "kind": "OBJECT",
50 | "name": "Store",
51 | "ofType": null
52 | },
53 | "isDeprecated": false,
54 | "deprecationReason": null
55 | }
56 | ],
57 | "inputFields": null,
58 | "interfaces": [],
59 | "enumValues": null,
60 | "possibleTypes": null
61 | },
62 | {
63 | "kind": "SCALAR",
64 | "name": "ID",
65 | "description": "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID.",
66 | "fields": null,
67 | "inputFields": null,
68 | "interfaces": null,
69 | "enumValues": null,
70 | "possibleTypes": null
71 | },
72 | {
73 | "kind": "INTERFACE",
74 | "name": "Node",
75 | "description": "An object with an ID",
76 | "fields": [
77 | {
78 | "name": "id",
79 | "description": "The id of the object.",
80 | "args": [],
81 | "type": {
82 | "kind": "NON_NULL",
83 | "name": null,
84 | "ofType": {
85 | "kind": "SCALAR",
86 | "name": "ID",
87 | "ofType": null
88 | }
89 | },
90 | "isDeprecated": false,
91 | "deprecationReason": null
92 | }
93 | ],
94 | "inputFields": null,
95 | "interfaces": null,
96 | "enumValues": null,
97 | "possibleTypes": [
98 | {
99 | "kind": "OBJECT",
100 | "name": "Person",
101 | "ofType": null
102 | },
103 | {
104 | "kind": "OBJECT",
105 | "name": "Post",
106 | "ofType": null
107 | },
108 | {
109 | "kind": "OBJECT",
110 | "name": "Store",
111 | "ofType": null
112 | }
113 | ]
114 | },
115 | {
116 | "kind": "OBJECT",
117 | "name": "Person",
118 | "description": "This response a Person",
119 | "fields": [
120 | {
121 | "name": "id",
122 | "description": "The ID of an object",
123 | "args": [],
124 | "type": {
125 | "kind": "NON_NULL",
126 | "name": null,
127 | "ofType": {
128 | "kind": "SCALAR",
129 | "name": "ID",
130 | "ofType": null
131 | }
132 | },
133 | "isDeprecated": false,
134 | "deprecationReason": null
135 | },
136 | {
137 | "name": "firstName",
138 | "description": null,
139 | "args": [],
140 | "type": {
141 | "kind": "SCALAR",
142 | "name": "String",
143 | "ofType": null
144 | },
145 | "isDeprecated": false,
146 | "deprecationReason": null
147 | },
148 | {
149 | "name": "lastName",
150 | "description": null,
151 | "args": [],
152 | "type": {
153 | "kind": "SCALAR",
154 | "name": "String",
155 | "ofType": null
156 | },
157 | "isDeprecated": false,
158 | "deprecationReason": null
159 | },
160 | {
161 | "name": "email",
162 | "description": null,
163 | "args": [],
164 | "type": {
165 | "kind": "SCALAR",
166 | "name": "String",
167 | "ofType": null
168 | },
169 | "isDeprecated": false,
170 | "deprecationReason": null
171 | },
172 | {
173 | "name": "posts",
174 | "description": null,
175 | "args": [
176 | {
177 | "name": "after",
178 | "description": null,
179 | "type": {
180 | "kind": "SCALAR",
181 | "name": "String",
182 | "ofType": null
183 | },
184 | "defaultValue": null
185 | },
186 | {
187 | "name": "first",
188 | "description": null,
189 | "type": {
190 | "kind": "SCALAR",
191 | "name": "Int",
192 | "ofType": null
193 | },
194 | "defaultValue": null
195 | },
196 | {
197 | "name": "before",
198 | "description": null,
199 | "type": {
200 | "kind": "SCALAR",
201 | "name": "String",
202 | "ofType": null
203 | },
204 | "defaultValue": null
205 | },
206 | {
207 | "name": "last",
208 | "description": null,
209 | "type": {
210 | "kind": "SCALAR",
211 | "name": "Int",
212 | "ofType": null
213 | },
214 | "defaultValue": null
215 | }
216 | ],
217 | "type": {
218 | "kind": "OBJECT",
219 | "name": "PostConnection",
220 | "ofType": null
221 | },
222 | "isDeprecated": false,
223 | "deprecationReason": null
224 | }
225 | ],
226 | "inputFields": null,
227 | "interfaces": [
228 | {
229 | "kind": "INTERFACE",
230 | "name": "Node",
231 | "ofType": null
232 | }
233 | ],
234 | "enumValues": null,
235 | "possibleTypes": null
236 | },
237 | {
238 | "kind": "SCALAR",
239 | "name": "String",
240 | "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.",
241 | "fields": null,
242 | "inputFields": null,
243 | "interfaces": null,
244 | "enumValues": null,
245 | "possibleTypes": null
246 | },
247 | {
248 | "kind": "SCALAR",
249 | "name": "Int",
250 | "description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^53 - 1) and 2^53 - 1 since represented in JSON as double-precision floating point numbers specifiedby [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).",
251 | "fields": null,
252 | "inputFields": null,
253 | "interfaces": null,
254 | "enumValues": null,
255 | "possibleTypes": null
256 | },
257 | {
258 | "kind": "OBJECT",
259 | "name": "PostConnection",
260 | "description": "A connection to a list of items.",
261 | "fields": [
262 | {
263 | "name": "pageInfo",
264 | "description": "Information to aid in pagination.",
265 | "args": [],
266 | "type": {
267 | "kind": "NON_NULL",
268 | "name": null,
269 | "ofType": {
270 | "kind": "OBJECT",
271 | "name": "PageInfo",
272 | "ofType": null
273 | }
274 | },
275 | "isDeprecated": false,
276 | "deprecationReason": null
277 | },
278 | {
279 | "name": "edges",
280 | "description": "Information to aid in pagination.",
281 | "args": [],
282 | "type": {
283 | "kind": "LIST",
284 | "name": null,
285 | "ofType": {
286 | "kind": "OBJECT",
287 | "name": "PostEdge",
288 | "ofType": null
289 | }
290 | },
291 | "isDeprecated": false,
292 | "deprecationReason": null
293 | }
294 | ],
295 | "inputFields": null,
296 | "interfaces": [],
297 | "enumValues": null,
298 | "possibleTypes": null
299 | },
300 | {
301 | "kind": "OBJECT",
302 | "name": "PageInfo",
303 | "description": "Information about pagination in a connection.",
304 | "fields": [
305 | {
306 | "name": "hasNextPage",
307 | "description": "When paginating forwards, are there more items?",
308 | "args": [],
309 | "type": {
310 | "kind": "NON_NULL",
311 | "name": null,
312 | "ofType": {
313 | "kind": "SCALAR",
314 | "name": "Boolean",
315 | "ofType": null
316 | }
317 | },
318 | "isDeprecated": false,
319 | "deprecationReason": null
320 | },
321 | {
322 | "name": "hasPreviousPage",
323 | "description": "When paginating backwards, are there more items?",
324 | "args": [],
325 | "type": {
326 | "kind": "NON_NULL",
327 | "name": null,
328 | "ofType": {
329 | "kind": "SCALAR",
330 | "name": "Boolean",
331 | "ofType": null
332 | }
333 | },
334 | "isDeprecated": false,
335 | "deprecationReason": null
336 | },
337 | {
338 | "name": "startCursor",
339 | "description": "When paginating backwards, the cursor to continue.",
340 | "args": [],
341 | "type": {
342 | "kind": "SCALAR",
343 | "name": "String",
344 | "ofType": null
345 | },
346 | "isDeprecated": false,
347 | "deprecationReason": null
348 | },
349 | {
350 | "name": "endCursor",
351 | "description": "When paginating forwards, the cursor to continue.",
352 | "args": [],
353 | "type": {
354 | "kind": "SCALAR",
355 | "name": "String",
356 | "ofType": null
357 | },
358 | "isDeprecated": false,
359 | "deprecationReason": null
360 | }
361 | ],
362 | "inputFields": null,
363 | "interfaces": [],
364 | "enumValues": null,
365 | "possibleTypes": null
366 | },
367 | {
368 | "kind": "SCALAR",
369 | "name": "Boolean",
370 | "description": "The `Boolean` scalar type represents `true` or `false`.",
371 | "fields": null,
372 | "inputFields": null,
373 | "interfaces": null,
374 | "enumValues": null,
375 | "possibleTypes": null
376 | },
377 | {
378 | "kind": "OBJECT",
379 | "name": "PostEdge",
380 | "description": "An edge in a connection.",
381 | "fields": [
382 | {
383 | "name": "node",
384 | "description": "The item at the end of the edge",
385 | "args": [],
386 | "type": {
387 | "kind": "OBJECT",
388 | "name": "Post",
389 | "ofType": null
390 | },
391 | "isDeprecated": false,
392 | "deprecationReason": null
393 | },
394 | {
395 | "name": "cursor",
396 | "description": "A cursor for use in pagination",
397 | "args": [],
398 | "type": {
399 | "kind": "NON_NULL",
400 | "name": null,
401 | "ofType": {
402 | "kind": "SCALAR",
403 | "name": "String",
404 | "ofType": null
405 | }
406 | },
407 | "isDeprecated": false,
408 | "deprecationReason": null
409 | }
410 | ],
411 | "inputFields": null,
412 | "interfaces": [],
413 | "enumValues": null,
414 | "possibleTypes": null
415 | },
416 | {
417 | "kind": "OBJECT",
418 | "name": "Post",
419 | "description": "This response Post",
420 | "fields": [
421 | {
422 | "name": "id",
423 | "description": "The ID of an object",
424 | "args": [],
425 | "type": {
426 | "kind": "NON_NULL",
427 | "name": null,
428 | "ofType": {
429 | "kind": "SCALAR",
430 | "name": "ID",
431 | "ofType": null
432 | }
433 | },
434 | "isDeprecated": false,
435 | "deprecationReason": null
436 | },
437 | {
438 | "name": "title",
439 | "description": null,
440 | "args": [],
441 | "type": {
442 | "kind": "SCALAR",
443 | "name": "String",
444 | "ofType": null
445 | },
446 | "isDeprecated": false,
447 | "deprecationReason": null
448 | },
449 | {
450 | "name": "content",
451 | "description": null,
452 | "args": [],
453 | "type": {
454 | "kind": "SCALAR",
455 | "name": "String",
456 | "ofType": null
457 | },
458 | "isDeprecated": false,
459 | "deprecationReason": null
460 | },
461 | {
462 | "name": "person",
463 | "description": null,
464 | "args": [],
465 | "type": {
466 | "kind": "OBJECT",
467 | "name": "Person",
468 | "ofType": null
469 | },
470 | "isDeprecated": false,
471 | "deprecationReason": null
472 | }
473 | ],
474 | "inputFields": null,
475 | "interfaces": [
476 | {
477 | "kind": "INTERFACE",
478 | "name": "Node",
479 | "ofType": null
480 | }
481 | ],
482 | "enumValues": null,
483 | "possibleTypes": null
484 | },
485 | {
486 | "kind": "OBJECT",
487 | "name": "Store",
488 | "description": null,
489 | "fields": [
490 | {
491 | "name": "id",
492 | "description": "The ID of an object",
493 | "args": [],
494 | "type": {
495 | "kind": "NON_NULL",
496 | "name": null,
497 | "ofType": {
498 | "kind": "SCALAR",
499 | "name": "ID",
500 | "ofType": null
501 | }
502 | },
503 | "isDeprecated": false,
504 | "deprecationReason": null
505 | },
506 | {
507 | "name": "people",
508 | "description": null,
509 | "args": [
510 | {
511 | "name": "after",
512 | "description": null,
513 | "type": {
514 | "kind": "SCALAR",
515 | "name": "String",
516 | "ofType": null
517 | },
518 | "defaultValue": null
519 | },
520 | {
521 | "name": "first",
522 | "description": null,
523 | "type": {
524 | "kind": "SCALAR",
525 | "name": "Int",
526 | "ofType": null
527 | },
528 | "defaultValue": null
529 | },
530 | {
531 | "name": "before",
532 | "description": null,
533 | "type": {
534 | "kind": "SCALAR",
535 | "name": "String",
536 | "ofType": null
537 | },
538 | "defaultValue": null
539 | },
540 | {
541 | "name": "last",
542 | "description": null,
543 | "type": {
544 | "kind": "SCALAR",
545 | "name": "Int",
546 | "ofType": null
547 | },
548 | "defaultValue": null
549 | }
550 | ],
551 | "type": {
552 | "kind": "OBJECT",
553 | "name": "PersonConnection",
554 | "ofType": null
555 | },
556 | "isDeprecated": false,
557 | "deprecationReason": null
558 | },
559 | {
560 | "name": "posts",
561 | "description": null,
562 | "args": [
563 | {
564 | "name": "after",
565 | "description": null,
566 | "type": {
567 | "kind": "SCALAR",
568 | "name": "String",
569 | "ofType": null
570 | },
571 | "defaultValue": null
572 | },
573 | {
574 | "name": "first",
575 | "description": null,
576 | "type": {
577 | "kind": "SCALAR",
578 | "name": "Int",
579 | "ofType": null
580 | },
581 | "defaultValue": null
582 | },
583 | {
584 | "name": "before",
585 | "description": null,
586 | "type": {
587 | "kind": "SCALAR",
588 | "name": "String",
589 | "ofType": null
590 | },
591 | "defaultValue": null
592 | },
593 | {
594 | "name": "last",
595 | "description": null,
596 | "type": {
597 | "kind": "SCALAR",
598 | "name": "Int",
599 | "ofType": null
600 | },
601 | "defaultValue": null
602 | }
603 | ],
604 | "type": {
605 | "kind": "OBJECT",
606 | "name": "PostConnection",
607 | "ofType": null
608 | },
609 | "isDeprecated": false,
610 | "deprecationReason": null
611 | }
612 | ],
613 | "inputFields": null,
614 | "interfaces": [
615 | {
616 | "kind": "INTERFACE",
617 | "name": "Node",
618 | "ofType": null
619 | }
620 | ],
621 | "enumValues": null,
622 | "possibleTypes": null
623 | },
624 | {
625 | "kind": "OBJECT",
626 | "name": "PersonConnection",
627 | "description": "A connection to a list of items.",
628 | "fields": [
629 | {
630 | "name": "pageInfo",
631 | "description": "Information to aid in pagination.",
632 | "args": [],
633 | "type": {
634 | "kind": "NON_NULL",
635 | "name": null,
636 | "ofType": {
637 | "kind": "OBJECT",
638 | "name": "PageInfo",
639 | "ofType": null
640 | }
641 | },
642 | "isDeprecated": false,
643 | "deprecationReason": null
644 | },
645 | {
646 | "name": "edges",
647 | "description": "Information to aid in pagination.",
648 | "args": [],
649 | "type": {
650 | "kind": "LIST",
651 | "name": null,
652 | "ofType": {
653 | "kind": "OBJECT",
654 | "name": "PersonEdge",
655 | "ofType": null
656 | }
657 | },
658 | "isDeprecated": false,
659 | "deprecationReason": null
660 | }
661 | ],
662 | "inputFields": null,
663 | "interfaces": [],
664 | "enumValues": null,
665 | "possibleTypes": null
666 | },
667 | {
668 | "kind": "OBJECT",
669 | "name": "PersonEdge",
670 | "description": "An edge in a connection.",
671 | "fields": [
672 | {
673 | "name": "node",
674 | "description": "The item at the end of the edge",
675 | "args": [],
676 | "type": {
677 | "kind": "OBJECT",
678 | "name": "Person",
679 | "ofType": null
680 | },
681 | "isDeprecated": false,
682 | "deprecationReason": null
683 | },
684 | {
685 | "name": "cursor",
686 | "description": "A cursor for use in pagination",
687 | "args": [],
688 | "type": {
689 | "kind": "NON_NULL",
690 | "name": null,
691 | "ofType": {
692 | "kind": "SCALAR",
693 | "name": "String",
694 | "ofType": null
695 | }
696 | },
697 | "isDeprecated": false,
698 | "deprecationReason": null
699 | }
700 | ],
701 | "inputFields": null,
702 | "interfaces": [],
703 | "enumValues": null,
704 | "possibleTypes": null
705 | },
706 | {
707 | "kind": "OBJECT",
708 | "name": "Mutation",
709 | "description": null,
710 | "fields": [
711 | {
712 | "name": "createPost",
713 | "description": null,
714 | "args": [
715 | {
716 | "name": "input",
717 | "description": null,
718 | "type": {
719 | "kind": "NON_NULL",
720 | "name": null,
721 | "ofType": {
722 | "kind": "INPUT_OBJECT",
723 | "name": "CreatePostInput",
724 | "ofType": null
725 | }
726 | },
727 | "defaultValue": null
728 | }
729 | ],
730 | "type": {
731 | "kind": "OBJECT",
732 | "name": "CreatePostPayload",
733 | "ofType": null
734 | },
735 | "isDeprecated": false,
736 | "deprecationReason": null
737 | }
738 | ],
739 | "inputFields": null,
740 | "interfaces": [],
741 | "enumValues": null,
742 | "possibleTypes": null
743 | },
744 | {
745 | "kind": "INPUT_OBJECT",
746 | "name": "CreatePostInput",
747 | "description": null,
748 | "fields": null,
749 | "inputFields": [
750 | {
751 | "name": "title",
752 | "description": null,
753 | "type": {
754 | "kind": "NON_NULL",
755 | "name": null,
756 | "ofType": {
757 | "kind": "SCALAR",
758 | "name": "String",
759 | "ofType": null
760 | }
761 | },
762 | "defaultValue": null
763 | },
764 | {
765 | "name": "content",
766 | "description": null,
767 | "type": {
768 | "kind": "NON_NULL",
769 | "name": null,
770 | "ofType": {
771 | "kind": "SCALAR",
772 | "name": "String",
773 | "ofType": null
774 | }
775 | },
776 | "defaultValue": null
777 | },
778 | {
779 | "name": "person",
780 | "description": null,
781 | "type": {
782 | "kind": "NON_NULL",
783 | "name": null,
784 | "ofType": {
785 | "kind": "SCALAR",
786 | "name": "String",
787 | "ofType": null
788 | }
789 | },
790 | "defaultValue": null
791 | },
792 | {
793 | "name": "clientMutationId",
794 | "description": null,
795 | "type": {
796 | "kind": "NON_NULL",
797 | "name": null,
798 | "ofType": {
799 | "kind": "SCALAR",
800 | "name": "String",
801 | "ofType": null
802 | }
803 | },
804 | "defaultValue": null
805 | }
806 | ],
807 | "interfaces": null,
808 | "enumValues": null,
809 | "possibleTypes": null
810 | },
811 | {
812 | "kind": "OBJECT",
813 | "name": "CreatePostPayload",
814 | "description": null,
815 | "fields": [
816 | {
817 | "name": "postEdge",
818 | "description": null,
819 | "args": [],
820 | "type": {
821 | "kind": "OBJECT",
822 | "name": "PostEdge",
823 | "ofType": null
824 | },
825 | "isDeprecated": false,
826 | "deprecationReason": null
827 | },
828 | {
829 | "name": "store",
830 | "description": null,
831 | "args": [],
832 | "type": {
833 | "kind": "OBJECT",
834 | "name": "Store",
835 | "ofType": null
836 | },
837 | "isDeprecated": false,
838 | "deprecationReason": null
839 | },
840 | {
841 | "name": "clientMutationId",
842 | "description": null,
843 | "args": [],
844 | "type": {
845 | "kind": "NON_NULL",
846 | "name": null,
847 | "ofType": {
848 | "kind": "SCALAR",
849 | "name": "String",
850 | "ofType": null
851 | }
852 | },
853 | "isDeprecated": false,
854 | "deprecationReason": null
855 | }
856 | ],
857 | "inputFields": null,
858 | "interfaces": [],
859 | "enumValues": null,
860 | "possibleTypes": null
861 | },
862 | {
863 | "kind": "OBJECT",
864 | "name": "__Schema",
865 | "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.",
866 | "fields": [
867 | {
868 | "name": "types",
869 | "description": "A list of all types supported by this server.",
870 | "args": [],
871 | "type": {
872 | "kind": "NON_NULL",
873 | "name": null,
874 | "ofType": {
875 | "kind": "LIST",
876 | "name": null,
877 | "ofType": {
878 | "kind": "NON_NULL",
879 | "name": null,
880 | "ofType": {
881 | "kind": "OBJECT",
882 | "name": "__Type"
883 | }
884 | }
885 | }
886 | },
887 | "isDeprecated": false,
888 | "deprecationReason": null
889 | },
890 | {
891 | "name": "queryType",
892 | "description": "The type that query operations will be rooted at.",
893 | "args": [],
894 | "type": {
895 | "kind": "NON_NULL",
896 | "name": null,
897 | "ofType": {
898 | "kind": "OBJECT",
899 | "name": "__Type",
900 | "ofType": null
901 | }
902 | },
903 | "isDeprecated": false,
904 | "deprecationReason": null
905 | },
906 | {
907 | "name": "mutationType",
908 | "description": "If this server supports mutation, the type that mutation operations will be rooted at.",
909 | "args": [],
910 | "type": {
911 | "kind": "OBJECT",
912 | "name": "__Type",
913 | "ofType": null
914 | },
915 | "isDeprecated": false,
916 | "deprecationReason": null
917 | },
918 | {
919 | "name": "subscriptionType",
920 | "description": "If this server support subscription, the type that subscription operations will be rooted at.",
921 | "args": [],
922 | "type": {
923 | "kind": "OBJECT",
924 | "name": "__Type",
925 | "ofType": null
926 | },
927 | "isDeprecated": false,
928 | "deprecationReason": null
929 | },
930 | {
931 | "name": "directives",
932 | "description": "A list of all directives supported by this server.",
933 | "args": [],
934 | "type": {
935 | "kind": "NON_NULL",
936 | "name": null,
937 | "ofType": {
938 | "kind": "LIST",
939 | "name": null,
940 | "ofType": {
941 | "kind": "NON_NULL",
942 | "name": null,
943 | "ofType": {
944 | "kind": "OBJECT",
945 | "name": "__Directive"
946 | }
947 | }
948 | }
949 | },
950 | "isDeprecated": false,
951 | "deprecationReason": null
952 | }
953 | ],
954 | "inputFields": null,
955 | "interfaces": [],
956 | "enumValues": null,
957 | "possibleTypes": null
958 | },
959 | {
960 | "kind": "OBJECT",
961 | "name": "__Type",
962 | "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.",
963 | "fields": [
964 | {
965 | "name": "kind",
966 | "description": null,
967 | "args": [],
968 | "type": {
969 | "kind": "NON_NULL",
970 | "name": null,
971 | "ofType": {
972 | "kind": "ENUM",
973 | "name": "__TypeKind",
974 | "ofType": null
975 | }
976 | },
977 | "isDeprecated": false,
978 | "deprecationReason": null
979 | },
980 | {
981 | "name": "name",
982 | "description": null,
983 | "args": [],
984 | "type": {
985 | "kind": "SCALAR",
986 | "name": "String",
987 | "ofType": null
988 | },
989 | "isDeprecated": false,
990 | "deprecationReason": null
991 | },
992 | {
993 | "name": "description",
994 | "description": null,
995 | "args": [],
996 | "type": {
997 | "kind": "SCALAR",
998 | "name": "String",
999 | "ofType": null
1000 | },
1001 | "isDeprecated": false,
1002 | "deprecationReason": null
1003 | },
1004 | {
1005 | "name": "fields",
1006 | "description": null,
1007 | "args": [
1008 | {
1009 | "name": "includeDeprecated",
1010 | "description": null,
1011 | "type": {
1012 | "kind": "SCALAR",
1013 | "name": "Boolean",
1014 | "ofType": null
1015 | },
1016 | "defaultValue": "false"
1017 | }
1018 | ],
1019 | "type": {
1020 | "kind": "LIST",
1021 | "name": null,
1022 | "ofType": {
1023 | "kind": "NON_NULL",
1024 | "name": null,
1025 | "ofType": {
1026 | "kind": "OBJECT",
1027 | "name": "__Field",
1028 | "ofType": null
1029 | }
1030 | }
1031 | },
1032 | "isDeprecated": false,
1033 | "deprecationReason": null
1034 | },
1035 | {
1036 | "name": "interfaces",
1037 | "description": null,
1038 | "args": [],
1039 | "type": {
1040 | "kind": "LIST",
1041 | "name": null,
1042 | "ofType": {
1043 | "kind": "NON_NULL",
1044 | "name": null,
1045 | "ofType": {
1046 | "kind": "OBJECT",
1047 | "name": "__Type",
1048 | "ofType": null
1049 | }
1050 | }
1051 | },
1052 | "isDeprecated": false,
1053 | "deprecationReason": null
1054 | },
1055 | {
1056 | "name": "possibleTypes",
1057 | "description": null,
1058 | "args": [],
1059 | "type": {
1060 | "kind": "LIST",
1061 | "name": null,
1062 | "ofType": {
1063 | "kind": "NON_NULL",
1064 | "name": null,
1065 | "ofType": {
1066 | "kind": "OBJECT",
1067 | "name": "__Type",
1068 | "ofType": null
1069 | }
1070 | }
1071 | },
1072 | "isDeprecated": false,
1073 | "deprecationReason": null
1074 | },
1075 | {
1076 | "name": "enumValues",
1077 | "description": null,
1078 | "args": [
1079 | {
1080 | "name": "includeDeprecated",
1081 | "description": null,
1082 | "type": {
1083 | "kind": "SCALAR",
1084 | "name": "Boolean",
1085 | "ofType": null
1086 | },
1087 | "defaultValue": "false"
1088 | }
1089 | ],
1090 | "type": {
1091 | "kind": "LIST",
1092 | "name": null,
1093 | "ofType": {
1094 | "kind": "NON_NULL",
1095 | "name": null,
1096 | "ofType": {
1097 | "kind": "OBJECT",
1098 | "name": "__EnumValue",
1099 | "ofType": null
1100 | }
1101 | }
1102 | },
1103 | "isDeprecated": false,
1104 | "deprecationReason": null
1105 | },
1106 | {
1107 | "name": "inputFields",
1108 | "description": null,
1109 | "args": [],
1110 | "type": {
1111 | "kind": "LIST",
1112 | "name": null,
1113 | "ofType": {
1114 | "kind": "NON_NULL",
1115 | "name": null,
1116 | "ofType": {
1117 | "kind": "OBJECT",
1118 | "name": "__InputValue",
1119 | "ofType": null
1120 | }
1121 | }
1122 | },
1123 | "isDeprecated": false,
1124 | "deprecationReason": null
1125 | },
1126 | {
1127 | "name": "ofType",
1128 | "description": null,
1129 | "args": [],
1130 | "type": {
1131 | "kind": "OBJECT",
1132 | "name": "__Type",
1133 | "ofType": null
1134 | },
1135 | "isDeprecated": false,
1136 | "deprecationReason": null
1137 | }
1138 | ],
1139 | "inputFields": null,
1140 | "interfaces": [],
1141 | "enumValues": null,
1142 | "possibleTypes": null
1143 | },
1144 | {
1145 | "kind": "ENUM",
1146 | "name": "__TypeKind",
1147 | "description": "An enum describing what kind of type a given `__Type` is.",
1148 | "fields": null,
1149 | "inputFields": null,
1150 | "interfaces": null,
1151 | "enumValues": [
1152 | {
1153 | "name": "SCALAR",
1154 | "description": "Indicates this type is a scalar.",
1155 | "isDeprecated": false,
1156 | "deprecationReason": null
1157 | },
1158 | {
1159 | "name": "OBJECT",
1160 | "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.",
1161 | "isDeprecated": false,
1162 | "deprecationReason": null
1163 | },
1164 | {
1165 | "name": "INTERFACE",
1166 | "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.",
1167 | "isDeprecated": false,
1168 | "deprecationReason": null
1169 | },
1170 | {
1171 | "name": "UNION",
1172 | "description": "Indicates this type is a union. `possibleTypes` is a valid field.",
1173 | "isDeprecated": false,
1174 | "deprecationReason": null
1175 | },
1176 | {
1177 | "name": "ENUM",
1178 | "description": "Indicates this type is an enum. `enumValues` is a valid field.",
1179 | "isDeprecated": false,
1180 | "deprecationReason": null
1181 | },
1182 | {
1183 | "name": "INPUT_OBJECT",
1184 | "description": "Indicates this type is an input object. `inputFields` is a valid field.",
1185 | "isDeprecated": false,
1186 | "deprecationReason": null
1187 | },
1188 | {
1189 | "name": "LIST",
1190 | "description": "Indicates this type is a list. `ofType` is a valid field.",
1191 | "isDeprecated": false,
1192 | "deprecationReason": null
1193 | },
1194 | {
1195 | "name": "NON_NULL",
1196 | "description": "Indicates this type is a non-null. `ofType` is a valid field.",
1197 | "isDeprecated": false,
1198 | "deprecationReason": null
1199 | }
1200 | ],
1201 | "possibleTypes": null
1202 | },
1203 | {
1204 | "kind": "OBJECT",
1205 | "name": "__Field",
1206 | "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.",
1207 | "fields": [
1208 | {
1209 | "name": "name",
1210 | "description": null,
1211 | "args": [],
1212 | "type": {
1213 | "kind": "NON_NULL",
1214 | "name": null,
1215 | "ofType": {
1216 | "kind": "SCALAR",
1217 | "name": "String",
1218 | "ofType": null
1219 | }
1220 | },
1221 | "isDeprecated": false,
1222 | "deprecationReason": null
1223 | },
1224 | {
1225 | "name": "description",
1226 | "description": null,
1227 | "args": [],
1228 | "type": {
1229 | "kind": "SCALAR",
1230 | "name": "String",
1231 | "ofType": null
1232 | },
1233 | "isDeprecated": false,
1234 | "deprecationReason": null
1235 | },
1236 | {
1237 | "name": "args",
1238 | "description": null,
1239 | "args": [],
1240 | "type": {
1241 | "kind": "NON_NULL",
1242 | "name": null,
1243 | "ofType": {
1244 | "kind": "LIST",
1245 | "name": null,
1246 | "ofType": {
1247 | "kind": "NON_NULL",
1248 | "name": null,
1249 | "ofType": {
1250 | "kind": "OBJECT",
1251 | "name": "__InputValue"
1252 | }
1253 | }
1254 | }
1255 | },
1256 | "isDeprecated": false,
1257 | "deprecationReason": null
1258 | },
1259 | {
1260 | "name": "type",
1261 | "description": null,
1262 | "args": [],
1263 | "type": {
1264 | "kind": "NON_NULL",
1265 | "name": null,
1266 | "ofType": {
1267 | "kind": "OBJECT",
1268 | "name": "__Type",
1269 | "ofType": null
1270 | }
1271 | },
1272 | "isDeprecated": false,
1273 | "deprecationReason": null
1274 | },
1275 | {
1276 | "name": "isDeprecated",
1277 | "description": null,
1278 | "args": [],
1279 | "type": {
1280 | "kind": "NON_NULL",
1281 | "name": null,
1282 | "ofType": {
1283 | "kind": "SCALAR",
1284 | "name": "Boolean",
1285 | "ofType": null
1286 | }
1287 | },
1288 | "isDeprecated": false,
1289 | "deprecationReason": null
1290 | },
1291 | {
1292 | "name": "deprecationReason",
1293 | "description": null,
1294 | "args": [],
1295 | "type": {
1296 | "kind": "SCALAR",
1297 | "name": "String",
1298 | "ofType": null
1299 | },
1300 | "isDeprecated": false,
1301 | "deprecationReason": null
1302 | }
1303 | ],
1304 | "inputFields": null,
1305 | "interfaces": [],
1306 | "enumValues": null,
1307 | "possibleTypes": null
1308 | },
1309 | {
1310 | "kind": "OBJECT",
1311 | "name": "__InputValue",
1312 | "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.",
1313 | "fields": [
1314 | {
1315 | "name": "name",
1316 | "description": null,
1317 | "args": [],
1318 | "type": {
1319 | "kind": "NON_NULL",
1320 | "name": null,
1321 | "ofType": {
1322 | "kind": "SCALAR",
1323 | "name": "String",
1324 | "ofType": null
1325 | }
1326 | },
1327 | "isDeprecated": false,
1328 | "deprecationReason": null
1329 | },
1330 | {
1331 | "name": "description",
1332 | "description": null,
1333 | "args": [],
1334 | "type": {
1335 | "kind": "SCALAR",
1336 | "name": "String",
1337 | "ofType": null
1338 | },
1339 | "isDeprecated": false,
1340 | "deprecationReason": null
1341 | },
1342 | {
1343 | "name": "type",
1344 | "description": null,
1345 | "args": [],
1346 | "type": {
1347 | "kind": "NON_NULL",
1348 | "name": null,
1349 | "ofType": {
1350 | "kind": "OBJECT",
1351 | "name": "__Type",
1352 | "ofType": null
1353 | }
1354 | },
1355 | "isDeprecated": false,
1356 | "deprecationReason": null
1357 | },
1358 | {
1359 | "name": "defaultValue",
1360 | "description": "A GraphQL-formatted string representing the default value for this input value.",
1361 | "args": [],
1362 | "type": {
1363 | "kind": "SCALAR",
1364 | "name": "String",
1365 | "ofType": null
1366 | },
1367 | "isDeprecated": false,
1368 | "deprecationReason": null
1369 | }
1370 | ],
1371 | "inputFields": null,
1372 | "interfaces": [],
1373 | "enumValues": null,
1374 | "possibleTypes": null
1375 | },
1376 | {
1377 | "kind": "OBJECT",
1378 | "name": "__EnumValue",
1379 | "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.",
1380 | "fields": [
1381 | {
1382 | "name": "name",
1383 | "description": null,
1384 | "args": [],
1385 | "type": {
1386 | "kind": "NON_NULL",
1387 | "name": null,
1388 | "ofType": {
1389 | "kind": "SCALAR",
1390 | "name": "String",
1391 | "ofType": null
1392 | }
1393 | },
1394 | "isDeprecated": false,
1395 | "deprecationReason": null
1396 | },
1397 | {
1398 | "name": "description",
1399 | "description": null,
1400 | "args": [],
1401 | "type": {
1402 | "kind": "SCALAR",
1403 | "name": "String",
1404 | "ofType": null
1405 | },
1406 | "isDeprecated": false,
1407 | "deprecationReason": null
1408 | },
1409 | {
1410 | "name": "isDeprecated",
1411 | "description": null,
1412 | "args": [],
1413 | "type": {
1414 | "kind": "NON_NULL",
1415 | "name": null,
1416 | "ofType": {
1417 | "kind": "SCALAR",
1418 | "name": "Boolean",
1419 | "ofType": null
1420 | }
1421 | },
1422 | "isDeprecated": false,
1423 | "deprecationReason": null
1424 | },
1425 | {
1426 | "name": "deprecationReason",
1427 | "description": null,
1428 | "args": [],
1429 | "type": {
1430 | "kind": "SCALAR",
1431 | "name": "String",
1432 | "ofType": null
1433 | },
1434 | "isDeprecated": false,
1435 | "deprecationReason": null
1436 | }
1437 | ],
1438 | "inputFields": null,
1439 | "interfaces": [],
1440 | "enumValues": null,
1441 | "possibleTypes": null
1442 | },
1443 | {
1444 | "kind": "OBJECT",
1445 | "name": "__Directive",
1446 | "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL’s execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.",
1447 | "fields": [
1448 | {
1449 | "name": "name",
1450 | "description": null,
1451 | "args": [],
1452 | "type": {
1453 | "kind": "NON_NULL",
1454 | "name": null,
1455 | "ofType": {
1456 | "kind": "SCALAR",
1457 | "name": "String",
1458 | "ofType": null
1459 | }
1460 | },
1461 | "isDeprecated": false,
1462 | "deprecationReason": null
1463 | },
1464 | {
1465 | "name": "description",
1466 | "description": null,
1467 | "args": [],
1468 | "type": {
1469 | "kind": "SCALAR",
1470 | "name": "String",
1471 | "ofType": null
1472 | },
1473 | "isDeprecated": false,
1474 | "deprecationReason": null
1475 | },
1476 | {
1477 | "name": "args",
1478 | "description": null,
1479 | "args": [],
1480 | "type": {
1481 | "kind": "NON_NULL",
1482 | "name": null,
1483 | "ofType": {
1484 | "kind": "LIST",
1485 | "name": null,
1486 | "ofType": {
1487 | "kind": "NON_NULL",
1488 | "name": null,
1489 | "ofType": {
1490 | "kind": "OBJECT",
1491 | "name": "__InputValue"
1492 | }
1493 | }
1494 | }
1495 | },
1496 | "isDeprecated": false,
1497 | "deprecationReason": null
1498 | },
1499 | {
1500 | "name": "onOperation",
1501 | "description": null,
1502 | "args": [],
1503 | "type": {
1504 | "kind": "NON_NULL",
1505 | "name": null,
1506 | "ofType": {
1507 | "kind": "SCALAR",
1508 | "name": "Boolean",
1509 | "ofType": null
1510 | }
1511 | },
1512 | "isDeprecated": false,
1513 | "deprecationReason": null
1514 | },
1515 | {
1516 | "name": "onFragment",
1517 | "description": null,
1518 | "args": [],
1519 | "type": {
1520 | "kind": "NON_NULL",
1521 | "name": null,
1522 | "ofType": {
1523 | "kind": "SCALAR",
1524 | "name": "Boolean",
1525 | "ofType": null
1526 | }
1527 | },
1528 | "isDeprecated": false,
1529 | "deprecationReason": null
1530 | },
1531 | {
1532 | "name": "onField",
1533 | "description": null,
1534 | "args": [],
1535 | "type": {
1536 | "kind": "NON_NULL",
1537 | "name": null,
1538 | "ofType": {
1539 | "kind": "SCALAR",
1540 | "name": "Boolean",
1541 | "ofType": null
1542 | }
1543 | },
1544 | "isDeprecated": false,
1545 | "deprecationReason": null
1546 | }
1547 | ],
1548 | "inputFields": null,
1549 | "interfaces": [],
1550 | "enumValues": null,
1551 | "possibleTypes": null
1552 | }
1553 | ],
1554 | "directives": [
1555 | {
1556 | "name": "include",
1557 | "description": "Directs the executor to include this field or fragment only when the `if` argument is true.",
1558 | "args": [
1559 | {
1560 | "name": "if",
1561 | "description": "Included when true.",
1562 | "type": {
1563 | "kind": "NON_NULL",
1564 | "name": null,
1565 | "ofType": {
1566 | "kind": "SCALAR",
1567 | "name": "Boolean",
1568 | "ofType": null
1569 | }
1570 | },
1571 | "defaultValue": null
1572 | }
1573 | ],
1574 | "onOperation": false,
1575 | "onFragment": true,
1576 | "onField": true
1577 | },
1578 | {
1579 | "name": "skip",
1580 | "description": "Directs the executor to skip this field or fragment when the `if` argument is true.",
1581 | "args": [
1582 | {
1583 | "name": "if",
1584 | "description": "Skipped when true.",
1585 | "type": {
1586 | "kind": "NON_NULL",
1587 | "name": null,
1588 | "ofType": {
1589 | "kind": "SCALAR",
1590 | "name": "Boolean",
1591 | "ofType": null
1592 | }
1593 | },
1594 | "defaultValue": null
1595 | }
1596 | ],
1597 | "onOperation": false,
1598 | "onFragment": true,
1599 | "onField": true
1600 | }
1601 | ]
1602 | }
1603 | }
1604 | }
--------------------------------------------------------------------------------