├── .gitignore
├── relayPlugin.js
├── src
├── frontend
│ ├── components
│ │ ├── About.js
│ │ ├── User.js
│ │ ├── Application.js
│ │ ├── Logout.js
│ │ ├── Dashboard.js
│ │ ├── App.js
│ │ └── Login.js
│ ├── containers
│ │ ├── User.js
│ │ └── Application.js
│ ├── index.template.html
│ ├── roots
│ │ ├── UserRoot.js
│ │ └── ExampleRoot.js
│ ├── index2.js
│ ├── index.js
│ └── helpers
│ │ └── auth.js
├── server
│ ├── server.js
│ └── data
│ │ ├── schema.js
│ │ └── schema.json
└── public
│ └── ql
│ ├── index.html
│ └── graphiql.css
├── .eslintrc
├── README.md
├── CHANGELOG.md
├── webpack.config.js
├── LICENSE
├── package.json
└── gulpfile.babel.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | build
3 | *.sublime-project
4 | *.sublime-workspace
5 |
--------------------------------------------------------------------------------
/relayPlugin.js:
--------------------------------------------------------------------------------
1 | var getbabelRelayPlugin = require('babel-relay-plugin');
2 | var schema = require('./src/server/data/schema.json');
3 |
4 | module.exports = getbabelRelayPlugin(schema.data);
--------------------------------------------------------------------------------
/src/frontend/components/About.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default React.createClass({
4 | displayName: 'About',
5 |
6 | render() {
7 | return (
8 |
About
9 | );
10 | },
11 | });
12 |
13 |
--------------------------------------------------------------------------------
/src/frontend/components/User.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class Application extends React.Component {
4 | render() {
5 | return (
6 |
7 | email:{ this.props.user.email },
8 | id:{ this.props.user.id }
9 |
10 | );
11 | }
12 | }
--------------------------------------------------------------------------------
/src/frontend/containers/User.js:
--------------------------------------------------------------------------------
1 | import User from '../components/User';
2 | import Relay from 'react-relay';
3 |
4 | export default Relay.createContainer(User, {
5 | fragments: {
6 | user: () => Relay.QL`
7 | fragment on User {
8 | email,
9 | id
10 | }
11 | `
12 | }
13 | });
--------------------------------------------------------------------------------
/src/frontend/index.template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {%=o.htmlWebpackPlugin.options.title || 'Skele' %}
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/frontend/components/Application.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class Application extends React.Component {
4 | render() {
5 | return (
6 |
7 | text:{ this.props.example.text },
8 | version:{ this.props.example.version },
9 | id:{ this.props.example.id }
10 |
11 | );
12 | }
13 | }
--------------------------------------------------------------------------------
/src/frontend/containers/Application.js:
--------------------------------------------------------------------------------
1 | import Application from '../components/Application';
2 | import Relay from 'react-relay';
3 |
4 | export default Relay.createContainer(Application, {
5 | fragments: {
6 | example: () => Relay.QL`
7 | fragment on Example {
8 | text,
9 | version,
10 | id
11 | }
12 | `
13 | }
14 | });
--------------------------------------------------------------------------------
/src/frontend/roots/UserRoot.js:
--------------------------------------------------------------------------------
1 | import Relay from 'react-relay';
2 |
3 | export default class extends Relay.Route {
4 | static path = '/';
5 | static queries = {
6 | user: (Component) => Relay.QL`
7 | query {
8 | user {
9 | ${Component.getFragment('user')}
10 | }
11 | }
12 | `
13 | };
14 | static routeName = 'UserRoute';
15 | }
--------------------------------------------------------------------------------
/src/frontend/roots/ExampleRoot.js:
--------------------------------------------------------------------------------
1 | import Relay from 'react-relay';
2 |
3 | export default class extends Relay.Route {
4 | static path = '/';
5 | static queries = {
6 | example: (Component) => Relay.QL`
7 | query {
8 | example {
9 | ${Component.getFragment('example')}
10 | }
11 | }
12 | `
13 | };
14 | static routeName = 'ExampleRoute';
15 | }
--------------------------------------------------------------------------------
/src/frontend/components/Logout.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import auth from '../helpers/auth';
4 |
5 | export default React.createClass({
6 | displayName: 'Logout',
7 |
8 | propTypes: {
9 | },
10 |
11 | componentDidMount() {
12 | auth.logout();
13 | },
14 |
15 | render() {
16 | return (
17 | You are now logged out
18 | );
19 | },
20 | });
21 |
--------------------------------------------------------------------------------
/src/frontend/components/Dashboard.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import auth from '../helpers/auth';
4 |
5 | export default React.createClass({
6 | displayName: 'Dashboard',
7 |
8 | propTypes: {
9 | },
10 |
11 | render() {
12 | const token = auth.getToken();
13 |
14 | return (
15 |
16 |
Dashboard
17 |
You made it!
18 |
{token}
19 |
20 | );
21 | },
22 | });
23 |
--------------------------------------------------------------------------------
/src/frontend/index2.js:
--------------------------------------------------------------------------------
1 | /*global document*/
2 | import React from 'react';
3 | import ReactDOM from 'react-dom';
4 | import Relay from 'react-relay';
5 |
6 | // purposefully calling Relay 'routes' roots (as in Query Root)
7 | import UserRoot from './roots/UserRoot';
8 | import Application from './containers/User';
9 |
10 | class Root extends React.Component {
11 | render() {
12 | return (
13 |
16 | );
17 | }
18 | }
19 |
20 | ReactDOM.render(
21 | ,
22 | document.getElementById('container')
23 | );
--------------------------------------------------------------------------------
/src/server/server.js:
--------------------------------------------------------------------------------
1 | import express from 'express';
2 | import { Schema } from './data/schema';
3 | import graphQLHTTP from 'express-graphql';
4 | import { printSchema } from 'graphql/utilities/schemaPrinter';
5 | import path from 'path';
6 |
7 | const app = express();
8 | app.use(express.static(path.resolve(__dirname, 'public')));
9 | app.use('/schema',function(req,res,next) {
10 | res.set('Content-Type', 'text/plain');
11 | res.send(printSchema(Schema));
12 | });
13 | app.use('/', graphQLHTTP({ schema: Schema, pretty: true }));
14 | app.listen(8080, (err) => {
15 | if (err) {
16 | return console.error(err);
17 | }
18 | console.log('GraphQL Server is now running on localhost:8080');
19 | });
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "rules": {
4 | "quotes": [
5 | 2,
6 | "single"
7 | ],
8 | "linebreak-style": [
9 | 2,
10 | "unix"
11 | ],
12 | "no-unused-vars": [2, {
13 | "vars": "all",
14 | "args": "after-used",
15 | "argsIgnorePattern": "^_",
16 | "varsIgnorePattern": "^_"
17 | }],
18 | "semi": [
19 | 2,
20 | "always"
21 | ],
22 | "no-console" : 0
23 | },
24 | "env": {
25 | "es6": true,
26 | "node": true
27 | },
28 | "ecmaFeatures": {
29 | "classes": true,
30 | "modules": true,
31 | "jsx": true
32 | },
33 | "plugins": [
34 | "react"
35 | ],
36 | "extends": "airbnb"
37 | }
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # graphql-relay-authentication
2 | This project is a simple application to use as a starting point for an authentication based React/Relay application.
3 |
4 | This application has the following characteristics:
5 |
6 | - front end built with react and relay
7 | - back end will be a GraphQL server with no actual persistent layer (everything in memory)
8 | - application will have a login and register pages
9 | - a protected page which will be available only to authenticated user
10 |
11 | # Credits
12 |
13 | [fortruce/relay-skeleton](https://github.com/fortruce/relay-skeleton): skeleton for a React, Relay, GraphQL project. I expect
14 | to change the structure of the project over time but this skeleton is a very valuable starting point.
15 |
16 | [Keep a CHANGELOG](http://keepachangelog.com/): very interesting initiative by [Olivier Lacan](http://olivierlacan.com/) to formalize
17 | the way you should write your CHANGELOG.md file. Worth giving it a try.
--------------------------------------------------------------------------------
/src/frontend/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from 'react-dom';
3 | import { Router, Route } from 'react-router';
4 |
5 | // componets for the application
6 | import App from './components/App';
7 | import Login from './components/Login';
8 | import Logout from './components/Logout';
9 | import Dashboard from './components/Dashboard';
10 | import About from './components/About';
11 |
12 | import auth from './helpers/auth';
13 |
14 | function requireAuth(nextState, replaceState) {
15 | if (!auth.loggedIn()) {
16 | replaceState({ nextPathname: nextState.location.pathname }, '/login');
17 | }
18 | }
19 |
20 | render((
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | ), document.getElementById('container'));
30 |
31 |
--------------------------------------------------------------------------------
/src/frontend/components/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router';
3 |
4 | import auth from '../helpers/auth';
5 |
6 | export default React.createClass({
7 | displayName: 'App',
8 |
9 | propTypes: {
10 | children: React.PropTypes.element,
11 | },
12 |
13 | getInitialState() {
14 | return {
15 | loggedIn: auth.loggedIn(),
16 | };
17 | },
18 |
19 | componentWillMount() {
20 | auth.onChange = this.updateAuth;
21 | auth.login();
22 | },
23 |
24 | updateAuth(loggedIn) {
25 | this.setState({
26 | loggedIn: loggedIn,
27 | });
28 | },
29 |
30 | render() {
31 | return (
32 |
33 |
34 | -
35 | {this.state.loggedIn ? (
36 | Log out
37 | ) : (
38 | Sign in
39 | )}
40 |
41 | - About
42 | - Dashboard (authenticated)
43 |
44 | {this.props.children}
45 |
46 | );
47 | },
48 | });
49 |
--------------------------------------------------------------------------------
/src/frontend/helpers/auth.js:
--------------------------------------------------------------------------------
1 | function pretendRequest(email, pass, cb) {
2 | setTimeout(() => {
3 | if (email === 'joe@example.com' && pass === 'password1') {
4 | cb({
5 | authenticated: true,
6 | token: Math.random().toString(36).substring(7),
7 | });
8 | } else {
9 | cb({ authenticated: false });
10 | }
11 | }, 0);
12 | }
13 |
14 | export default {
15 | login(email, pass, _cb) {
16 | const cb = arguments[arguments.length - 1];
17 | if (localStorage.token) {
18 | if (cb) {
19 | cb(true);
20 | }
21 | this.onChange(true);
22 | return;
23 | }
24 | pretendRequest(email, pass, (res) => {
25 | if (res.authenticated) {
26 | localStorage.token = res.token;
27 | if (cb) {
28 | cb(true);
29 | }
30 | this.onChange(true);
31 | } else {
32 | if (cb) {
33 | cb(false);
34 | }
35 | this.onChange(false);
36 | }
37 | });
38 | },
39 |
40 | getToken() {
41 | return localStorage.token;
42 | },
43 |
44 | logout(cb) {
45 | delete localStorage.token;
46 | if (cb) {
47 | cb();
48 | }
49 | this.onChange(false);
50 | },
51 |
52 | loggedIn() {
53 | return !!localStorage.token;
54 | },
55 |
56 | onChange() {},
57 | };
58 |
59 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | All notable changes to this project will be documented in this file.
3 |
4 | ## [Unreleased][unreleased]
5 | ### Added
6 | - add eslint support
7 | - add [Airbnb javascript coding](https://github.com/airbnb/javascript) style using [eslint](https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb)
8 | - use the `auth` sample code from [Recat Royer example](https://github.com/rackt/react-router/tree/master/examples/auth-flow) as a staring point for our sample
9 |
10 | ## 0.0.1 - 2015-10-05
11 | ### Added
12 | - Add the `/schema` middleware to get the GraphQL schema
13 | - Add the GraphiQL web interface in the `ql` subdirectory of the server
14 | - Add gulp tasks to clean and to prepare the build directory
15 |
16 | ### Changed
17 | - Remove webpack to generate the server code and replace with babel to generate es5 code
18 | - Rename gulp tasks to follow a naming convention "system:function"
19 |
20 | ## Initial import in master - 2015-10-04
21 | ### Added
22 | - Skeleton project using the [fortruce/relay-skeleton](https://github.com/fortruce/relay-skeleton) project
23 | - README.md file to describe the project and prepare a credit page
24 | - prepare CHANGELOG.md file following the format described [here](http://keepachangelog.com/)
25 | - .gitignore file for this file organization
26 |
27 | [unreleased]: https://github.com/pcarion/graphql-relay-authentication/compare/rel/0.0.1...develop
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | /*
2 | TODO:
3 | * add a production flag that disables debug/sourcemaps and minifies
4 | */
5 |
6 | var webpack = require('webpack');
7 | var path = require('path');
8 | var assign = require('object-assign');
9 | var HtmlWebpackPlugin = require('html-webpack-plugin');
10 |
11 | var defaultConfig = {
12 | devtool: 'sourcemap'
13 | };
14 |
15 | var frontendConfig = assign({}, defaultConfig, {
16 | entry: [
17 | 'webpack-dev-server/client?http://localhost:3000',
18 | 'webpack/hot/only-dev-server',
19 | './src/frontend/index.js'
20 | ],
21 |
22 | output: {
23 | filename: 'bundle.js',
24 | path: path.join(__dirname, 'build', 'public')
25 | },
26 |
27 | plugins: [
28 | new webpack.HotModuleReplacementPlugin(),
29 | new webpack.NoErrorsPlugin(),
30 | new HtmlWebpackPlugin({
31 | title: 'Skele',
32 | filename: 'index.html',
33 | template: 'src/frontend/index.template.html',
34 | inject: true
35 | })
36 | ],
37 |
38 | module: {
39 | loaders: [
40 | {
41 | test: /\.js$/,
42 | include: path.join(__dirname, 'src', 'frontend'),
43 | loaders: ['react-hot', 'babel?stage=0&plugins[]=' + path.join(__dirname, 'relayPlugin')]
44 | },
45 | {
46 | test: /\.scss$/,
47 | include: path.join(__dirname, 'src', 'frontend', 'scss'),
48 | loaders: ['style', 'css', 'sass']
49 | }
50 | ]
51 | }
52 | });
53 |
54 | module.exports = [frontendConfig ];
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015, Pierre Carion
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | * Neither the name of graphql-relay-authentication nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 |
--------------------------------------------------------------------------------
/src/frontend/components/Login.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {findDOMNode} from 'react-dom';
3 | import { History } from 'react-router';
4 |
5 | import auth from '../helpers/auth';
6 |
7 | export default React.createClass({
8 | displayName: 'Login',
9 |
10 | propTypes: {
11 | location: React.PropTypes.object.isRequired,
12 | },
13 |
14 | mixins: [History],
15 |
16 | getInitialState() {
17 | return {
18 | error: false,
19 | };
20 | },
21 |
22 | handleSubmit(event) {
23 | event.preventDefault();
24 |
25 | const {location} = this.props;
26 | const email = findDOMNode(this.refs.email).value;
27 | const pass = findDOMNode(this.refs.pass).value;
28 |
29 | auth.login(email, pass, (loggedIn) => {
30 | if (!loggedIn) {
31 | return this.setState({
32 | error: true,
33 | });
34 | }
35 |
36 | if (location.state && location.state.nextPathname) {
37 | this.history.replaceState(null, location.state.nextPathname);
38 | } else {
39 | this.history.replaceState(null, '/about');
40 | }
41 | });
42 | },
43 |
44 | render() {
45 | return (
46 |
54 | );
55 | },
56 | });
57 |
58 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "relay-skeleton",
3 | "version": "0.0.1",
4 | "description": "A minimal React, Relay, GraphQL skeleton.",
5 | "main": "gulpfile.babel.js",
6 | "scripts": {
7 | "start": "gulp"
8 | },
9 | "dependencies": {
10 | "express-graphql": "^0.3.0",
11 | "graphql": "^0.4.2",
12 | "graphql-relay": "^0.3.0",
13 | "history": "^1.12.4",
14 | "node-uuid": "^1.4.3",
15 | "react": "^0.14.0-beta3",
16 | "react-dom": "^0.14.0-beta3",
17 | "react-relay": "^0.1.1",
18 | "react-router": "^1.0.0-beta3"
19 | },
20 | "devDependencies": {
21 | "babel": "^5.8.21",
22 | "babel-core": "^5.8.20",
23 | "babel-eslint": "^4.1.3",
24 | "babel-loader": "^5.3.2",
25 | "babel-relay-plugin": "^0.1.2",
26 | "css-loader": "^0.15.6",
27 | "del": "^2.0.2",
28 | "eslint": "^1.6.0",
29 | "eslint-config-airbnb": "^0.1.0",
30 | "eslint-plugin-react": "^3.5.1",
31 | "express": "^4.13.3",
32 | "gulp": "^3.9.0",
33 | "gulp-babel": "^5.2.1",
34 | "gulp-concat": "^2.6.0",
35 | "gulp-sourcemaps": "^1.6.0",
36 | "html-webpack-plugin": "^1.6.0",
37 | "nodemon": "^1.4.0",
38 | "object-assign": "^3.0.0",
39 | "react-hot-loader": "^1.2.8",
40 | "sass-loader": "^2.0.0",
41 | "source-map-support": "^0.3.2",
42 | "style-loader": "^0.12.3",
43 | "webpack": "^1.10.5",
44 | "webpack-dev-server": "^1.10.1"
45 | },
46 | "repository": {
47 | "type": "git",
48 | "url": "https://github.com/fortruce/relay-skeleton.git"
49 | },
50 | "keywords": [
51 | "react",
52 | "relay",
53 | "skeleton",
54 | "webpack"
55 | ],
56 | "author": "fortruce",
57 | "license": "ISC",
58 | "bugs": {
59 | "url": "https://github.com/fortruce/relay-skeleton/issues"
60 | },
61 | "homepage": "https://github.com/fortruce/relay-skeleton"
62 | }
63 |
--------------------------------------------------------------------------------
/src/server/data/schema.js:
--------------------------------------------------------------------------------
1 | import {
2 | GraphQLObjectType,
3 | GraphQLInt,
4 | GraphQLString,
5 | GraphQLSchema
6 | } from 'graphql';
7 |
8 | import {
9 | fromGlobalId,
10 | globalIdField,
11 | nodeDefinitions
12 | } from 'graphql-relay';
13 |
14 | import uuid from 'node-uuid';
15 |
16 | class User {
17 | constructor(email, password) {
18 | this._id = uuid.v4();
19 | this._email = email;
20 | this._password = password;
21 | }
22 |
23 | get id() {
24 | return this._id;
25 | }
26 |
27 | get email() {
28 | return this._email;
29 | }
30 | }
31 |
32 | class Example {
33 | constructor(text, version) {
34 | this._id = uuid.v4();
35 | this._text = text;
36 | this._version = version;
37 | }
38 |
39 | get id() {
40 | return this._id;
41 | }
42 |
43 | get text() {
44 | return this._text;
45 | }
46 |
47 | get version() {
48 | return this._version;
49 | }
50 | }
51 |
52 |
53 | const example = new Example('Hello World!',3);
54 | const user = new User('pcarion@gmail.com', 'xyz123');
55 |
56 | // let usersDirectory = new Map();
57 |
58 | // function getUser(id) {
59 | // return usersDirectory.get(id);
60 | // }
61 |
62 | // function createUser(email, password) {
63 | // return new User(email, password);
64 |
65 | // }
66 |
67 | /**
68 | * The first argument defines the way to resolve an ID to its object.
69 | * The second argument defines the way to resolve a node object to its GraphQL type.
70 | */
71 | var { nodeInterface, nodeField } = nodeDefinitions(
72 | (globalId) => {
73 | let { _id, type } = fromGlobalId(globalId);
74 | if (type === 'Example') {
75 | return example;
76 | } else if (type === 'User') {
77 | return user;
78 | }
79 | return null;
80 | },
81 | (obj) => {
82 | if (obj instanceof User) {
83 | return userType;
84 | } else if (obj instanceof Example) {
85 | return exampleType;
86 | }
87 | return null;
88 | }
89 | );
90 |
91 | var userType = new GraphQLObjectType({
92 | name: 'User',
93 | fields: () => ({
94 | id: globalIdField('User'),
95 | email: {
96 | type: GraphQLString,
97 | description: 'email of the user'
98 | },
99 | password: {
100 | type: GraphQLString,
101 | description: 'encoded password'
102 | }
103 | }),
104 | interfaces: [ nodeInterface ]
105 | });
106 |
107 | var exampleType = new GraphQLObjectType({
108 | name: 'Example',
109 | fields: () => ({
110 | id: globalIdField('Example'),
111 | text: {
112 | type: GraphQLString,
113 | description: 'Hello World'
114 | },
115 | version: {
116 | type: GraphQLInt,
117 | description: 'version'
118 | }
119 | }),
120 | interfaces: [ nodeInterface ]
121 | });
122 |
123 | var queryType = new GraphQLObjectType({
124 | name: 'Query',
125 | fields: () => ({
126 | node: nodeField,
127 | example: {
128 | type: exampleType,
129 | resolve: () => example
130 | },
131 | user: {
132 | type: userType,
133 | resolve: () => user
134 | }
135 | })
136 | });
137 |
138 | export var Schema = new GraphQLSchema({
139 | query: queryType
140 | });
--------------------------------------------------------------------------------
/src/public/ql/index.html:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Loading...
19 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/gulpfile.babel.js:
--------------------------------------------------------------------------------
1 | import gulp from 'gulp';
2 | import sourcemaps from 'gulp-sourcemaps';
3 | import del from 'del';
4 | import babel from 'gulp-babel';
5 | import concat from 'gulp-concat';
6 |
7 | import webpack from 'webpack';
8 | import WebpackDevServer from 'webpack-dev-server';
9 | import nodemon from 'nodemon';
10 | import path from 'path';
11 | import { Schema } from './src/server/data/schema';
12 | import { introspectionQuery } from 'graphql/utilities';
13 | import { graphql } from 'graphql';
14 | import fs from 'fs';
15 |
16 | import configs from './webpack.config';
17 | const [ frontendConfig ] = configs;
18 |
19 | let compiler;
20 |
21 | // trigger a manual recompilation of webpack(frontendConfig);
22 | function recompile() {
23 | if (!compiler)
24 | return null;
25 | return new Promise((resolve, reject) => {
26 | compiler.run((err, stats) => {
27 | if (err)
28 | reject(err);
29 | console.log('[webpackDevServer]: recompiled');
30 | resolve();
31 | });
32 | });
33 | }
34 |
35 | // run the webpack dev server
36 | // must generate the schema.json first as compiler relies on it for babel-relay-plugin
37 | gulp.task('frontend:webpack', ['schema:generate'], () => {
38 | compiler = webpack(frontendConfig);
39 | let server = new WebpackDevServer(compiler, {
40 | contentBase: path.join(__dirname, 'build', 'public'),
41 | hot: true,
42 | noInfo: true,
43 | stats: { colors: true },
44 | historyApiFallback: true,
45 | proxy: {
46 | '/graphql': 'http://localhost:8080'
47 | }
48 | });
49 | server.listen(3000, 'localhost', (err, result) => {
50 | if (err)
51 | return console.error(err);
52 | console.log('[webpackDevServer]: listening on localhost:3000');
53 | });
54 | });
55 |
56 | // Regenerate the graphql schema and recompile the frontend code that relies on schema.json
57 | gulp.task('schema:generate', () => {
58 | return graphql(Schema, introspectionQuery)
59 | .then(result => {
60 | if (result.errors)
61 | return console.error('[schema]: ERROR --', JSON.stringify(result.errors, null, 2));
62 | fs.writeFileSync(
63 | path.join(__dirname, './src/server/data/schema.json'),
64 | JSON.stringify(result, null, 2)
65 | );
66 | return compiler ? recompile() : null;
67 | });
68 | });
69 |
70 | // generate the server using babel
71 | gulp.task('server:babel', function () {
72 | return gulp.src("src/server/**/*.js")
73 | .pipe(sourcemaps.init())
74 | .pipe(babel())
75 | .pipe(sourcemaps.write("."))
76 | .pipe(gulp.dest("build"));
77 | });
78 |
79 | // recompile the schema whenever .js files in data are updated
80 | gulp.task('schema:watch', () => {
81 | gulp.watch(path.join(__dirname, './src/server/data', '**/*.js'), ['schema:generate','server:babel']);
82 | });
83 |
84 | // copy the public directory to the build folder
85 | gulp.task('public:copy', function () {
86 | return gulp
87 | .src('src/public/**/*.*', {base: './src'})
88 | .pipe(gulp.dest('build'));
89 | })
90 |
91 | gulp.task('public:clean', function () {
92 | return del([
93 | 'build'
94 | ]);
95 | });
96 |
97 | gulp.task('server:start', ['server:babel', 'public:copy', 'schema:watch'], () => {
98 | nodemon({
99 | execMap: {
100 | js: 'node'
101 | },
102 | script: path.join(__dirname, 'build', 'server.js'),
103 | watch: ['build/'],
104 | ext: 'js'
105 | }).on('restart', () => {
106 | console.log('[nodemon]: restart');
107 | });
108 | });
109 |
110 | gulp.task('frontend', ['frontend:webpack']);
111 | gulp.task('server', ['server:start']);
112 |
113 | gulp.task('default', ['frontend', 'server']);
114 |
115 |
--------------------------------------------------------------------------------
/src/public/ql/graphiql.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | height: 100%;
3 | margin: 0;
4 | overflow: hidden;
5 | width: 100%;
6 | }
7 |
8 | #graphiql-container {
9 | color: #141823;
10 | width: 100%;
11 | display: -webkit-flex;
12 | display: flex;
13 | -webkit-flex-direction: row;
14 | flex-direction: row;
15 | height: 100%;
16 | font-family: helvetica, arial, sans-serif;
17 | font-size: 14px;
18 | }
19 |
20 | #graphiql-container .editorWrap {
21 | display: -webkit-flex;
22 | display: flex;
23 | -webkit-flex-direction: column;
24 | flex-direction: column;
25 | -webkit-flex: 1;
26 | flex: 1;
27 | }
28 |
29 | #graphiql-container .title {
30 | font-size: 18px;
31 | }
32 |
33 | #graphiql-container .title em {
34 | font-family: georgia;
35 | font-size: 19px;
36 | }
37 |
38 | #graphiql-container .topBarWrap {
39 | display: -webkit-flex;
40 | display: flex;
41 | -webkit-flex-direction: row;
42 | flex-direction: row;
43 | }
44 |
45 | #graphiql-container .topBar {
46 | background: -webkit-linear-gradient(#f7f7f7, #e2e2e2);
47 | background: linear-gradient(#f7f7f7, #e2e2e2);
48 | border-bottom: solid 1px #d0d0d0;
49 | cursor: default;
50 | height: 34px;
51 | padding: 7px 14px 6px;
52 | -webkit-user-select: none;
53 | user-select: none;
54 | display: -webkit-flex;
55 | display: flex;
56 | -webkit-flex-direction: row;
57 | flex-direction: row;
58 | -webkit-flex: 1;
59 | flex: 1;
60 | -webkit-align-items: center;
61 | align-items: center;
62 | }
63 |
64 | #graphiql-container .docExplorerShow {
65 | background: -webkit-linear-gradient(#f7f7f7, #e2e2e2);
66 | background: linear-gradient(#f7f7f7, #e2e2e2);
67 | border: none;
68 | border-bottom: solid 1px #d0d0d0;
69 | border-left: solid 1px rgba(0, 0, 0, 0.2);
70 | color: #3B5998;
71 | cursor: pointer;
72 | font-size: 14px;
73 | outline: 0;
74 | padding: 2px 20px 0 18px;
75 | }
76 |
77 | #graphiql-container .docExplorerShow:before {
78 | border-left: 2px solid #3B5998;
79 | border-top: 2px solid #3B5998;
80 | content: '';
81 | display: inline-block;
82 | height: 9px;
83 | margin: 0 3px -1px 0;
84 | position: relative;
85 | width: 9px;
86 | -webkit-transform: rotate(-45deg);
87 | transform: rotate(-45deg);
88 | }
89 |
90 | #graphiql-container .editorBar {
91 | display: -webkit-flex;
92 | display: flex;
93 | -webkit-flex-direction: row;
94 | flex-direction: row;
95 | -webkit-flex: 1;
96 | flex: 1;
97 | }
98 |
99 | #graphiql-container .queryWrap {
100 | display: -webkit-flex;
101 | display: flex;
102 | -webkit-flex-direction: column;
103 | flex-direction: column;
104 | -webkit-flex: 1;
105 | flex: 1;
106 | }
107 |
108 | #graphiql-container .resultWrap {
109 | display: -webkit-flex;
110 | display: flex;
111 | -webkit-flex-direction: column;
112 | flex-direction: column;
113 | -webkit-flex: 1;
114 | flex: 1;
115 | border-left: solid 1px #e0e0e0;
116 | }
117 |
118 | #graphiql-container .docExplorerWrap {
119 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.15);
120 | z-index: 3;
121 | position: relative;
122 | background: white;
123 | }
124 |
125 | #graphiql-container .docExplorerResizer {
126 | cursor: col-resize;
127 | height: 100%;
128 | left: -5px;
129 | position: absolute;
130 | top: 0;
131 | width: 10px;
132 | z-index: 10;
133 | }
134 |
135 | #graphiql-container .docExplorerHide {
136 | cursor: pointer;
137 | font-size: 18px;
138 | margin: -7px -8px -6px 0;
139 | padding: 18px 16px 15px 12px;
140 | }
141 |
142 | #graphiql-container .query-editor {
143 | -webkit-flex: 1;
144 | flex: 1;
145 | position: relative;
146 | }
147 |
148 | #graphiql-container .variable-editor {
149 | height: 30px;
150 | display: -webkit-flex;
151 | display: flex;
152 | -webkit-flex-direction: column;
153 | flex-direction: column;
154 | position: relative;
155 | }
156 |
157 | #graphiql-container .variable-editor-title {
158 | background: #eeeeee;
159 | border-bottom: solid 1px #d6d6d6;
160 | border-top: solid 1px #e0e0e0;
161 | color: #777;
162 | font-variant: small-caps;
163 | font-weight: bold;
164 | letter-spacing: 1px;
165 | line-height: 14px;
166 | padding: 6px 0 8px 43px;
167 | text-transform: lowercase;
168 | -webkit-user-select: none;
169 | user-select: none;
170 | }
171 |
172 | #graphiql-container .codemirrorWrap {
173 | -webkit-flex: 1;
174 | flex: 1;
175 | position: relative;
176 | }
177 |
178 | #graphiql-container .result-window {
179 | -webkit-flex: 1;
180 | flex: 1;
181 | position: relative;
182 | }
183 |
184 | #graphiql-container .footer {
185 | background: #f6f7f8;
186 | border-left: solid 1px #e0e0e0;
187 | border-top: solid 1px #e0e0e0;
188 | margin-left: 12px;
189 | position: relative;
190 | }
191 |
192 | #graphiql-container .footer:before {
193 | background: #eeeeee;
194 | bottom: 0;
195 | content: " ";
196 | left: -13px;
197 | position: absolute;
198 | top: -1px;
199 | width: 12px;
200 | }
201 |
202 | #graphiql-container .result-window .CodeMirror {
203 | background: #f6f7f8;
204 | }
205 |
206 | #graphiql-container .result-window .CodeMirror-gutters {
207 | background-color: #eeeeee;
208 | border-color: #e0e0e0;
209 | cursor: col-resize;
210 | }
211 |
212 | #graphiql-container .result-window .CodeMirror-foldgutter,
213 | #graphiql-container .result-window .CodeMirror-foldgutter-open:after,
214 | #graphiql-container .result-window .CodeMirror-foldgutter-folded:after {
215 | padding-left: 3px;
216 | }
217 |
218 | #graphiql-container .execute-button {
219 | background: -webkit-linear-gradient(#fdfdfd, #d2d3d6);
220 | background: linear-gradient(#fdfdfd, #d2d3d6);
221 | border: solid 1px rgba(0,0,0,0.25);
222 | border-radius: 17px;
223 | box-shadow: 0 1px 0 #fff;
224 | cursor: pointer;
225 | fill: #444;
226 | height: 34px;
227 | margin: 0 14px 0 28px;
228 | padding: 0;
229 | width: 34px;
230 | }
231 |
232 | #graphiql-container .execute-button:active {
233 | background: -webkit-linear-gradient(#e6e6e6, #c0c0c0);
234 | background: linear-gradient(#e6e6e6, #c0c0c0);
235 | box-shadow:
236 | 0 1px 0 #fff,
237 | inset 0 0 2px rgba(0, 0, 0, 0.3),
238 | inset 0 0 6px rgba(0, 0, 0, 0.2);
239 | }
240 |
241 | #graphiql-container .execute-button:focus {
242 | outline: 0;
243 | }
244 |
245 | #graphiql-container .CodeMirror-scroll {
246 | -webkit-overflow-scrolling: touch;
247 | }
248 |
249 | #graphiql-container .CodeMirror {
250 | position: absolute;
251 | top: 0;
252 | left: 0;
253 | height: 100%;
254 | width: 100%;
255 | font-size: 13px;
256 | font-family: 'Consolas', 'Inconsolata', 'Droid Sans Mono', 'Monaco', monospace;
257 | color: #141823;
258 | }
259 |
260 | #graphiql-container .CodeMirror-lines {
261 | padding: 20px 0;
262 | }
263 |
264 | .CodeMirror-hint-information .content {
265 | -webkit-box-orient: vertical;
266 | color: #141823;
267 | display: -webkit-box;
268 | font-family: helvetica, arial, sans-serif;
269 | font-size: 13px;
270 | -webkit-line-clamp: 3;
271 | line-height: 16px;
272 | max-height: 48px;
273 | overflow: hidden;
274 | text-overflow: -o-ellipsis-lastline;
275 | }
276 |
277 | .CodeMirror-hint-information .content p:first-child {
278 | margin-top: 0;
279 | }
280 |
281 | .CodeMirror-hint-information .content p:last-child {
282 | margin-bottom: 0;
283 | }
284 |
285 | .CodeMirror-hint-information .infoType {
286 | color: #30a;
287 | margin-right: 0.5em;
288 | display: inline;
289 | cursor: pointer;
290 | }
291 |
292 | .autoInsertedLeaf.cm-property {
293 | padding: 2px 4px 1px;
294 | margin: -2px -4px -1px;
295 | border-radius: 2px;
296 | border-bottom: solid 2px rgba(255, 255, 255, 0);
297 | -webkit-animation-duration: 6s;
298 | -moz-animation-duration: 6s;
299 | animation-duration: 6s;
300 | -webkit-animation-name: insertionFade;
301 | -moz-animation-name: insertionFade;
302 | animation-name: insertionFade;
303 | }
304 |
305 | @-moz-keyframes insertionFade {
306 | from, to {
307 | background: rgba(255, 255, 255, 0);
308 | border-color: rgba(255, 255, 255, 0);
309 | }
310 |
311 | 15%, 85% {
312 | background: #fbffc9;
313 | border-color: #f0f3c0;
314 | }
315 | }
316 |
317 | @-webkit-keyframes insertionFade {
318 | from, to {
319 | background: rgba(255, 255, 255, 0);
320 | border-color: rgba(255, 255, 255, 0);
321 | }
322 |
323 | 15%, 85% {
324 | background: #fbffc9;
325 | border-color: #f0f3c0;
326 | }
327 | }
328 |
329 | @keyframes insertionFade {
330 | from, to {
331 | background: rgba(255, 255, 255, 0);
332 | border-color: rgba(255, 255, 255, 0);
333 | }
334 |
335 | 15%, 85% {
336 | background: #fbffc9;
337 | border-color: #f0f3c0;
338 | }
339 | }
340 |
341 | div.CodeMirror-lint-tooltip {
342 | background-color: white;
343 | color: #141823;
344 | border: 0;
345 | border-radius: 2px;
346 | -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
347 | -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
348 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
349 | font-family: helvetica, arial, sans-serif;
350 | font-size: 13px;
351 | line-height: 16px;
352 | padding: 6px 10px;
353 | opacity: 0;
354 | transition: opacity 0.15s;
355 | -moz-transition: opacity 0.15s;
356 | -webkit-transition: opacity 0.15s;
357 | -o-transition: opacity 0.15s;
358 | -ms-transition: opacity 0.15s;
359 | }
360 |
361 | div.CodeMirror-lint-message-error, div.CodeMirror-lint-message-warning {
362 | padding-left: 23px;
363 | }
364 |
365 | /* COLORS */
366 |
367 | #graphiql-container .CodeMirror-foldmarker {
368 | border-radius: 4px;
369 | background: #08f;
370 | background: -webkit-linear-gradient(#43A8FF, #0F83E8);
371 | background: linear-gradient(#43A8FF, #0F83E8);
372 |
373 | color: white;
374 | -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), inset 0 0 0 1px rgba(0, 0, 0, 0.1);
375 | -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), inset 0 0 0 1px rgba(0, 0, 0, 0.1);
376 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), inset 0 0 0 1px rgba(0, 0, 0, 0.1);
377 | font-family: arial;
378 | line-height: 0;
379 | padding: 0px 4px 1px;
380 | font-size: 12px;
381 | margin: 0 3px;
382 | text-shadow: 0 -1px rgba(0, 0, 0, 0.1);
383 | }
384 |
385 | #graphiql-container div.CodeMirror span.CodeMirror-matchingbracket {
386 | color: #555;
387 | text-decoration: underline;
388 | }
389 |
390 | #graphiql-container div.CodeMirror span.CodeMirror-nonmatchingbracket {
391 | color: #f00;
392 | }
393 |
394 | /* Comment */
395 | .cm-comment {
396 | color: #999;
397 | }
398 |
399 | /* Punctuation */
400 | .cm-punctuation {
401 | color: #555;
402 | }
403 |
404 | /* Keyword */
405 | .cm-keyword {
406 | color: #B11A04;
407 | }
408 |
409 | /* OperationName, FragmentName */
410 | .cm-def {
411 | color: #D2054E;
412 | }
413 |
414 | /* FieldName */
415 | .cm-property {
416 | color: #1F61A0;
417 | }
418 |
419 | /* FieldAlias */
420 | .cm-qualifier {
421 | color: #1C92A9;
422 | }
423 |
424 | /* ArgumentName and ObjectFieldName */
425 | .cm-attribute {
426 | color: #8B2BB9;
427 | }
428 |
429 | /* Number */
430 | .cm-number {
431 | color: #2882F9;
432 | }
433 |
434 | /* String */
435 | .cm-string {
436 | color: #D64292;
437 | }
438 |
439 | /* Boolean */
440 | .cm-builtin {
441 | color: #D47509;
442 | }
443 |
444 | /* EnumValue */
445 | .cm-string-2 {
446 | color: #0B7FC7;
447 | }
448 |
449 | /* Variable */
450 | .cm-variable {
451 | color: #397D13;
452 | }
453 |
454 | /* Directive */
455 | .cm-meta {
456 | color: #B33086;
457 | }
458 |
459 | /* Type */
460 | .cm-atom {
461 | color: #CA9800;
462 | }
463 | /* BASICS */
464 |
465 | .CodeMirror {
466 | /* Set height, width, borders, and global font properties here */
467 | font-family: monospace;
468 | height: 300px;
469 | color: black;
470 | }
471 |
472 | /* PADDING */
473 |
474 | .CodeMirror-lines {
475 | padding: 4px 0; /* Vertical padding around content */
476 | }
477 | .CodeMirror pre {
478 | padding: 0 4px; /* Horizontal padding of content */
479 | }
480 |
481 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
482 | background-color: white; /* The little square between H and V scrollbars */
483 | }
484 |
485 | /* GUTTER */
486 |
487 | .CodeMirror-gutters {
488 | border-right: 1px solid #ddd;
489 | background-color: #f7f7f7;
490 | white-space: nowrap;
491 | }
492 | .CodeMirror-linenumbers {}
493 | .CodeMirror-linenumber {
494 | padding: 0 3px 0 5px;
495 | min-width: 20px;
496 | text-align: right;
497 | color: #999;
498 | white-space: nowrap;
499 | }
500 |
501 | .CodeMirror-guttermarker { color: black; }
502 | .CodeMirror-guttermarker-subtle { color: #999; }
503 |
504 | /* CURSOR */
505 |
506 | .CodeMirror div.CodeMirror-cursor {
507 | border-left: 1px solid black;
508 | }
509 | /* Shown when moving in bi-directional text */
510 | .CodeMirror div.CodeMirror-secondarycursor {
511 | border-left: 1px solid silver;
512 | }
513 | .CodeMirror.cm-fat-cursor div.CodeMirror-cursor {
514 | width: auto;
515 | border: 0;
516 | background: #7e7;
517 | }
518 | .CodeMirror.cm-fat-cursor div.CodeMirror-cursors {
519 | z-index: 1;
520 | }
521 |
522 | .cm-animate-fat-cursor {
523 | width: auto;
524 | border: 0;
525 | -webkit-animation: blink 1.06s steps(1) infinite;
526 | -moz-animation: blink 1.06s steps(1) infinite;
527 | animation: blink 1.06s steps(1) infinite;
528 | }
529 | @-moz-keyframes blink {
530 | 0% { background: #7e7; }
531 | 50% { background: none; }
532 | 100% { background: #7e7; }
533 | }
534 | @-webkit-keyframes blink {
535 | 0% { background: #7e7; }
536 | 50% { background: none; }
537 | 100% { background: #7e7; }
538 | }
539 | @keyframes blink {
540 | 0% { background: #7e7; }
541 | 50% { background: none; }
542 | 100% { background: #7e7; }
543 | }
544 |
545 | /* Can style cursor different in overwrite (non-insert) mode */
546 | div.CodeMirror-overwrite div.CodeMirror-cursor {}
547 |
548 | .cm-tab { display: inline-block; text-decoration: inherit; }
549 |
550 | .CodeMirror-ruler {
551 | border-left: 1px solid #ccc;
552 | position: absolute;
553 | }
554 |
555 | /* DEFAULT THEME */
556 |
557 | .cm-s-default .cm-keyword {color: #708;}
558 | .cm-s-default .cm-atom {color: #219;}
559 | .cm-s-default .cm-number {color: #164;}
560 | .cm-s-default .cm-def {color: #00f;}
561 | .cm-s-default .cm-variable,
562 | .cm-s-default .cm-punctuation,
563 | .cm-s-default .cm-property,
564 | .cm-s-default .cm-operator {}
565 | .cm-s-default .cm-variable-2 {color: #05a;}
566 | .cm-s-default .cm-variable-3 {color: #085;}
567 | .cm-s-default .cm-comment {color: #a50;}
568 | .cm-s-default .cm-string {color: #a11;}
569 | .cm-s-default .cm-string-2 {color: #f50;}
570 | .cm-s-default .cm-meta {color: #555;}
571 | .cm-s-default .cm-qualifier {color: #555;}
572 | .cm-s-default .cm-builtin {color: #30a;}
573 | .cm-s-default .cm-bracket {color: #997;}
574 | .cm-s-default .cm-tag {color: #170;}
575 | .cm-s-default .cm-attribute {color: #00c;}
576 | .cm-s-default .cm-header {color: blue;}
577 | .cm-s-default .cm-quote {color: #090;}
578 | .cm-s-default .cm-hr {color: #999;}
579 | .cm-s-default .cm-link {color: #00c;}
580 |
581 | .cm-negative {color: #d44;}
582 | .cm-positive {color: #292;}
583 | .cm-header, .cm-strong {font-weight: bold;}
584 | .cm-em {font-style: italic;}
585 | .cm-link {text-decoration: underline;}
586 | .cm-strikethrough {text-decoration: line-through;}
587 |
588 | .cm-s-default .cm-error {color: #f00;}
589 | .cm-invalidchar {color: #f00;}
590 |
591 | .CodeMirror-composing { border-bottom: 2px solid; }
592 |
593 | /* Default styles for common addons */
594 |
595 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
596 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
597 | .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
598 | .CodeMirror-activeline-background {background: #e8f2ff;}
599 |
600 | /* STOP */
601 |
602 | /* The rest of this file contains styles related to the mechanics of
603 | the editor. You probably shouldn't touch them. */
604 |
605 | .CodeMirror {
606 | position: relative;
607 | overflow: hidden;
608 | background: white;
609 | }
610 |
611 | .CodeMirror-scroll {
612 | overflow: scroll !important; /* Things will break if this is overridden */
613 | /* 30px is the magic margin used to hide the element's real scrollbars */
614 | /* See overflow: hidden in .CodeMirror */
615 | margin-bottom: -30px; margin-right: -30px;
616 | padding-bottom: 30px;
617 | height: 100%;
618 | outline: none; /* Prevent dragging from highlighting the element */
619 | position: relative;
620 | }
621 | .CodeMirror-sizer {
622 | position: relative;
623 | border-right: 30px solid transparent;
624 | }
625 |
626 | /* The fake, visible scrollbars. Used to force redraw during scrolling
627 | before actuall scrolling happens, thus preventing shaking and
628 | flickering artifacts. */
629 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
630 | position: absolute;
631 | z-index: 6;
632 | display: none;
633 | }
634 | .CodeMirror-vscrollbar {
635 | right: 0; top: 0;
636 | overflow-x: hidden;
637 | overflow-y: scroll;
638 | }
639 | .CodeMirror-hscrollbar {
640 | bottom: 0; left: 0;
641 | overflow-y: hidden;
642 | overflow-x: scroll;
643 | }
644 | .CodeMirror-scrollbar-filler {
645 | right: 0; bottom: 0;
646 | }
647 | .CodeMirror-gutter-filler {
648 | left: 0; bottom: 0;
649 | }
650 |
651 | .CodeMirror-gutters {
652 | position: absolute; left: 0; top: 0;
653 | z-index: 3;
654 | }
655 | .CodeMirror-gutter {
656 | white-space: normal;
657 | height: 100%;
658 | display: inline-block;
659 | margin-bottom: -30px;
660 | /* Hack to make IE7 behave */
661 | *zoom:1;
662 | *display:inline;
663 | }
664 | .CodeMirror-gutter-wrapper {
665 | position: absolute;
666 | z-index: 4;
667 | height: 100%;
668 | }
669 | .CodeMirror-gutter-elt {
670 | position: absolute;
671 | cursor: default;
672 | z-index: 4;
673 | }
674 | .CodeMirror-gutter-wrapper {
675 | -webkit-user-select: none;
676 | -moz-user-select: none;
677 | user-select: none;
678 | }
679 |
680 | .CodeMirror-lines {
681 | cursor: text;
682 | min-height: 1px; /* prevents collapsing before first draw */
683 | }
684 | .CodeMirror pre {
685 | /* Reset some styles that the rest of the page might have set */
686 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
687 | border-width: 0;
688 | background: transparent;
689 | font-family: inherit;
690 | font-size: inherit;
691 | margin: 0;
692 | white-space: pre;
693 | word-wrap: normal;
694 | line-height: inherit;
695 | color: inherit;
696 | z-index: 2;
697 | position: relative;
698 | overflow: visible;
699 | -webkit-tap-highlight-color: transparent;
700 | }
701 | .CodeMirror-wrap pre {
702 | word-wrap: break-word;
703 | white-space: pre-wrap;
704 | word-break: normal;
705 | }
706 |
707 | .CodeMirror-linebackground {
708 | position: absolute;
709 | left: 0; right: 0; top: 0; bottom: 0;
710 | z-index: 0;
711 | }
712 |
713 | .CodeMirror-linewidget {
714 | position: relative;
715 | z-index: 2;
716 | overflow: auto;
717 | }
718 |
719 | .CodeMirror-widget {}
720 |
721 | .CodeMirror-code {
722 | outline: none;
723 | }
724 |
725 | /* Force content-box sizing for the elements where we expect it */
726 | .CodeMirror-scroll,
727 | .CodeMirror-sizer,
728 | .CodeMirror-gutter,
729 | .CodeMirror-gutters,
730 | .CodeMirror-linenumber {
731 | -moz-box-sizing: content-box;
732 | box-sizing: content-box;
733 | }
734 |
735 | .CodeMirror-measure {
736 | position: absolute;
737 | width: 100%;
738 | height: 0;
739 | overflow: hidden;
740 | visibility: hidden;
741 | }
742 | .CodeMirror-measure pre { position: static; }
743 |
744 | .CodeMirror div.CodeMirror-cursor {
745 | position: absolute;
746 | border-right: none;
747 | width: 0;
748 | }
749 |
750 | div.CodeMirror-cursors {
751 | visibility: hidden;
752 | position: relative;
753 | z-index: 3;
754 | }
755 | .CodeMirror-focused div.CodeMirror-cursors {
756 | visibility: visible;
757 | }
758 |
759 | .CodeMirror-selected { background: #d9d9d9; }
760 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
761 | .CodeMirror-crosshair { cursor: crosshair; }
762 | .CodeMirror ::selection { background: #d7d4f0; }
763 | .CodeMirror ::-moz-selection { background: #d7d4f0; }
764 |
765 | .cm-searching {
766 | background: #ffa;
767 | background: rgba(255, 255, 0, .4);
768 | }
769 |
770 | /* IE7 hack to prevent it from returning funny offsetTops on the spans */
771 | .CodeMirror span { *vertical-align: text-bottom; }
772 |
773 | /* Used to force a border model for a node */
774 | .cm-force-border { padding-right: .1px; }
775 |
776 | @media print {
777 | /* Hide the cursor when printing */
778 | .CodeMirror div.CodeMirror-cursors {
779 | visibility: hidden;
780 | }
781 | }
782 |
783 | /* See issue #2901 */
784 | .cm-tab-wrap-hack:after { content: ''; }
785 |
786 | /* Help users use markselection to safely style text background */
787 | span.CodeMirror-selectedtext { background: none; }
788 | #graphiql-container .doc-explorer {
789 | background: white;
790 | }
791 |
792 | #graphiql-container .doc-explorer-title-bar {
793 | cursor: default;
794 | display: -webkit-flex;
795 | display: flex;
796 | height: 34px;
797 | line-height: 14px;
798 | padding: 8px 8px 5px;
799 | position: relative;
800 | -webkit-user-select: none;
801 | user-select: none;
802 | }
803 |
804 | #graphiql-container .doc-explorer-title {
805 | padding: 10px 0 10px 10px;
806 | font-weight: bold;
807 | text-align: center;
808 | text-overflow: ellipsis;
809 | white-space: nowrap;
810 | overflow-x: hidden;
811 | -webkit-flex: 1;
812 | flex: 1;
813 | }
814 |
815 | #graphiql-container .doc-explorer-back {
816 | color: #3B5998;
817 | cursor: pointer;
818 | margin: -7px 0 -6px -8px;
819 | overflow-x: hidden;
820 | padding: 17px 12px 16px 16px;
821 | text-overflow: ellipsis;
822 | white-space: nowrap;
823 | }
824 |
825 | #graphiql-container .doc-explorer-back:before {
826 | border-left: 2px solid #3B5998;
827 | border-top: 2px solid #3B5998;
828 | content: '';
829 | display: inline-block;
830 | height: 9px;
831 | margin: 0 3px -1px 0;
832 | position: relative;
833 | width: 9px;
834 | -webkit-transform: rotate(-45deg);
835 | transform: rotate(-45deg);
836 | }
837 |
838 | #graphiql-container .doc-explorer-rhs {
839 | position: relative;
840 | }
841 |
842 | #graphiql-container .doc-explorer-contents {
843 | position: relative;
844 | height: 100%;
845 | background-color: #ffffff;
846 | border-top: 1px solid #d6d6d6;
847 | padding: 20px 15px;
848 | overflow-y: auto;
849 | min-width: 300px;
850 | }
851 |
852 | #graphiql-container .doc-type-description p:first-child ,
853 | #graphiql-container .doc-type-description blockquote:first-child {
854 | margin-top: 0;
855 | }
856 |
857 | #graphiql-container .doc-explorer-contents a {
858 | cursor: pointer;
859 | text-decoration: none;
860 | }
861 |
862 | #graphiql-container .doc-explorer-contents a:hover {
863 | text-decoration: underline;
864 | }
865 |
866 | #graphiql-container .doc-value-description {
867 | padding: 4px 0 8px 12px;
868 | }
869 |
870 | #graphiql-container .doc-category {
871 | margin: 20px 0;
872 | }
873 |
874 | #graphiql-container .doc-category-title {
875 | border-bottom: 1px solid #e0e0e0;
876 | color: #777;
877 | cursor: default;
878 | font-size: 14px;
879 | font-variant: small-caps;
880 | font-weight: bold;
881 | letter-spacing: 1px;
882 | margin-bottom: 10px;
883 | padding: 10px 0;
884 | -webkit-user-select: none;
885 | user-select: none;
886 | }
887 |
888 | #graphiql-container .doc-category-item {
889 | margin: 12px 0;
890 | color: #555;
891 | }
892 |
893 | #graphiql-container .keyword {
894 | color: #B11A04;
895 | }
896 |
897 | #graphiql-container .type-name {
898 | color: #CA9800;
899 | }
900 |
901 | #graphiql-container .field-name {
902 | color: #1F61A0;
903 | }
904 |
905 | #graphiql-container .value-name {
906 | color: #0B7FC7;
907 | }
908 |
909 | #graphiql-container .arg-name {
910 | color: #8B2BB9;
911 | }
912 |
913 | #graphiql-container .arg:after {
914 | content: ', ';
915 | }
916 |
917 | #graphiql-container .arg:last-child:after {
918 | content: '';
919 | }
920 | .CodeMirror-foldmarker {
921 | color: blue;
922 | text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px;
923 | font-family: arial;
924 | line-height: .3;
925 | cursor: pointer;
926 | }
927 | .CodeMirror-foldgutter {
928 | width: .7em;
929 | }
930 | .CodeMirror-foldgutter-open,
931 | .CodeMirror-foldgutter-folded {
932 | cursor: pointer;
933 | }
934 | .CodeMirror-foldgutter-open:after {
935 | content: "\25BE";
936 | }
937 | .CodeMirror-foldgutter-folded:after {
938 | content: "\25B8";
939 | }
940 | /* The lint marker gutter */
941 | .CodeMirror-lint-markers {
942 | width: 16px;
943 | }
944 |
945 | .CodeMirror-lint-tooltip {
946 | background-color: infobackground;
947 | border: 1px solid black;
948 | border-radius: 4px 4px 4px 4px;
949 | color: infotext;
950 | font-family: monospace;
951 | font-size: 10pt;
952 | overflow: hidden;
953 | padding: 2px 5px;
954 | position: fixed;
955 | white-space: pre;
956 | white-space: pre-wrap;
957 | z-index: 100;
958 | max-width: 600px;
959 | opacity: 0;
960 | transition: opacity .4s;
961 | -moz-transition: opacity .4s;
962 | -webkit-transition: opacity .4s;
963 | -o-transition: opacity .4s;
964 | -ms-transition: opacity .4s;
965 | }
966 |
967 | .CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning {
968 | background-position: left bottom;
969 | background-repeat: repeat-x;
970 | }
971 |
972 | .CodeMirror-lint-mark-error {
973 | background-image:
974 | url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==")
975 | ;
976 | }
977 |
978 | .CodeMirror-lint-mark-warning {
979 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII=");
980 | }
981 |
982 | .CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning {
983 | background-position: center center;
984 | background-repeat: no-repeat;
985 | cursor: pointer;
986 | display: inline-block;
987 | height: 16px;
988 | width: 16px;
989 | vertical-align: middle;
990 | position: relative;
991 | }
992 |
993 | .CodeMirror-lint-message-error, .CodeMirror-lint-message-warning {
994 | padding-left: 18px;
995 | background-position: top left;
996 | background-repeat: no-repeat;
997 | }
998 |
999 | .CodeMirror-lint-marker-error, .CodeMirror-lint-message-error {
1000 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII=");
1001 | }
1002 |
1003 | .CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning {
1004 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII=");
1005 | }
1006 |
1007 | .CodeMirror-lint-marker-multiple {
1008 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC");
1009 | background-repeat: no-repeat;
1010 | background-position: right bottom;
1011 | width: 100%; height: 100%;
1012 | }
1013 | .CodeMirror-hints {
1014 | background: white;
1015 | -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
1016 | -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
1017 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
1018 | font-family: 'Consolas', 'Inconsolata', 'Droid Sans Mono', 'Monaco', monospace;
1019 | font-size: 13px;
1020 | list-style: none;
1021 | margin: 0;
1022 | margin-left: -6px;
1023 | max-height: 14.5em;
1024 | overflow-y: auto;
1025 | overflow: hidden;
1026 | padding: 0;
1027 | position: absolute;
1028 | z-index: 10;
1029 | }
1030 |
1031 | .CodeMirror-hints-wrapper {
1032 | background: white;
1033 | -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
1034 | -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
1035 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
1036 | margin-left: -6px;
1037 | position: absolute;
1038 | z-index: 10;
1039 | }
1040 |
1041 | .CodeMirror-hints-wrapper .CodeMirror-hints {
1042 | -webkit-box-shadow: none;
1043 | -moz-box-shadow: none;
1044 | box-shadow: none;
1045 | position: relative;
1046 | margin-left: 0;
1047 | z-index: 0;
1048 | }
1049 |
1050 | .CodeMirror-hint {
1051 | border-top: solid 1px #f7f7f7;
1052 | color: #141823;
1053 | cursor: pointer;
1054 | margin: 0;
1055 | max-width: 300px;
1056 | overflow: hidden;
1057 | padding: 2px 6px;
1058 | white-space: pre;
1059 | }
1060 |
1061 | li.CodeMirror-hint-active {
1062 | background-color: #08f;
1063 | border-top-color: white;
1064 | color: white;
1065 | }
1066 |
1067 | .CodeMirror-hint-information {
1068 | border-top: solid 1px #c0c0c0;
1069 | max-width: 300px;
1070 | padding: 4px 6px;
1071 | position: relative;
1072 | z-index: 1;
1073 | }
1074 |
1075 | .CodeMirror-hint-information:first-child {
1076 | border-bottom: solid 1px #c0c0c0;
1077 | border-top: none;
1078 | margin-bottom: -1px;
1079 | }
1080 |
--------------------------------------------------------------------------------
/src/server/data/schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "data": {
3 | "__schema": {
4 | "queryType": {
5 | "name": "Query"
6 | },
7 | "mutationType": null,
8 | "types": [
9 | {
10 | "kind": "OBJECT",
11 | "name": "Query",
12 | "description": null,
13 | "fields": [
14 | {
15 | "name": "node",
16 | "description": "Fetches an object given its ID",
17 | "args": [
18 | {
19 | "name": "id",
20 | "description": "The ID of an object",
21 | "type": {
22 | "kind": "NON_NULL",
23 | "name": null,
24 | "ofType": {
25 | "kind": "SCALAR",
26 | "name": "ID",
27 | "ofType": null
28 | }
29 | },
30 | "defaultValue": null
31 | }
32 | ],
33 | "type": {
34 | "kind": "INTERFACE",
35 | "name": "Node",
36 | "ofType": null
37 | },
38 | "isDeprecated": false,
39 | "deprecationReason": null
40 | },
41 | {
42 | "name": "example",
43 | "description": null,
44 | "args": [],
45 | "type": {
46 | "kind": "OBJECT",
47 | "name": "Example",
48 | "ofType": null
49 | },
50 | "isDeprecated": false,
51 | "deprecationReason": null
52 | },
53 | {
54 | "name": "user",
55 | "description": null,
56 | "args": [],
57 | "type": {
58 | "kind": "OBJECT",
59 | "name": "User",
60 | "ofType": null
61 | },
62 | "isDeprecated": false,
63 | "deprecationReason": null
64 | }
65 | ],
66 | "inputFields": null,
67 | "interfaces": [],
68 | "enumValues": null,
69 | "possibleTypes": null
70 | },
71 | {
72 | "kind": "SCALAR",
73 | "name": "ID",
74 | "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.",
75 | "fields": null,
76 | "inputFields": null,
77 | "interfaces": null,
78 | "enumValues": null,
79 | "possibleTypes": null
80 | },
81 | {
82 | "kind": "INTERFACE",
83 | "name": "Node",
84 | "description": "An object with an ID",
85 | "fields": [
86 | {
87 | "name": "id",
88 | "description": "The id of the object.",
89 | "args": [],
90 | "type": {
91 | "kind": "NON_NULL",
92 | "name": null,
93 | "ofType": {
94 | "kind": "SCALAR",
95 | "name": "ID",
96 | "ofType": null
97 | }
98 | },
99 | "isDeprecated": false,
100 | "deprecationReason": null
101 | }
102 | ],
103 | "inputFields": null,
104 | "interfaces": null,
105 | "enumValues": null,
106 | "possibleTypes": [
107 | {
108 | "kind": "OBJECT",
109 | "name": "User",
110 | "ofType": null
111 | },
112 | {
113 | "kind": "OBJECT",
114 | "name": "Example",
115 | "ofType": null
116 | }
117 | ]
118 | },
119 | {
120 | "kind": "OBJECT",
121 | "name": "User",
122 | "description": null,
123 | "fields": [
124 | {
125 | "name": "id",
126 | "description": "The ID of an object",
127 | "args": [],
128 | "type": {
129 | "kind": "NON_NULL",
130 | "name": null,
131 | "ofType": {
132 | "kind": "SCALAR",
133 | "name": "ID",
134 | "ofType": null
135 | }
136 | },
137 | "isDeprecated": false,
138 | "deprecationReason": null
139 | },
140 | {
141 | "name": "email",
142 | "description": "email of the user",
143 | "args": [],
144 | "type": {
145 | "kind": "SCALAR",
146 | "name": "String",
147 | "ofType": null
148 | },
149 | "isDeprecated": false,
150 | "deprecationReason": null
151 | },
152 | {
153 | "name": "password",
154 | "description": "encoded password",
155 | "args": [],
156 | "type": {
157 | "kind": "SCALAR",
158 | "name": "String",
159 | "ofType": null
160 | },
161 | "isDeprecated": false,
162 | "deprecationReason": null
163 | }
164 | ],
165 | "inputFields": null,
166 | "interfaces": [
167 | {
168 | "kind": "INTERFACE",
169 | "name": "Node",
170 | "ofType": null
171 | }
172 | ],
173 | "enumValues": null,
174 | "possibleTypes": null
175 | },
176 | {
177 | "kind": "SCALAR",
178 | "name": "String",
179 | "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.",
180 | "fields": null,
181 | "inputFields": null,
182 | "interfaces": null,
183 | "enumValues": null,
184 | "possibleTypes": null
185 | },
186 | {
187 | "kind": "OBJECT",
188 | "name": "Example",
189 | "description": null,
190 | "fields": [
191 | {
192 | "name": "id",
193 | "description": "The ID of an object",
194 | "args": [],
195 | "type": {
196 | "kind": "NON_NULL",
197 | "name": null,
198 | "ofType": {
199 | "kind": "SCALAR",
200 | "name": "ID",
201 | "ofType": null
202 | }
203 | },
204 | "isDeprecated": false,
205 | "deprecationReason": null
206 | },
207 | {
208 | "name": "text",
209 | "description": "Hello World",
210 | "args": [],
211 | "type": {
212 | "kind": "SCALAR",
213 | "name": "String",
214 | "ofType": null
215 | },
216 | "isDeprecated": false,
217 | "deprecationReason": null
218 | },
219 | {
220 | "name": "version",
221 | "description": "version",
222 | "args": [],
223 | "type": {
224 | "kind": "SCALAR",
225 | "name": "Int",
226 | "ofType": null
227 | },
228 | "isDeprecated": false,
229 | "deprecationReason": null
230 | }
231 | ],
232 | "inputFields": null,
233 | "interfaces": [
234 | {
235 | "kind": "INTERFACE",
236 | "name": "Node",
237 | "ofType": null
238 | }
239 | ],
240 | "enumValues": null,
241 | "possibleTypes": null
242 | },
243 | {
244 | "kind": "SCALAR",
245 | "name": "Int",
246 | "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).",
247 | "fields": null,
248 | "inputFields": null,
249 | "interfaces": null,
250 | "enumValues": null,
251 | "possibleTypes": null
252 | },
253 | {
254 | "kind": "OBJECT",
255 | "name": "__Schema",
256 | "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 and mutation operations.",
257 | "fields": [
258 | {
259 | "name": "types",
260 | "description": "A list of all types supported by this server.",
261 | "args": [],
262 | "type": {
263 | "kind": "NON_NULL",
264 | "name": null,
265 | "ofType": {
266 | "kind": "LIST",
267 | "name": null,
268 | "ofType": {
269 | "kind": "NON_NULL",
270 | "name": null,
271 | "ofType": {
272 | "kind": "OBJECT",
273 | "name": "__Type"
274 | }
275 | }
276 | }
277 | },
278 | "isDeprecated": false,
279 | "deprecationReason": null
280 | },
281 | {
282 | "name": "queryType",
283 | "description": "The type that query operations will be rooted at.",
284 | "args": [],
285 | "type": {
286 | "kind": "NON_NULL",
287 | "name": null,
288 | "ofType": {
289 | "kind": "OBJECT",
290 | "name": "__Type",
291 | "ofType": null
292 | }
293 | },
294 | "isDeprecated": false,
295 | "deprecationReason": null
296 | },
297 | {
298 | "name": "mutationType",
299 | "description": "If this server supports mutation, the type that mutation operations will be rooted at.",
300 | "args": [],
301 | "type": {
302 | "kind": "OBJECT",
303 | "name": "__Type",
304 | "ofType": null
305 | },
306 | "isDeprecated": false,
307 | "deprecationReason": null
308 | },
309 | {
310 | "name": "directives",
311 | "description": "A list of all directives supported by this server.",
312 | "args": [],
313 | "type": {
314 | "kind": "NON_NULL",
315 | "name": null,
316 | "ofType": {
317 | "kind": "LIST",
318 | "name": null,
319 | "ofType": {
320 | "kind": "NON_NULL",
321 | "name": null,
322 | "ofType": {
323 | "kind": "OBJECT",
324 | "name": "__Directive"
325 | }
326 | }
327 | }
328 | },
329 | "isDeprecated": false,
330 | "deprecationReason": null
331 | }
332 | ],
333 | "inputFields": null,
334 | "interfaces": [],
335 | "enumValues": null,
336 | "possibleTypes": null
337 | },
338 | {
339 | "kind": "OBJECT",
340 | "name": "__Type",
341 | "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.",
342 | "fields": [
343 | {
344 | "name": "kind",
345 | "description": null,
346 | "args": [],
347 | "type": {
348 | "kind": "NON_NULL",
349 | "name": null,
350 | "ofType": {
351 | "kind": "ENUM",
352 | "name": "__TypeKind",
353 | "ofType": null
354 | }
355 | },
356 | "isDeprecated": false,
357 | "deprecationReason": null
358 | },
359 | {
360 | "name": "name",
361 | "description": null,
362 | "args": [],
363 | "type": {
364 | "kind": "SCALAR",
365 | "name": "String",
366 | "ofType": null
367 | },
368 | "isDeprecated": false,
369 | "deprecationReason": null
370 | },
371 | {
372 | "name": "description",
373 | "description": null,
374 | "args": [],
375 | "type": {
376 | "kind": "SCALAR",
377 | "name": "String",
378 | "ofType": null
379 | },
380 | "isDeprecated": false,
381 | "deprecationReason": null
382 | },
383 | {
384 | "name": "fields",
385 | "description": null,
386 | "args": [
387 | {
388 | "name": "includeDeprecated",
389 | "description": null,
390 | "type": {
391 | "kind": "SCALAR",
392 | "name": "Boolean",
393 | "ofType": null
394 | },
395 | "defaultValue": "false"
396 | }
397 | ],
398 | "type": {
399 | "kind": "LIST",
400 | "name": null,
401 | "ofType": {
402 | "kind": "NON_NULL",
403 | "name": null,
404 | "ofType": {
405 | "kind": "OBJECT",
406 | "name": "__Field",
407 | "ofType": null
408 | }
409 | }
410 | },
411 | "isDeprecated": false,
412 | "deprecationReason": null
413 | },
414 | {
415 | "name": "interfaces",
416 | "description": null,
417 | "args": [],
418 | "type": {
419 | "kind": "LIST",
420 | "name": null,
421 | "ofType": {
422 | "kind": "NON_NULL",
423 | "name": null,
424 | "ofType": {
425 | "kind": "OBJECT",
426 | "name": "__Type",
427 | "ofType": null
428 | }
429 | }
430 | },
431 | "isDeprecated": false,
432 | "deprecationReason": null
433 | },
434 | {
435 | "name": "possibleTypes",
436 | "description": null,
437 | "args": [],
438 | "type": {
439 | "kind": "LIST",
440 | "name": null,
441 | "ofType": {
442 | "kind": "NON_NULL",
443 | "name": null,
444 | "ofType": {
445 | "kind": "OBJECT",
446 | "name": "__Type",
447 | "ofType": null
448 | }
449 | }
450 | },
451 | "isDeprecated": false,
452 | "deprecationReason": null
453 | },
454 | {
455 | "name": "enumValues",
456 | "description": null,
457 | "args": [
458 | {
459 | "name": "includeDeprecated",
460 | "description": null,
461 | "type": {
462 | "kind": "SCALAR",
463 | "name": "Boolean",
464 | "ofType": null
465 | },
466 | "defaultValue": "false"
467 | }
468 | ],
469 | "type": {
470 | "kind": "LIST",
471 | "name": null,
472 | "ofType": {
473 | "kind": "NON_NULL",
474 | "name": null,
475 | "ofType": {
476 | "kind": "OBJECT",
477 | "name": "__EnumValue",
478 | "ofType": null
479 | }
480 | }
481 | },
482 | "isDeprecated": false,
483 | "deprecationReason": null
484 | },
485 | {
486 | "name": "inputFields",
487 | "description": null,
488 | "args": [],
489 | "type": {
490 | "kind": "LIST",
491 | "name": null,
492 | "ofType": {
493 | "kind": "NON_NULL",
494 | "name": null,
495 | "ofType": {
496 | "kind": "OBJECT",
497 | "name": "__InputValue",
498 | "ofType": null
499 | }
500 | }
501 | },
502 | "isDeprecated": false,
503 | "deprecationReason": null
504 | },
505 | {
506 | "name": "ofType",
507 | "description": null,
508 | "args": [],
509 | "type": {
510 | "kind": "OBJECT",
511 | "name": "__Type",
512 | "ofType": null
513 | },
514 | "isDeprecated": false,
515 | "deprecationReason": null
516 | }
517 | ],
518 | "inputFields": null,
519 | "interfaces": [],
520 | "enumValues": null,
521 | "possibleTypes": null
522 | },
523 | {
524 | "kind": "ENUM",
525 | "name": "__TypeKind",
526 | "description": "An enum describing what kind of type a given `__Type` is.",
527 | "fields": null,
528 | "inputFields": null,
529 | "interfaces": null,
530 | "enumValues": [
531 | {
532 | "name": "SCALAR",
533 | "description": "Indicates this type is a scalar.",
534 | "isDeprecated": false,
535 | "deprecationReason": null
536 | },
537 | {
538 | "name": "OBJECT",
539 | "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.",
540 | "isDeprecated": false,
541 | "deprecationReason": null
542 | },
543 | {
544 | "name": "INTERFACE",
545 | "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.",
546 | "isDeprecated": false,
547 | "deprecationReason": null
548 | },
549 | {
550 | "name": "UNION",
551 | "description": "Indicates this type is a union. `possibleTypes` is a valid field.",
552 | "isDeprecated": false,
553 | "deprecationReason": null
554 | },
555 | {
556 | "name": "ENUM",
557 | "description": "Indicates this type is an enum. `enumValues` is a valid field.",
558 | "isDeprecated": false,
559 | "deprecationReason": null
560 | },
561 | {
562 | "name": "INPUT_OBJECT",
563 | "description": "Indicates this type is an input object. `inputFields` is a valid field.",
564 | "isDeprecated": false,
565 | "deprecationReason": null
566 | },
567 | {
568 | "name": "LIST",
569 | "description": "Indicates this type is a list. `ofType` is a valid field.",
570 | "isDeprecated": false,
571 | "deprecationReason": null
572 | },
573 | {
574 | "name": "NON_NULL",
575 | "description": "Indicates this type is a non-null. `ofType` is a valid field.",
576 | "isDeprecated": false,
577 | "deprecationReason": null
578 | }
579 | ],
580 | "possibleTypes": null
581 | },
582 | {
583 | "kind": "SCALAR",
584 | "name": "Boolean",
585 | "description": "The `Boolean` scalar type represents `true` or `false`.",
586 | "fields": null,
587 | "inputFields": null,
588 | "interfaces": null,
589 | "enumValues": null,
590 | "possibleTypes": null
591 | },
592 | {
593 | "kind": "OBJECT",
594 | "name": "__Field",
595 | "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.",
596 | "fields": [
597 | {
598 | "name": "name",
599 | "description": null,
600 | "args": [],
601 | "type": {
602 | "kind": "NON_NULL",
603 | "name": null,
604 | "ofType": {
605 | "kind": "SCALAR",
606 | "name": "String",
607 | "ofType": null
608 | }
609 | },
610 | "isDeprecated": false,
611 | "deprecationReason": null
612 | },
613 | {
614 | "name": "description",
615 | "description": null,
616 | "args": [],
617 | "type": {
618 | "kind": "SCALAR",
619 | "name": "String",
620 | "ofType": null
621 | },
622 | "isDeprecated": false,
623 | "deprecationReason": null
624 | },
625 | {
626 | "name": "args",
627 | "description": null,
628 | "args": [],
629 | "type": {
630 | "kind": "NON_NULL",
631 | "name": null,
632 | "ofType": {
633 | "kind": "LIST",
634 | "name": null,
635 | "ofType": {
636 | "kind": "NON_NULL",
637 | "name": null,
638 | "ofType": {
639 | "kind": "OBJECT",
640 | "name": "__InputValue"
641 | }
642 | }
643 | }
644 | },
645 | "isDeprecated": false,
646 | "deprecationReason": null
647 | },
648 | {
649 | "name": "type",
650 | "description": null,
651 | "args": [],
652 | "type": {
653 | "kind": "NON_NULL",
654 | "name": null,
655 | "ofType": {
656 | "kind": "OBJECT",
657 | "name": "__Type",
658 | "ofType": null
659 | }
660 | },
661 | "isDeprecated": false,
662 | "deprecationReason": null
663 | },
664 | {
665 | "name": "isDeprecated",
666 | "description": null,
667 | "args": [],
668 | "type": {
669 | "kind": "NON_NULL",
670 | "name": null,
671 | "ofType": {
672 | "kind": "SCALAR",
673 | "name": "Boolean",
674 | "ofType": null
675 | }
676 | },
677 | "isDeprecated": false,
678 | "deprecationReason": null
679 | },
680 | {
681 | "name": "deprecationReason",
682 | "description": null,
683 | "args": [],
684 | "type": {
685 | "kind": "SCALAR",
686 | "name": "String",
687 | "ofType": null
688 | },
689 | "isDeprecated": false,
690 | "deprecationReason": null
691 | }
692 | ],
693 | "inputFields": null,
694 | "interfaces": [],
695 | "enumValues": null,
696 | "possibleTypes": null
697 | },
698 | {
699 | "kind": "OBJECT",
700 | "name": "__InputValue",
701 | "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.",
702 | "fields": [
703 | {
704 | "name": "name",
705 | "description": null,
706 | "args": [],
707 | "type": {
708 | "kind": "NON_NULL",
709 | "name": null,
710 | "ofType": {
711 | "kind": "SCALAR",
712 | "name": "String",
713 | "ofType": null
714 | }
715 | },
716 | "isDeprecated": false,
717 | "deprecationReason": null
718 | },
719 | {
720 | "name": "description",
721 | "description": null,
722 | "args": [],
723 | "type": {
724 | "kind": "SCALAR",
725 | "name": "String",
726 | "ofType": null
727 | },
728 | "isDeprecated": false,
729 | "deprecationReason": null
730 | },
731 | {
732 | "name": "type",
733 | "description": null,
734 | "args": [],
735 | "type": {
736 | "kind": "NON_NULL",
737 | "name": null,
738 | "ofType": {
739 | "kind": "OBJECT",
740 | "name": "__Type",
741 | "ofType": null
742 | }
743 | },
744 | "isDeprecated": false,
745 | "deprecationReason": null
746 | },
747 | {
748 | "name": "defaultValue",
749 | "description": "A GraphQL-formatted string representing the default value for this input value.",
750 | "args": [],
751 | "type": {
752 | "kind": "SCALAR",
753 | "name": "String",
754 | "ofType": null
755 | },
756 | "isDeprecated": false,
757 | "deprecationReason": null
758 | }
759 | ],
760 | "inputFields": null,
761 | "interfaces": [],
762 | "enumValues": null,
763 | "possibleTypes": null
764 | },
765 | {
766 | "kind": "OBJECT",
767 | "name": "__EnumValue",
768 | "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.",
769 | "fields": [
770 | {
771 | "name": "name",
772 | "description": null,
773 | "args": [],
774 | "type": {
775 | "kind": "NON_NULL",
776 | "name": null,
777 | "ofType": {
778 | "kind": "SCALAR",
779 | "name": "String",
780 | "ofType": null
781 | }
782 | },
783 | "isDeprecated": false,
784 | "deprecationReason": null
785 | },
786 | {
787 | "name": "description",
788 | "description": null,
789 | "args": [],
790 | "type": {
791 | "kind": "SCALAR",
792 | "name": "String",
793 | "ofType": null
794 | },
795 | "isDeprecated": false,
796 | "deprecationReason": null
797 | },
798 | {
799 | "name": "isDeprecated",
800 | "description": null,
801 | "args": [],
802 | "type": {
803 | "kind": "NON_NULL",
804 | "name": null,
805 | "ofType": {
806 | "kind": "SCALAR",
807 | "name": "Boolean",
808 | "ofType": null
809 | }
810 | },
811 | "isDeprecated": false,
812 | "deprecationReason": null
813 | },
814 | {
815 | "name": "deprecationReason",
816 | "description": null,
817 | "args": [],
818 | "type": {
819 | "kind": "SCALAR",
820 | "name": "String",
821 | "ofType": null
822 | },
823 | "isDeprecated": false,
824 | "deprecationReason": null
825 | }
826 | ],
827 | "inputFields": null,
828 | "interfaces": [],
829 | "enumValues": null,
830 | "possibleTypes": null
831 | },
832 | {
833 | "kind": "OBJECT",
834 | "name": "__Directive",
835 | "description": "A Directives 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.",
836 | "fields": [
837 | {
838 | "name": "name",
839 | "description": null,
840 | "args": [],
841 | "type": {
842 | "kind": "NON_NULL",
843 | "name": null,
844 | "ofType": {
845 | "kind": "SCALAR",
846 | "name": "String",
847 | "ofType": null
848 | }
849 | },
850 | "isDeprecated": false,
851 | "deprecationReason": null
852 | },
853 | {
854 | "name": "description",
855 | "description": null,
856 | "args": [],
857 | "type": {
858 | "kind": "SCALAR",
859 | "name": "String",
860 | "ofType": null
861 | },
862 | "isDeprecated": false,
863 | "deprecationReason": null
864 | },
865 | {
866 | "name": "args",
867 | "description": null,
868 | "args": [],
869 | "type": {
870 | "kind": "NON_NULL",
871 | "name": null,
872 | "ofType": {
873 | "kind": "LIST",
874 | "name": null,
875 | "ofType": {
876 | "kind": "NON_NULL",
877 | "name": null,
878 | "ofType": {
879 | "kind": "OBJECT",
880 | "name": "__InputValue"
881 | }
882 | }
883 | }
884 | },
885 | "isDeprecated": false,
886 | "deprecationReason": null
887 | },
888 | {
889 | "name": "onOperation",
890 | "description": null,
891 | "args": [],
892 | "type": {
893 | "kind": "NON_NULL",
894 | "name": null,
895 | "ofType": {
896 | "kind": "SCALAR",
897 | "name": "Boolean",
898 | "ofType": null
899 | }
900 | },
901 | "isDeprecated": false,
902 | "deprecationReason": null
903 | },
904 | {
905 | "name": "onFragment",
906 | "description": null,
907 | "args": [],
908 | "type": {
909 | "kind": "NON_NULL",
910 | "name": null,
911 | "ofType": {
912 | "kind": "SCALAR",
913 | "name": "Boolean",
914 | "ofType": null
915 | }
916 | },
917 | "isDeprecated": false,
918 | "deprecationReason": null
919 | },
920 | {
921 | "name": "onField",
922 | "description": null,
923 | "args": [],
924 | "type": {
925 | "kind": "NON_NULL",
926 | "name": null,
927 | "ofType": {
928 | "kind": "SCALAR",
929 | "name": "Boolean",
930 | "ofType": null
931 | }
932 | },
933 | "isDeprecated": false,
934 | "deprecationReason": null
935 | }
936 | ],
937 | "inputFields": null,
938 | "interfaces": [],
939 | "enumValues": null,
940 | "possibleTypes": null
941 | }
942 | ],
943 | "directives": [
944 | {
945 | "name": "include",
946 | "description": "Directs the executor to include this field or fragment only when the `if` argument is true.",
947 | "args": [
948 | {
949 | "name": "if",
950 | "description": "Included when true.",
951 | "type": {
952 | "kind": "NON_NULL",
953 | "name": null,
954 | "ofType": {
955 | "kind": "SCALAR",
956 | "name": "Boolean",
957 | "ofType": null
958 | }
959 | },
960 | "defaultValue": null
961 | }
962 | ],
963 | "onOperation": false,
964 | "onFragment": true,
965 | "onField": true
966 | },
967 | {
968 | "name": "skip",
969 | "description": "Directs the executor to skip this field or fragment when the `if` argument is true.",
970 | "args": [
971 | {
972 | "name": "if",
973 | "description": "Skipped when true.",
974 | "type": {
975 | "kind": "NON_NULL",
976 | "name": null,
977 | "ofType": {
978 | "kind": "SCALAR",
979 | "name": "Boolean",
980 | "ofType": null
981 | }
982 | },
983 | "defaultValue": null
984 | }
985 | ],
986 | "onOperation": false,
987 | "onFragment": true,
988 | "onField": true
989 | }
990 | ]
991 | }
992 | }
993 | }
--------------------------------------------------------------------------------