├── config.json ├── test ├── index.js └── api │ ├── routes │ └── user.js │ └── index.js ├── src ├── server │ ├── consts.js │ ├── models │ │ ├── index.js │ │ └── User.js │ ├── db │ │ ├── config.js │ │ └── index.js │ ├── auth │ │ ├── provider.js │ │ ├── config.js │ │ ├── strategies │ │ │ ├── jwt.js │ │ │ └── email.js │ │ └── index.js │ ├── index.js │ ├── routes │ │ ├── api │ │ │ ├── user.js │ │ │ └── auth.js │ │ ├── index.js │ │ └── base │ │ │ └── graphql.js │ ├── middleware │ │ └── index.js │ └── graphql │ │ ├── index.js │ │ └── util.js └── index.js ├── .babelrc ├── .travis.yml ├── .gitignore ├── .eslintrc ├── scripts └── updateSchema.js ├── README.md ├── package.json └── data ├── schema.graphql └── schema.json /config.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | require('babel-polyfill'); 2 | 3 | require('./api'); 4 | -------------------------------------------------------------------------------- /src/server/consts.js: -------------------------------------------------------------------------------- 1 | export const ERROR = 'ERROR'; 2 | export const OK = 'OK'; 3 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [], 3 | "presets": ["es2015", "stage-0"] 4 | } 5 | 6 | -------------------------------------------------------------------------------- /src/server/models/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by sibelius on 05/04/16. 3 | */ 4 | import User from './User'; 5 | 6 | export default [User]; 7 | 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4" 4 | services: 5 | - mongodb 6 | before_script: 7 | - mongo mydb-test --eval 'db.addUser("travis", "test");' -------------------------------------------------------------------------------- /src/server/db/config.js: -------------------------------------------------------------------------------- 1 | export const development = 'mongodb://localhost/mydb'; 2 | export const production = 'mongodb://localhost/mydb'; 3 | export const test = 'mongodb://localhost/mydb-test'; 4 | -------------------------------------------------------------------------------- /src/server/auth/provider.js: -------------------------------------------------------------------------------- 1 | // TODO - add real clientId and clientSecret 2 | export default { 3 | clientId: '', 4 | clientSecret: '', 5 | route: '/auth/facebook', 6 | callbackRoute: '/auth/facebook/callback', 7 | }; 8 | -------------------------------------------------------------------------------- /test/api/routes/user.js: -------------------------------------------------------------------------------- 1 | export default (request) => { 2 | describe('Users', () => { 3 | it('should fail to authenticate user', async () => { 4 | await request.get('/api/user/me') 5 | .expect(401); 6 | }); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.sublime-project 3 | *.sublime-workspace 4 | .idea/ 5 | 6 | lib 7 | lib-cov 8 | *.seed 9 | *.log 10 | *.csv 11 | *.dat 12 | *.out 13 | *.pid 14 | *.gz 15 | *.map 16 | 17 | pids 18 | logs 19 | results 20 | 21 | node_modules 22 | npm-debug.log 23 | 24 | dump.rdb 25 | bundle.js 26 | -------------------------------------------------------------------------------- /src/server/db/index.js: -------------------------------------------------------------------------------- 1 | import mongoose from 'mongoose'; 2 | 3 | export default (uri) => new Promise((resolve, reject) => { 4 | mongoose.connection 5 | .on('error', error => reject(error)) 6 | .on('close', () => console.log('Database connection closed.')) 7 | .once('open', () => resolve(mongoose.connections[0])); 8 | 9 | mongoose.connect(uri); 10 | }); 11 | -------------------------------------------------------------------------------- /src/server/index.js: -------------------------------------------------------------------------------- 1 | import Koa from 'koa'; 2 | 3 | import middleware from './middleware'; 4 | import auth from './auth'; 5 | import routes from './routes'; 6 | 7 | const app = new Koa(); 8 | app.keys = ['my-secret-key']; 9 | 10 | app.use(middleware()); 11 | app.use(auth()); 12 | app.use(routes()); 13 | app.use(ctx => ctx.status = 404); 14 | 15 | export default app; 16 | -------------------------------------------------------------------------------- /src/server/auth/config.js: -------------------------------------------------------------------------------- 1 | export const localClient = { 2 | name: 'local', 3 | id: 'local', 4 | secret: 'local', 5 | }; 6 | 7 | export const facebook = { 8 | clientId: '', 9 | clientSecret: '', 10 | callbackUrl: 'http://localhost:3000/api/auth/facebook/callback', 11 | }; 12 | 13 | // TODO - add a real secret key 14 | export const auth = { 15 | secret: 'my-secret-code', 16 | }; 17 | -------------------------------------------------------------------------------- /src/server/routes/api/user.js: -------------------------------------------------------------------------------- 1 | import User from '../../models/User'; 2 | import { isAuthenticated } from '../../auth'; 3 | 4 | export default (router) => { 5 | router 6 | // Get user data from server using token 7 | .get('/user/me', isAuthenticated(), async ctx => { 8 | const user = await User.findById(ctx.passport.user); 9 | if (user) ctx.body = user; 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb/base", 3 | "parser": "babel-eslint", 4 | "rules": { 5 | "no-console": 0, 6 | "max-len": "off", 7 | "no-return-assign": "off", 8 | "no-param-reassign": [2, { "props": false }], 9 | "no-underscore-dangle": ["error", { "allow": ["_id"] }], 10 | "comma-dangle": "off", 11 | "function-paren-newline": "off", 12 | "arrow-parens": "off" 13 | }, 14 | "env": { 15 | "mocha": true 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/server/middleware/index.js: -------------------------------------------------------------------------------- 1 | import compose from 'koa-compose'; 2 | import convert from 'koa-convert'; 3 | import logger from 'koa-logger'; 4 | import cors from 'koa-cors'; 5 | import bodyParser from 'koa-bodyparser'; 6 | // import session from 'koa-generic-session'; 7 | 8 | export default function middleware() { 9 | return compose([ 10 | logger(), 11 | convert(cors()), 12 | convert(bodyParser()), 13 | // convert(session()), 14 | ]); 15 | } 16 | -------------------------------------------------------------------------------- /src/server/graphql/index.js: -------------------------------------------------------------------------------- 1 | import compose from 'koa-compose'; 2 | import convert from 'koa-convert'; 3 | import { getSchema } from '@risingstack/graffiti-mongoose'; 4 | import graffiti from '@risingstack/graffiti'; 5 | import Models from '../models'; 6 | 7 | export const schema = getSchema(Models); 8 | export const graphiql = true; 9 | 10 | export default function graphql() { 11 | return compose([ 12 | convert(graffiti.koa({ 13 | schema, 14 | graphiql, 15 | })), 16 | ]); 17 | } 18 | -------------------------------------------------------------------------------- /src/server/models/User.js: -------------------------------------------------------------------------------- 1 | import mongoose from 'mongoose-fill'; 2 | 3 | const UserSchema = new mongoose.Schema({ 4 | name: { 5 | type: String, 6 | required: true, 7 | }, 8 | email: { 9 | type: String, 10 | required: false, 11 | index: true, 12 | }, 13 | password: { 14 | type: String, 15 | required: true, 16 | }, 17 | }, { 18 | timestamps: { 19 | createdAt: 'createdAt', 20 | updatedAt: 'updatedAt', 21 | }, 22 | }); 23 | 24 | export default mongoose.model('User', UserSchema); 25 | -------------------------------------------------------------------------------- /src/server/auth/strategies/jwt.js: -------------------------------------------------------------------------------- 1 | import { Strategy as JWTStrategy, ExtractJwt } from 'passport-jwt'; 2 | import User from '../../models/User'; 3 | import { auth } from '../config'; 4 | 5 | const opts = { 6 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), 7 | secretOrKey: auth.secret, 8 | }; 9 | 10 | export default new JWTStrategy(opts, async (jwtPayload, done) => { 11 | const user = await User.findById(jwtPayload.id); 12 | if (user) { 13 | done(null, user); 14 | } else { 15 | done(null, false); 16 | } 17 | }); 18 | -------------------------------------------------------------------------------- /src/server/routes/index.js: -------------------------------------------------------------------------------- 1 | import compose from 'koa-compose'; 2 | import Router from 'koa-router'; 3 | import importDir from 'import-dir'; 4 | 5 | const routerConfigs = [{ folder: 'base', prefix: '' }, { folder: 'api', prefix: '/api' }]; 6 | 7 | export default function routes() { 8 | const composed = routerConfigs.reduce((prev, curr) => { 9 | const Routes = importDir(`./${curr.folder}`); 10 | const router = new Router({ 11 | prefix: curr.prefix 12 | }); 13 | 14 | Object.keys(Routes).map(name => Routes[name](router)); 15 | 16 | return [router.routes(), router.allowedMethods(), ...prev]; 17 | }, []); 18 | 19 | return compose(composed); 20 | } 21 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import 'babel-polyfill'; 2 | import 'isomorphic-fetch'; 3 | import app from './server'; 4 | import connectDatabase from './server/db'; 5 | import { development, /* test , */production } from './server/db/config'; 6 | 7 | const port = process.env.PORT || 4000; 8 | const databaseConfig = (process.env.NODE_ENV === 'production') ? production : development; 9 | 10 | (async () => { 11 | try { 12 | const info = await connectDatabase(databaseConfig); 13 | console.log(`Connected to ${info.host}:${info.port}/${info.name}`); 14 | } catch (error) { 15 | console.error('Unable to connect to database'); 16 | } 17 | 18 | await app.listen(port); 19 | console.log(`Server started on port ${port}`); 20 | })(); 21 | -------------------------------------------------------------------------------- /src/server/auth/strategies/email.js: -------------------------------------------------------------------------------- 1 | import { Strategy as CustomStrategy } from 'passport-custom'; 2 | import User from '../../models/User'; 3 | 4 | export default new CustomStrategy(async (ctx, done) => { 5 | console.log('Email Strategy: ', ctx.body); 6 | 7 | try { 8 | // Test whether is a login using email and password 9 | if (ctx.body.email && ctx.body.password) { 10 | const user = await User.findOne({ email: ctx.body.email.toLowerCase() }); 11 | 12 | if (!user) { 13 | done(null, false); 14 | } 15 | 16 | done(null, user); 17 | // TODO - check password 18 | } else { 19 | done(null, false); 20 | } 21 | } catch (error) { 22 | done(error); 23 | } 24 | }); 25 | -------------------------------------------------------------------------------- /test/api/index.js: -------------------------------------------------------------------------------- 1 | import importDir from 'import-dir'; 2 | import supertest from 'supertest'; 3 | import mongoose from 'mongoose'; 4 | import chai from 'chai'; 5 | import app from '../../src/server'; 6 | import connectDatabase from '../../src/server/db'; 7 | import { test } from '../../src/server/db/config'; 8 | 9 | const routes = importDir('./routes'); 10 | const request = supertest.agent(app.listen()); 11 | chai.should(); 12 | 13 | describe('Routes', () => { 14 | before(async () => { 15 | await connectDatabase(test); 16 | }); 17 | 18 | beforeEach(async () => { 19 | Object.keys(mongoose.models).forEach(async name => { 20 | await mongoose.model(name).remove(); 21 | }); 22 | }); 23 | 24 | Object.keys(routes).forEach(name => routes[name](request)); 25 | }); 26 | -------------------------------------------------------------------------------- /scripts/updateSchema.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env babel-node --optional es7.asyncFunctions 2 | 3 | import fs from 'fs'; 4 | import path from 'path'; 5 | import { graphql } from 'graphql'; 6 | import { introspectionQuery, printSchema } from 'graphql/utilities'; 7 | import { schema } from '../src/server/graphql'; 8 | 9 | // Save JSON of full schema introspection for Babel Relay Plugin to use 10 | (async () => { 11 | const result = await (graphql(schema, introspectionQuery)); 12 | if (result.errors) { 13 | console.error( 14 | 'ERROR introspecting schema: ', 15 | JSON.stringify(result.errors, null, 2) 16 | ); 17 | } else { 18 | fs.writeFileSync( 19 | path.join(__dirname, '../data/schema.json'), 20 | JSON.stringify(result, null, 2) 21 | ); 22 | } 23 | })(); 24 | 25 | // Save user readable type system shorthand of schema 26 | fs.writeFileSync( 27 | path.join(__dirname, '../data/schema.graphql'), 28 | printSchema(schema) 29 | ); 30 | -------------------------------------------------------------------------------- /src/server/routes/base/graphql.js: -------------------------------------------------------------------------------- 1 | import { graphql } from 'graphql'; 2 | import renderGraphiQL from '../../graphql/util'; 3 | import { schema, graphiql } from '../../graphql'; 4 | 5 | function accepts(ctx, type) { 6 | return ctx.headers && ctx.headers.accept && ctx.headers.accept.includes(type); 7 | } 8 | 9 | export default (router) => { 10 | router 11 | .get('/graphql', 12 | async ctx => { 13 | const { body } = ctx.request; 14 | const { query, variables } = Object.assign({}, body, ctx.query); 15 | 16 | if (accepts(ctx, 'html') && graphiql) { 17 | ctx.body = renderGraphiQL({ query, variables }); 18 | } else if (query && query.includes('mutation')) { 19 | ctx.status = 406; 20 | ctx.body = 'GraphQL mutation only allowed in POST request.'; 21 | } 22 | } 23 | ) 24 | .post('/graphql', 25 | async ctx => { 26 | const { body } = ctx.request; 27 | const { query, variables } = Object.assign({}, body, ctx.query); 28 | 29 | ctx.body = await graphql(schema, query, ctx, variables); 30 | } 31 | ); 32 | }; 33 | -------------------------------------------------------------------------------- /src/server/routes/api/auth.js: -------------------------------------------------------------------------------- 1 | import { 2 | authEmail, 3 | generateToken, 4 | } from '../../auth'; 5 | /* import { ERROR, OK } from '../../consts'; */ 6 | import User from '../../models/User'; 7 | 8 | async function register(ctx, next) { 9 | const { name, email, password } = ctx.request.body; 10 | 11 | // TODO - improve validation 12 | if (name && email && password) { 13 | let user = await User.findOne({ email }); 14 | 15 | if (!user) { 16 | user = new User({ 17 | name, 18 | email, 19 | }); 20 | 21 | // TODO handle password 22 | 23 | await user.save(); 24 | 25 | ctx.passport = { 26 | user: user._id, 27 | }; 28 | 29 | await next(); 30 | } else { 31 | ctx.status = 400; 32 | ctx.body = { status: 'error', message: 'E-mail already registered' }; 33 | } 34 | } else { 35 | ctx.status = 400; 36 | ctx.body = { status: 'error', message: 'Invalid email or password' }; 37 | } 38 | } 39 | 40 | export default (router) => { 41 | router 42 | .post('/auth/email', 43 | authEmail(), 44 | generateToken()); 45 | 46 | router 47 | .post('/auth/register', 48 | register, 49 | generateToken(), 50 | ); 51 | }; 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Koa 2 + Passport + Mongoose + GraphQL 2 | 3 | [](https://travis-ci.org/sibelius/koa-passport-mongoose-graphql) 4 | 5 | ## Notice 6 | You want build a more flexible GraphQL schema, consider using this boilerplate instead: https://github.com/sibelius/graphql-dataloader-boilerplate 7 | 8 | [graffiti-mongoose](https://github.com/RisingStack/graffiti-mongoose) is good for your first version of GraphQL, but do not scale well when you need to customize your schema 9 | 10 | ## Command 11 | 12 | #### Setup 13 | ```bash 14 | npm install 15 | ``` 16 | #### Develop 17 | ```bash 18 | # using nodemon 19 | npm start 20 | 21 | # using babel-watch 22 | npm run watch 23 | ``` 24 | 25 | #### Test 26 | ```bash 27 | npm test 28 | ``` 29 | 30 | 31 | ## Dependencies 32 | 33 | - Watcher and hot-reload: [nodemon](http://nodemon.io/) 34 | - Test: 35 | + [mocha](https://mochajs.org/) 36 | + [should](https://github.com/shouldjs/should.js) 37 | + [supertest](https://github.com/visionmedia/supertest) 38 | - Build: [babel](http://babeljs.io/) 39 | + tools: babel-register 40 | + presets: babel-preset-es2015-node5 41 | + plugins: transform-async-to-generator, syntax-async-functions 42 | - *Lint*: 43 | You can choose the lint tool that you prefer. 44 | 45 | ## Reference 46 | 47 | - [koajs/koa#533](https://github.com/koajs/koa/issues/533) 48 | - [koajs/koa#596](https://github.com/koajs/koa/issues/596) 49 | -------------------------------------------------------------------------------- /src/server/auth/index.js: -------------------------------------------------------------------------------- 1 | import passport from 'koa-passport'; 2 | import compose from 'koa-compose'; 3 | import jwt from 'jsonwebtoken'; 4 | import User from '../models/User'; 5 | import { auth as config } from './config'; 6 | 7 | // Strategies 8 | import jwtStrategy from './strategies/jwt'; 9 | import emailStrategy from './strategies/email'; 10 | 11 | passport.use('jwt', jwtStrategy); 12 | passport.use('email', emailStrategy); 13 | 14 | passport.serializeUser((user, done) => { 15 | done(null, user._id); 16 | }); 17 | 18 | passport.deserializeUser((id, done) => { 19 | (async () => { 20 | try { 21 | const user = await User.findById(id); 22 | done(null, user); 23 | } catch (error) { 24 | done(error); 25 | } 26 | })(); 27 | }); 28 | 29 | export default function auth() { 30 | return compose([ 31 | passport.initialize(), 32 | ]); 33 | } 34 | 35 | export function isAuthenticated() { 36 | return passport.authenticate('jwt'); 37 | } 38 | 39 | export function authEmail() { 40 | return passport.authenticate('email'); 41 | } 42 | 43 | // After autentication using one of the strategies, generate a JWT token 44 | export function generateToken() { 45 | return async ctx => { 46 | const { user } = ctx.passport; 47 | if (user === false) { 48 | ctx.status = 401; 49 | } else { 50 | const jwtToken = jwt.sign({ id: user }, config.secret); 51 | const token = `JWT ${jwtToken}`; 52 | 53 | const currentUser = await User.findOne({ _id: user }); 54 | 55 | ctx.status = 200; 56 | ctx.body = { 57 | token, 58 | user: currentUser, 59 | }; 60 | } 61 | }; 62 | } 63 | 64 | // Web Facebook Authentication 65 | export function isFacebookAuthenticated() { 66 | return passport.authenticate('facebook', { 67 | scope: ['email'], 68 | }); 69 | } 70 | 71 | export function isFacebookAuthenticatedCallback() { 72 | return passport.authenticate('facebook', { 73 | failureRedirect: '/login', 74 | }); 75 | } 76 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "koa-passport-mongoose-graphql", 3 | "version": "1.0.0", 4 | "description": "Koa 2 server with passport mongoose and graphql", 5 | "main": "lib/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/sibeliusseraphini/koa-passport-mongoose-graphql" 9 | }, 10 | "license": "MIT", 11 | "dependencies": { 12 | "@risingstack/graffiti": "^3.0.4", 13 | "@risingstack/graffiti-mongoose": "^6.0.0", 14 | "aws-sdk": "^2.203.0", 15 | "babel-polyfill": "^6.7.4", 16 | "bcrypt-nodejs-as-promised": "^1.0.4", 17 | "es6-promise": "^4.2.4", 18 | "graphql": "^0.13.1", 19 | "import-dir": "0.0.1", 20 | "isomorphic-fetch": "^2.2.1", 21 | "jsonwebtoken": "^8.1.1", 22 | "koa": "^2.5.0", 23 | "koa-bodyparser": "^4.2.0", 24 | "koa-compose": "^4.0.0", 25 | "koa-convert": "^1.2.0", 26 | "koa-cors": "0.0.16", 27 | "koa-generic-session": "^2.0.1", 28 | "koa-logger": "^3.1.0", 29 | "koa-passport": "^4.0.1", 30 | "koa-router": "^7.4.0", 31 | "kue": "^0.11.6", 32 | "mongoose": "^5.0.7", 33 | "mongoose-fill": "^1.7.0", 34 | "mongoose-id-validator": "^0.4.3", 35 | "mongoose-populate-virtuals": "^1.0.3", 36 | "mongoose-validator": "^2.0.2", 37 | "oauth2orize-koa": "^1.3.2", 38 | "passport-custom": "^1.0.5", 39 | "passport-facebook": "^2.1.0", 40 | "passport-http": "^0.3.0", 41 | "passport-http-bearer": "^1.0.1", 42 | "passport-jwt": "^3.0.1", 43 | "passport-local": "^1.0.0", 44 | "uid": "0.0.2" 45 | }, 46 | "devDependencies": { 47 | "babel-cli": "^6.26.0", 48 | "babel-eslint": "^8.2.2", 49 | "babel-preset-es2015": "^6.6.0", 50 | "babel-preset-stage-0": "^6.5.0", 51 | "babel-register": "^6.9.0", 52 | "babel-watch": "^2.0.2", 53 | "chai": "^4.1.2", 54 | "eslint": "^4.18.1", 55 | "eslint-config-airbnb": "^16.1.0", 56 | "eslint-plugin-import": "^2.9.0", 57 | "eslint-plugin-jsx-a11y": "^6.0.3", 58 | "eslint-plugin-react": "^7.7.0", 59 | "mocha": "^5.0.1", 60 | "nodemon": "^1.15.1", 61 | "supertest": "^3.0.0" 62 | }, 63 | "scripts": { 64 | "clean": "rm -rf lib && mkdir lib", 65 | "build": "npm run clean && babel src --out-dir lib", 66 | "prestart": "npm run build", 67 | "start": "nodemon ./lib/index.js", 68 | "eslint": "eslint src test scripts", 69 | "watch": "nodemon --exec babel-node -- ./src/index.js", 70 | "update-schema": "babel-node ./scripts/updateSchema.js", 71 | "test": "mocha test --exit --require babel-core/register" 72 | }, 73 | "babel": { 74 | "whitelist": [ 75 | "strict", 76 | "regenerator", 77 | "es6.modules", 78 | "es6.arrowFunctions", 79 | "es6.destructuring", 80 | "es6.spread", 81 | "es7.asyncFunctions" 82 | ] 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /data/schema.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: RootQuery 3 | mutation: RootMutation 4 | } 5 | 6 | input addUserInput { 7 | name: String 8 | email: String 9 | password: String 10 | updatedAt: Date 11 | createdAt: Date 12 | clientMutationId: String 13 | } 14 | 15 | type addUserPayload { 16 | viewer: Viewer 17 | changedUserEdge: changedUserEdge 18 | clientMutationId: String 19 | } 20 | 21 | """An edge in a connection.""" 22 | type changedUserEdge { 23 | """The item at the end of the edge""" 24 | node: changedUserNode 25 | 26 | """A cursor for use in pagination""" 27 | cursor: String! 28 | } 29 | 30 | type changedUserNode { 31 | name: String 32 | email: String 33 | password: String 34 | _id: ID 35 | updatedAt: Date 36 | createdAt: Date 37 | 38 | """The ID of an object""" 39 | id: ID! 40 | } 41 | 42 | scalar Date 43 | 44 | input deleteUserInput { 45 | id: ID! 46 | clientMutationId: String 47 | } 48 | 49 | type deleteUserPayload { 50 | viewer: Viewer 51 | ok: Boolean 52 | id: ID! 53 | clientMutationId: String 54 | } 55 | 56 | """An object with an ID""" 57 | interface Node { 58 | """The id of the object.""" 59 | id: ID! 60 | } 61 | 62 | enum orderByUser { 63 | NAME_ASC 64 | NAME_DESC 65 | PASSWORD_ASC 66 | PASSWORD_DESC 67 | _ID_ASC 68 | _ID_DESC 69 | UPDATEDAT_ASC 70 | UPDATEDAT_DESC 71 | CREATEDAT_ASC 72 | CREATEDAT_DESC 73 | } 74 | 75 | type RootMutation { 76 | addUser(input: addUserInput!): addUserPayload 77 | updateUser(input: updateUserInput!): updateUserPayload 78 | deleteUser(input: deleteUserInput!): deleteUserPayload 79 | } 80 | 81 | type RootQuery { 82 | user(id: ID!): User 83 | User( 84 | """The ID of a User""" 85 | id: [ID] 86 | 87 | """The ID of a User""" 88 | ids: [ID] 89 | orderBy: orderByUser 90 | name: String 91 | email: String 92 | password: String 93 | _id: ID 94 | updatedAt: Date 95 | createdAt: Date 96 | ): [User] 97 | viewer: Viewer 98 | 99 | """Fetches an object given its ID""" 100 | node( 101 | """The ID of an object""" 102 | id: ID! 103 | ): Node 104 | } 105 | 106 | input updateUserInput { 107 | name: String 108 | email: String 109 | password: String 110 | updatedAt: Date 111 | createdAt: Date 112 | id: ID! 113 | clientMutationId: String 114 | } 115 | 116 | type updateUserPayload { 117 | changedUser: User 118 | clientMutationId: String 119 | } 120 | 121 | type User implements Node { 122 | name: String 123 | email: String 124 | password: String 125 | _id: ID 126 | updatedAt: Date 127 | createdAt: Date 128 | 129 | """The ID of an object""" 130 | id: ID! 131 | } 132 | 133 | type Viewer implements Node { 134 | """The ID of an object""" 135 | id: ID! 136 | user(id: ID!): User 137 | } 138 | -------------------------------------------------------------------------------- /src/server/graphql/util.js: -------------------------------------------------------------------------------- 1 | const GRAPHIQL_VERSION = '0.3.1'; 2 | 3 | // TODO default query 4 | // const defaultQuery = ``; 5 | export default ({ query, variables, version = GRAPHIQL_VERSION } = {}) => 6 | ` 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | Loading... 17 | 85 | 86 | `; 87 | -------------------------------------------------------------------------------- /data/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "__schema": { 4 | "queryType": { 5 | "name": "RootQuery" 6 | }, 7 | "mutationType": { 8 | "name": "RootMutation" 9 | }, 10 | "subscriptionType": null, 11 | "types": [ 12 | { 13 | "kind": "OBJECT", 14 | "name": "RootQuery", 15 | "description": null, 16 | "fields": [ 17 | { 18 | "name": "user", 19 | "description": null, 20 | "args": [ 21 | { 22 | "name": "id", 23 | "description": null, 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": "OBJECT", 38 | "name": "User", 39 | "ofType": null 40 | }, 41 | "isDeprecated": false, 42 | "deprecationReason": null 43 | }, 44 | { 45 | "name": "User", 46 | "description": null, 47 | "args": [ 48 | { 49 | "name": "id", 50 | "description": "The ID of a User", 51 | "type": { 52 | "kind": "LIST", 53 | "name": null, 54 | "ofType": { 55 | "kind": "SCALAR", 56 | "name": "ID", 57 | "ofType": null 58 | } 59 | }, 60 | "defaultValue": null 61 | }, 62 | { 63 | "name": "ids", 64 | "description": "The ID of a User", 65 | "type": { 66 | "kind": "LIST", 67 | "name": null, 68 | "ofType": { 69 | "kind": "SCALAR", 70 | "name": "ID", 71 | "ofType": null 72 | } 73 | }, 74 | "defaultValue": null 75 | }, 76 | { 77 | "name": "orderBy", 78 | "description": null, 79 | "type": { 80 | "kind": "ENUM", 81 | "name": "orderByUser", 82 | "ofType": null 83 | }, 84 | "defaultValue": null 85 | }, 86 | { 87 | "name": "name", 88 | "description": null, 89 | "type": { 90 | "kind": "SCALAR", 91 | "name": "String", 92 | "ofType": null 93 | }, 94 | "defaultValue": null 95 | }, 96 | { 97 | "name": "email", 98 | "description": null, 99 | "type": { 100 | "kind": "SCALAR", 101 | "name": "String", 102 | "ofType": null 103 | }, 104 | "defaultValue": null 105 | }, 106 | { 107 | "name": "password", 108 | "description": null, 109 | "type": { 110 | "kind": "SCALAR", 111 | "name": "String", 112 | "ofType": null 113 | }, 114 | "defaultValue": null 115 | }, 116 | { 117 | "name": "_id", 118 | "description": null, 119 | "type": { 120 | "kind": "SCALAR", 121 | "name": "ID", 122 | "ofType": null 123 | }, 124 | "defaultValue": null 125 | }, 126 | { 127 | "name": "updatedAt", 128 | "description": null, 129 | "type": { 130 | "kind": "SCALAR", 131 | "name": "Date", 132 | "ofType": null 133 | }, 134 | "defaultValue": null 135 | }, 136 | { 137 | "name": "createdAt", 138 | "description": null, 139 | "type": { 140 | "kind": "SCALAR", 141 | "name": "Date", 142 | "ofType": null 143 | }, 144 | "defaultValue": null 145 | } 146 | ], 147 | "type": { 148 | "kind": "LIST", 149 | "name": null, 150 | "ofType": { 151 | "kind": "OBJECT", 152 | "name": "User", 153 | "ofType": null 154 | } 155 | }, 156 | "isDeprecated": false, 157 | "deprecationReason": null 158 | }, 159 | { 160 | "name": "viewer", 161 | "description": null, 162 | "args": [], 163 | "type": { 164 | "kind": "OBJECT", 165 | "name": "Viewer", 166 | "ofType": null 167 | }, 168 | "isDeprecated": false, 169 | "deprecationReason": null 170 | }, 171 | { 172 | "name": "node", 173 | "description": "Fetches an object given its ID", 174 | "args": [ 175 | { 176 | "name": "id", 177 | "description": "The ID of an object", 178 | "type": { 179 | "kind": "NON_NULL", 180 | "name": null, 181 | "ofType": { 182 | "kind": "SCALAR", 183 | "name": "ID", 184 | "ofType": null 185 | } 186 | }, 187 | "defaultValue": null 188 | } 189 | ], 190 | "type": { 191 | "kind": "INTERFACE", 192 | "name": "Node", 193 | "ofType": null 194 | }, 195 | "isDeprecated": false, 196 | "deprecationReason": null 197 | } 198 | ], 199 | "inputFields": null, 200 | "interfaces": [], 201 | "enumValues": null, 202 | "possibleTypes": null 203 | }, 204 | { 205 | "kind": "SCALAR", 206 | "name": "ID", 207 | "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.", 208 | "fields": null, 209 | "inputFields": null, 210 | "interfaces": null, 211 | "enumValues": null, 212 | "possibleTypes": null 213 | }, 214 | { 215 | "kind": "OBJECT", 216 | "name": "User", 217 | "description": null, 218 | "fields": [ 219 | { 220 | "name": "name", 221 | "description": null, 222 | "args": [], 223 | "type": { 224 | "kind": "SCALAR", 225 | "name": "String", 226 | "ofType": null 227 | }, 228 | "isDeprecated": false, 229 | "deprecationReason": null 230 | }, 231 | { 232 | "name": "email", 233 | "description": null, 234 | "args": [], 235 | "type": { 236 | "kind": "SCALAR", 237 | "name": "String", 238 | "ofType": null 239 | }, 240 | "isDeprecated": false, 241 | "deprecationReason": null 242 | }, 243 | { 244 | "name": "password", 245 | "description": null, 246 | "args": [], 247 | "type": { 248 | "kind": "SCALAR", 249 | "name": "String", 250 | "ofType": null 251 | }, 252 | "isDeprecated": false, 253 | "deprecationReason": null 254 | }, 255 | { 256 | "name": "_id", 257 | "description": null, 258 | "args": [], 259 | "type": { 260 | "kind": "SCALAR", 261 | "name": "ID", 262 | "ofType": null 263 | }, 264 | "isDeprecated": false, 265 | "deprecationReason": null 266 | }, 267 | { 268 | "name": "updatedAt", 269 | "description": null, 270 | "args": [], 271 | "type": { 272 | "kind": "SCALAR", 273 | "name": "Date", 274 | "ofType": null 275 | }, 276 | "isDeprecated": false, 277 | "deprecationReason": null 278 | }, 279 | { 280 | "name": "createdAt", 281 | "description": null, 282 | "args": [], 283 | "type": { 284 | "kind": "SCALAR", 285 | "name": "Date", 286 | "ofType": null 287 | }, 288 | "isDeprecated": false, 289 | "deprecationReason": null 290 | }, 291 | { 292 | "name": "id", 293 | "description": "The ID of an object", 294 | "args": [], 295 | "type": { 296 | "kind": "NON_NULL", 297 | "name": null, 298 | "ofType": { 299 | "kind": "SCALAR", 300 | "name": "ID", 301 | "ofType": null 302 | } 303 | }, 304 | "isDeprecated": false, 305 | "deprecationReason": null 306 | } 307 | ], 308 | "inputFields": null, 309 | "interfaces": [ 310 | { 311 | "kind": "INTERFACE", 312 | "name": "Node", 313 | "ofType": null 314 | } 315 | ], 316 | "enumValues": null, 317 | "possibleTypes": null 318 | }, 319 | { 320 | "kind": "INTERFACE", 321 | "name": "Node", 322 | "description": "An object with an ID", 323 | "fields": [ 324 | { 325 | "name": "id", 326 | "description": "The id of the object.", 327 | "args": [], 328 | "type": { 329 | "kind": "NON_NULL", 330 | "name": null, 331 | "ofType": { 332 | "kind": "SCALAR", 333 | "name": "ID", 334 | "ofType": null 335 | } 336 | }, 337 | "isDeprecated": false, 338 | "deprecationReason": null 339 | } 340 | ], 341 | "inputFields": null, 342 | "interfaces": null, 343 | "enumValues": null, 344 | "possibleTypes": [ 345 | { 346 | "kind": "OBJECT", 347 | "name": "User", 348 | "ofType": null 349 | }, 350 | { 351 | "kind": "OBJECT", 352 | "name": "Viewer", 353 | "ofType": null 354 | } 355 | ] 356 | }, 357 | { 358 | "kind": "SCALAR", 359 | "name": "String", 360 | "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.", 361 | "fields": null, 362 | "inputFields": null, 363 | "interfaces": null, 364 | "enumValues": null, 365 | "possibleTypes": null 366 | }, 367 | { 368 | "kind": "SCALAR", 369 | "name": "Date", 370 | "description": null, 371 | "fields": null, 372 | "inputFields": null, 373 | "interfaces": null, 374 | "enumValues": null, 375 | "possibleTypes": null 376 | }, 377 | { 378 | "kind": "ENUM", 379 | "name": "orderByUser", 380 | "description": null, 381 | "fields": null, 382 | "inputFields": null, 383 | "interfaces": null, 384 | "enumValues": [ 385 | { 386 | "name": "NAME_ASC", 387 | "description": null, 388 | "isDeprecated": false, 389 | "deprecationReason": null 390 | }, 391 | { 392 | "name": "NAME_DESC", 393 | "description": null, 394 | "isDeprecated": false, 395 | "deprecationReason": null 396 | }, 397 | { 398 | "name": "PASSWORD_ASC", 399 | "description": null, 400 | "isDeprecated": false, 401 | "deprecationReason": null 402 | }, 403 | { 404 | "name": "PASSWORD_DESC", 405 | "description": null, 406 | "isDeprecated": false, 407 | "deprecationReason": null 408 | }, 409 | { 410 | "name": "_ID_ASC", 411 | "description": null, 412 | "isDeprecated": false, 413 | "deprecationReason": null 414 | }, 415 | { 416 | "name": "_ID_DESC", 417 | "description": null, 418 | "isDeprecated": false, 419 | "deprecationReason": null 420 | }, 421 | { 422 | "name": "UPDATEDAT_ASC", 423 | "description": null, 424 | "isDeprecated": false, 425 | "deprecationReason": null 426 | }, 427 | { 428 | "name": "UPDATEDAT_DESC", 429 | "description": null, 430 | "isDeprecated": false, 431 | "deprecationReason": null 432 | }, 433 | { 434 | "name": "CREATEDAT_ASC", 435 | "description": null, 436 | "isDeprecated": false, 437 | "deprecationReason": null 438 | }, 439 | { 440 | "name": "CREATEDAT_DESC", 441 | "description": null, 442 | "isDeprecated": false, 443 | "deprecationReason": null 444 | } 445 | ], 446 | "possibleTypes": null 447 | }, 448 | { 449 | "kind": "OBJECT", 450 | "name": "Viewer", 451 | "description": null, 452 | "fields": [ 453 | { 454 | "name": "id", 455 | "description": "The ID of an object", 456 | "args": [], 457 | "type": { 458 | "kind": "NON_NULL", 459 | "name": null, 460 | "ofType": { 461 | "kind": "SCALAR", 462 | "name": "ID", 463 | "ofType": null 464 | } 465 | }, 466 | "isDeprecated": false, 467 | "deprecationReason": null 468 | }, 469 | { 470 | "name": "user", 471 | "description": null, 472 | "args": [ 473 | { 474 | "name": "id", 475 | "description": null, 476 | "type": { 477 | "kind": "NON_NULL", 478 | "name": null, 479 | "ofType": { 480 | "kind": "SCALAR", 481 | "name": "ID", 482 | "ofType": null 483 | } 484 | }, 485 | "defaultValue": null 486 | } 487 | ], 488 | "type": { 489 | "kind": "OBJECT", 490 | "name": "User", 491 | "ofType": null 492 | }, 493 | "isDeprecated": false, 494 | "deprecationReason": null 495 | } 496 | ], 497 | "inputFields": null, 498 | "interfaces": [ 499 | { 500 | "kind": "INTERFACE", 501 | "name": "Node", 502 | "ofType": null 503 | } 504 | ], 505 | "enumValues": null, 506 | "possibleTypes": null 507 | }, 508 | { 509 | "kind": "OBJECT", 510 | "name": "RootMutation", 511 | "description": null, 512 | "fields": [ 513 | { 514 | "name": "addUser", 515 | "description": null, 516 | "args": [ 517 | { 518 | "name": "input", 519 | "description": null, 520 | "type": { 521 | "kind": "NON_NULL", 522 | "name": null, 523 | "ofType": { 524 | "kind": "INPUT_OBJECT", 525 | "name": "addUserInput", 526 | "ofType": null 527 | } 528 | }, 529 | "defaultValue": null 530 | } 531 | ], 532 | "type": { 533 | "kind": "OBJECT", 534 | "name": "addUserPayload", 535 | "ofType": null 536 | }, 537 | "isDeprecated": false, 538 | "deprecationReason": null 539 | }, 540 | { 541 | "name": "updateUser", 542 | "description": null, 543 | "args": [ 544 | { 545 | "name": "input", 546 | "description": null, 547 | "type": { 548 | "kind": "NON_NULL", 549 | "name": null, 550 | "ofType": { 551 | "kind": "INPUT_OBJECT", 552 | "name": "updateUserInput", 553 | "ofType": null 554 | } 555 | }, 556 | "defaultValue": null 557 | } 558 | ], 559 | "type": { 560 | "kind": "OBJECT", 561 | "name": "updateUserPayload", 562 | "ofType": null 563 | }, 564 | "isDeprecated": false, 565 | "deprecationReason": null 566 | }, 567 | { 568 | "name": "deleteUser", 569 | "description": null, 570 | "args": [ 571 | { 572 | "name": "input", 573 | "description": null, 574 | "type": { 575 | "kind": "NON_NULL", 576 | "name": null, 577 | "ofType": { 578 | "kind": "INPUT_OBJECT", 579 | "name": "deleteUserInput", 580 | "ofType": null 581 | } 582 | }, 583 | "defaultValue": null 584 | } 585 | ], 586 | "type": { 587 | "kind": "OBJECT", 588 | "name": "deleteUserPayload", 589 | "ofType": null 590 | }, 591 | "isDeprecated": false, 592 | "deprecationReason": null 593 | } 594 | ], 595 | "inputFields": null, 596 | "interfaces": [], 597 | "enumValues": null, 598 | "possibleTypes": null 599 | }, 600 | { 601 | "kind": "INPUT_OBJECT", 602 | "name": "addUserInput", 603 | "description": null, 604 | "fields": null, 605 | "inputFields": [ 606 | { 607 | "name": "name", 608 | "description": null, 609 | "type": { 610 | "kind": "SCALAR", 611 | "name": "String", 612 | "ofType": null 613 | }, 614 | "defaultValue": null 615 | }, 616 | { 617 | "name": "email", 618 | "description": null, 619 | "type": { 620 | "kind": "SCALAR", 621 | "name": "String", 622 | "ofType": null 623 | }, 624 | "defaultValue": null 625 | }, 626 | { 627 | "name": "password", 628 | "description": null, 629 | "type": { 630 | "kind": "SCALAR", 631 | "name": "String", 632 | "ofType": null 633 | }, 634 | "defaultValue": null 635 | }, 636 | { 637 | "name": "updatedAt", 638 | "description": null, 639 | "type": { 640 | "kind": "SCALAR", 641 | "name": "Date", 642 | "ofType": null 643 | }, 644 | "defaultValue": null 645 | }, 646 | { 647 | "name": "createdAt", 648 | "description": null, 649 | "type": { 650 | "kind": "SCALAR", 651 | "name": "Date", 652 | "ofType": null 653 | }, 654 | "defaultValue": null 655 | }, 656 | { 657 | "name": "clientMutationId", 658 | "description": null, 659 | "type": { 660 | "kind": "SCALAR", 661 | "name": "String", 662 | "ofType": null 663 | }, 664 | "defaultValue": null 665 | } 666 | ], 667 | "interfaces": null, 668 | "enumValues": null, 669 | "possibleTypes": null 670 | }, 671 | { 672 | "kind": "OBJECT", 673 | "name": "addUserPayload", 674 | "description": null, 675 | "fields": [ 676 | { 677 | "name": "viewer", 678 | "description": null, 679 | "args": [], 680 | "type": { 681 | "kind": "OBJECT", 682 | "name": "Viewer", 683 | "ofType": null 684 | }, 685 | "isDeprecated": false, 686 | "deprecationReason": null 687 | }, 688 | { 689 | "name": "changedUserEdge", 690 | "description": null, 691 | "args": [], 692 | "type": { 693 | "kind": "OBJECT", 694 | "name": "changedUserEdge", 695 | "ofType": null 696 | }, 697 | "isDeprecated": false, 698 | "deprecationReason": null 699 | }, 700 | { 701 | "name": "clientMutationId", 702 | "description": null, 703 | "args": [], 704 | "type": { 705 | "kind": "SCALAR", 706 | "name": "String", 707 | "ofType": null 708 | }, 709 | "isDeprecated": false, 710 | "deprecationReason": null 711 | } 712 | ], 713 | "inputFields": null, 714 | "interfaces": [], 715 | "enumValues": null, 716 | "possibleTypes": null 717 | }, 718 | { 719 | "kind": "OBJECT", 720 | "name": "changedUserEdge", 721 | "description": "An edge in a connection.", 722 | "fields": [ 723 | { 724 | "name": "node", 725 | "description": "The item at the end of the edge", 726 | "args": [], 727 | "type": { 728 | "kind": "OBJECT", 729 | "name": "changedUserNode", 730 | "ofType": null 731 | }, 732 | "isDeprecated": false, 733 | "deprecationReason": null 734 | }, 735 | { 736 | "name": "cursor", 737 | "description": "A cursor for use in pagination", 738 | "args": [], 739 | "type": { 740 | "kind": "NON_NULL", 741 | "name": null, 742 | "ofType": { 743 | "kind": "SCALAR", 744 | "name": "String", 745 | "ofType": null 746 | } 747 | }, 748 | "isDeprecated": false, 749 | "deprecationReason": null 750 | } 751 | ], 752 | "inputFields": null, 753 | "interfaces": [], 754 | "enumValues": null, 755 | "possibleTypes": null 756 | }, 757 | { 758 | "kind": "OBJECT", 759 | "name": "changedUserNode", 760 | "description": null, 761 | "fields": [ 762 | { 763 | "name": "name", 764 | "description": null, 765 | "args": [], 766 | "type": { 767 | "kind": "SCALAR", 768 | "name": "String", 769 | "ofType": null 770 | }, 771 | "isDeprecated": false, 772 | "deprecationReason": null 773 | }, 774 | { 775 | "name": "email", 776 | "description": null, 777 | "args": [], 778 | "type": { 779 | "kind": "SCALAR", 780 | "name": "String", 781 | "ofType": null 782 | }, 783 | "isDeprecated": false, 784 | "deprecationReason": null 785 | }, 786 | { 787 | "name": "password", 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": "_id", 800 | "description": null, 801 | "args": [], 802 | "type": { 803 | "kind": "SCALAR", 804 | "name": "ID", 805 | "ofType": null 806 | }, 807 | "isDeprecated": false, 808 | "deprecationReason": null 809 | }, 810 | { 811 | "name": "updatedAt", 812 | "description": null, 813 | "args": [], 814 | "type": { 815 | "kind": "SCALAR", 816 | "name": "Date", 817 | "ofType": null 818 | }, 819 | "isDeprecated": false, 820 | "deprecationReason": null 821 | }, 822 | { 823 | "name": "createdAt", 824 | "description": null, 825 | "args": [], 826 | "type": { 827 | "kind": "SCALAR", 828 | "name": "Date", 829 | "ofType": null 830 | }, 831 | "isDeprecated": false, 832 | "deprecationReason": null 833 | }, 834 | { 835 | "name": "id", 836 | "description": "The ID of an object", 837 | "args": [], 838 | "type": { 839 | "kind": "NON_NULL", 840 | "name": null, 841 | "ofType": { 842 | "kind": "SCALAR", 843 | "name": "ID", 844 | "ofType": null 845 | } 846 | }, 847 | "isDeprecated": false, 848 | "deprecationReason": null 849 | } 850 | ], 851 | "inputFields": null, 852 | "interfaces": [], 853 | "enumValues": null, 854 | "possibleTypes": null 855 | }, 856 | { 857 | "kind": "INPUT_OBJECT", 858 | "name": "updateUserInput", 859 | "description": null, 860 | "fields": null, 861 | "inputFields": [ 862 | { 863 | "name": "name", 864 | "description": null, 865 | "type": { 866 | "kind": "SCALAR", 867 | "name": "String", 868 | "ofType": null 869 | }, 870 | "defaultValue": null 871 | }, 872 | { 873 | "name": "email", 874 | "description": null, 875 | "type": { 876 | "kind": "SCALAR", 877 | "name": "String", 878 | "ofType": null 879 | }, 880 | "defaultValue": null 881 | }, 882 | { 883 | "name": "password", 884 | "description": null, 885 | "type": { 886 | "kind": "SCALAR", 887 | "name": "String", 888 | "ofType": null 889 | }, 890 | "defaultValue": null 891 | }, 892 | { 893 | "name": "updatedAt", 894 | "description": null, 895 | "type": { 896 | "kind": "SCALAR", 897 | "name": "Date", 898 | "ofType": null 899 | }, 900 | "defaultValue": null 901 | }, 902 | { 903 | "name": "createdAt", 904 | "description": null, 905 | "type": { 906 | "kind": "SCALAR", 907 | "name": "Date", 908 | "ofType": null 909 | }, 910 | "defaultValue": null 911 | }, 912 | { 913 | "name": "id", 914 | "description": null, 915 | "type": { 916 | "kind": "NON_NULL", 917 | "name": null, 918 | "ofType": { 919 | "kind": "SCALAR", 920 | "name": "ID", 921 | "ofType": null 922 | } 923 | }, 924 | "defaultValue": null 925 | }, 926 | { 927 | "name": "clientMutationId", 928 | "description": null, 929 | "type": { 930 | "kind": "SCALAR", 931 | "name": "String", 932 | "ofType": null 933 | }, 934 | "defaultValue": null 935 | } 936 | ], 937 | "interfaces": null, 938 | "enumValues": null, 939 | "possibleTypes": null 940 | }, 941 | { 942 | "kind": "OBJECT", 943 | "name": "updateUserPayload", 944 | "description": null, 945 | "fields": [ 946 | { 947 | "name": "changedUser", 948 | "description": null, 949 | "args": [], 950 | "type": { 951 | "kind": "OBJECT", 952 | "name": "User", 953 | "ofType": null 954 | }, 955 | "isDeprecated": false, 956 | "deprecationReason": null 957 | }, 958 | { 959 | "name": "clientMutationId", 960 | "description": null, 961 | "args": [], 962 | "type": { 963 | "kind": "SCALAR", 964 | "name": "String", 965 | "ofType": null 966 | }, 967 | "isDeprecated": false, 968 | "deprecationReason": null 969 | } 970 | ], 971 | "inputFields": null, 972 | "interfaces": [], 973 | "enumValues": null, 974 | "possibleTypes": null 975 | }, 976 | { 977 | "kind": "INPUT_OBJECT", 978 | "name": "deleteUserInput", 979 | "description": null, 980 | "fields": null, 981 | "inputFields": [ 982 | { 983 | "name": "id", 984 | "description": null, 985 | "type": { 986 | "kind": "NON_NULL", 987 | "name": null, 988 | "ofType": { 989 | "kind": "SCALAR", 990 | "name": "ID", 991 | "ofType": null 992 | } 993 | }, 994 | "defaultValue": null 995 | }, 996 | { 997 | "name": "clientMutationId", 998 | "description": null, 999 | "type": { 1000 | "kind": "SCALAR", 1001 | "name": "String", 1002 | "ofType": null 1003 | }, 1004 | "defaultValue": null 1005 | } 1006 | ], 1007 | "interfaces": null, 1008 | "enumValues": null, 1009 | "possibleTypes": null 1010 | }, 1011 | { 1012 | "kind": "OBJECT", 1013 | "name": "deleteUserPayload", 1014 | "description": null, 1015 | "fields": [ 1016 | { 1017 | "name": "viewer", 1018 | "description": null, 1019 | "args": [], 1020 | "type": { 1021 | "kind": "OBJECT", 1022 | "name": "Viewer", 1023 | "ofType": null 1024 | }, 1025 | "isDeprecated": false, 1026 | "deprecationReason": null 1027 | }, 1028 | { 1029 | "name": "ok", 1030 | "description": null, 1031 | "args": [], 1032 | "type": { 1033 | "kind": "SCALAR", 1034 | "name": "Boolean", 1035 | "ofType": null 1036 | }, 1037 | "isDeprecated": false, 1038 | "deprecationReason": null 1039 | }, 1040 | { 1041 | "name": "id", 1042 | "description": null, 1043 | "args": [], 1044 | "type": { 1045 | "kind": "NON_NULL", 1046 | "name": null, 1047 | "ofType": { 1048 | "kind": "SCALAR", 1049 | "name": "ID", 1050 | "ofType": null 1051 | } 1052 | }, 1053 | "isDeprecated": false, 1054 | "deprecationReason": null 1055 | }, 1056 | { 1057 | "name": "clientMutationId", 1058 | "description": null, 1059 | "args": [], 1060 | "type": { 1061 | "kind": "SCALAR", 1062 | "name": "String", 1063 | "ofType": null 1064 | }, 1065 | "isDeprecated": false, 1066 | "deprecationReason": null 1067 | } 1068 | ], 1069 | "inputFields": null, 1070 | "interfaces": [], 1071 | "enumValues": null, 1072 | "possibleTypes": null 1073 | }, 1074 | { 1075 | "kind": "SCALAR", 1076 | "name": "Boolean", 1077 | "description": "The `Boolean` scalar type represents `true` or `false`.", 1078 | "fields": null, 1079 | "inputFields": null, 1080 | "interfaces": null, 1081 | "enumValues": null, 1082 | "possibleTypes": null 1083 | }, 1084 | { 1085 | "kind": "OBJECT", 1086 | "name": "__Schema", 1087 | "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.", 1088 | "fields": [ 1089 | { 1090 | "name": "types", 1091 | "description": "A list of all types supported by this server.", 1092 | "args": [], 1093 | "type": { 1094 | "kind": "NON_NULL", 1095 | "name": null, 1096 | "ofType": { 1097 | "kind": "LIST", 1098 | "name": null, 1099 | "ofType": { 1100 | "kind": "NON_NULL", 1101 | "name": null, 1102 | "ofType": { 1103 | "kind": "OBJECT", 1104 | "name": "__Type", 1105 | "ofType": null 1106 | } 1107 | } 1108 | } 1109 | }, 1110 | "isDeprecated": false, 1111 | "deprecationReason": null 1112 | }, 1113 | { 1114 | "name": "queryType", 1115 | "description": "The type that query operations will be rooted at.", 1116 | "args": [], 1117 | "type": { 1118 | "kind": "NON_NULL", 1119 | "name": null, 1120 | "ofType": { 1121 | "kind": "OBJECT", 1122 | "name": "__Type", 1123 | "ofType": null 1124 | } 1125 | }, 1126 | "isDeprecated": false, 1127 | "deprecationReason": null 1128 | }, 1129 | { 1130 | "name": "mutationType", 1131 | "description": "If this server supports mutation, the type that mutation operations will be rooted at.", 1132 | "args": [], 1133 | "type": { 1134 | "kind": "OBJECT", 1135 | "name": "__Type", 1136 | "ofType": null 1137 | }, 1138 | "isDeprecated": false, 1139 | "deprecationReason": null 1140 | }, 1141 | { 1142 | "name": "subscriptionType", 1143 | "description": "If this server support subscription, the type that subscription operations will be rooted at.", 1144 | "args": [], 1145 | "type": { 1146 | "kind": "OBJECT", 1147 | "name": "__Type", 1148 | "ofType": null 1149 | }, 1150 | "isDeprecated": false, 1151 | "deprecationReason": null 1152 | }, 1153 | { 1154 | "name": "directives", 1155 | "description": "A list of all directives supported by this server.", 1156 | "args": [], 1157 | "type": { 1158 | "kind": "NON_NULL", 1159 | "name": null, 1160 | "ofType": { 1161 | "kind": "LIST", 1162 | "name": null, 1163 | "ofType": { 1164 | "kind": "NON_NULL", 1165 | "name": null, 1166 | "ofType": { 1167 | "kind": "OBJECT", 1168 | "name": "__Directive", 1169 | "ofType": null 1170 | } 1171 | } 1172 | } 1173 | }, 1174 | "isDeprecated": false, 1175 | "deprecationReason": null 1176 | } 1177 | ], 1178 | "inputFields": null, 1179 | "interfaces": [], 1180 | "enumValues": null, 1181 | "possibleTypes": null 1182 | }, 1183 | { 1184 | "kind": "OBJECT", 1185 | "name": "__Type", 1186 | "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.", 1187 | "fields": [ 1188 | { 1189 | "name": "kind", 1190 | "description": null, 1191 | "args": [], 1192 | "type": { 1193 | "kind": "NON_NULL", 1194 | "name": null, 1195 | "ofType": { 1196 | "kind": "ENUM", 1197 | "name": "__TypeKind", 1198 | "ofType": null 1199 | } 1200 | }, 1201 | "isDeprecated": false, 1202 | "deprecationReason": null 1203 | }, 1204 | { 1205 | "name": "name", 1206 | "description": null, 1207 | "args": [], 1208 | "type": { 1209 | "kind": "SCALAR", 1210 | "name": "String", 1211 | "ofType": null 1212 | }, 1213 | "isDeprecated": false, 1214 | "deprecationReason": null 1215 | }, 1216 | { 1217 | "name": "description", 1218 | "description": null, 1219 | "args": [], 1220 | "type": { 1221 | "kind": "SCALAR", 1222 | "name": "String", 1223 | "ofType": null 1224 | }, 1225 | "isDeprecated": false, 1226 | "deprecationReason": null 1227 | }, 1228 | { 1229 | "name": "fields", 1230 | "description": null, 1231 | "args": [ 1232 | { 1233 | "name": "includeDeprecated", 1234 | "description": null, 1235 | "type": { 1236 | "kind": "SCALAR", 1237 | "name": "Boolean", 1238 | "ofType": null 1239 | }, 1240 | "defaultValue": "false" 1241 | } 1242 | ], 1243 | "type": { 1244 | "kind": "LIST", 1245 | "name": null, 1246 | "ofType": { 1247 | "kind": "NON_NULL", 1248 | "name": null, 1249 | "ofType": { 1250 | "kind": "OBJECT", 1251 | "name": "__Field", 1252 | "ofType": null 1253 | } 1254 | } 1255 | }, 1256 | "isDeprecated": false, 1257 | "deprecationReason": null 1258 | }, 1259 | { 1260 | "name": "interfaces", 1261 | "description": null, 1262 | "args": [], 1263 | "type": { 1264 | "kind": "LIST", 1265 | "name": null, 1266 | "ofType": { 1267 | "kind": "NON_NULL", 1268 | "name": null, 1269 | "ofType": { 1270 | "kind": "OBJECT", 1271 | "name": "__Type", 1272 | "ofType": null 1273 | } 1274 | } 1275 | }, 1276 | "isDeprecated": false, 1277 | "deprecationReason": null 1278 | }, 1279 | { 1280 | "name": "possibleTypes", 1281 | "description": null, 1282 | "args": [], 1283 | "type": { 1284 | "kind": "LIST", 1285 | "name": null, 1286 | "ofType": { 1287 | "kind": "NON_NULL", 1288 | "name": null, 1289 | "ofType": { 1290 | "kind": "OBJECT", 1291 | "name": "__Type", 1292 | "ofType": null 1293 | } 1294 | } 1295 | }, 1296 | "isDeprecated": false, 1297 | "deprecationReason": null 1298 | }, 1299 | { 1300 | "name": "enumValues", 1301 | "description": null, 1302 | "args": [ 1303 | { 1304 | "name": "includeDeprecated", 1305 | "description": null, 1306 | "type": { 1307 | "kind": "SCALAR", 1308 | "name": "Boolean", 1309 | "ofType": null 1310 | }, 1311 | "defaultValue": "false" 1312 | } 1313 | ], 1314 | "type": { 1315 | "kind": "LIST", 1316 | "name": null, 1317 | "ofType": { 1318 | "kind": "NON_NULL", 1319 | "name": null, 1320 | "ofType": { 1321 | "kind": "OBJECT", 1322 | "name": "__EnumValue", 1323 | "ofType": null 1324 | } 1325 | } 1326 | }, 1327 | "isDeprecated": false, 1328 | "deprecationReason": null 1329 | }, 1330 | { 1331 | "name": "inputFields", 1332 | "description": null, 1333 | "args": [], 1334 | "type": { 1335 | "kind": "LIST", 1336 | "name": null, 1337 | "ofType": { 1338 | "kind": "NON_NULL", 1339 | "name": null, 1340 | "ofType": { 1341 | "kind": "OBJECT", 1342 | "name": "__InputValue", 1343 | "ofType": null 1344 | } 1345 | } 1346 | }, 1347 | "isDeprecated": false, 1348 | "deprecationReason": null 1349 | }, 1350 | { 1351 | "name": "ofType", 1352 | "description": null, 1353 | "args": [], 1354 | "type": { 1355 | "kind": "OBJECT", 1356 | "name": "__Type", 1357 | "ofType": null 1358 | }, 1359 | "isDeprecated": false, 1360 | "deprecationReason": null 1361 | } 1362 | ], 1363 | "inputFields": null, 1364 | "interfaces": [], 1365 | "enumValues": null, 1366 | "possibleTypes": null 1367 | }, 1368 | { 1369 | "kind": "ENUM", 1370 | "name": "__TypeKind", 1371 | "description": "An enum describing what kind of type a given `__Type` is.", 1372 | "fields": null, 1373 | "inputFields": null, 1374 | "interfaces": null, 1375 | "enumValues": [ 1376 | { 1377 | "name": "SCALAR", 1378 | "description": "Indicates this type is a scalar.", 1379 | "isDeprecated": false, 1380 | "deprecationReason": null 1381 | }, 1382 | { 1383 | "name": "OBJECT", 1384 | "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", 1385 | "isDeprecated": false, 1386 | "deprecationReason": null 1387 | }, 1388 | { 1389 | "name": "INTERFACE", 1390 | "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", 1391 | "isDeprecated": false, 1392 | "deprecationReason": null 1393 | }, 1394 | { 1395 | "name": "UNION", 1396 | "description": "Indicates this type is a union. `possibleTypes` is a valid field.", 1397 | "isDeprecated": false, 1398 | "deprecationReason": null 1399 | }, 1400 | { 1401 | "name": "ENUM", 1402 | "description": "Indicates this type is an enum. `enumValues` is a valid field.", 1403 | "isDeprecated": false, 1404 | "deprecationReason": null 1405 | }, 1406 | { 1407 | "name": "INPUT_OBJECT", 1408 | "description": "Indicates this type is an input object. `inputFields` is a valid field.", 1409 | "isDeprecated": false, 1410 | "deprecationReason": null 1411 | }, 1412 | { 1413 | "name": "LIST", 1414 | "description": "Indicates this type is a list. `ofType` is a valid field.", 1415 | "isDeprecated": false, 1416 | "deprecationReason": null 1417 | }, 1418 | { 1419 | "name": "NON_NULL", 1420 | "description": "Indicates this type is a non-null. `ofType` is a valid field.", 1421 | "isDeprecated": false, 1422 | "deprecationReason": null 1423 | } 1424 | ], 1425 | "possibleTypes": null 1426 | }, 1427 | { 1428 | "kind": "OBJECT", 1429 | "name": "__Field", 1430 | "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.", 1431 | "fields": [ 1432 | { 1433 | "name": "name", 1434 | "description": null, 1435 | "args": [], 1436 | "type": { 1437 | "kind": "NON_NULL", 1438 | "name": null, 1439 | "ofType": { 1440 | "kind": "SCALAR", 1441 | "name": "String", 1442 | "ofType": null 1443 | } 1444 | }, 1445 | "isDeprecated": false, 1446 | "deprecationReason": null 1447 | }, 1448 | { 1449 | "name": "description", 1450 | "description": null, 1451 | "args": [], 1452 | "type": { 1453 | "kind": "SCALAR", 1454 | "name": "String", 1455 | "ofType": null 1456 | }, 1457 | "isDeprecated": false, 1458 | "deprecationReason": null 1459 | }, 1460 | { 1461 | "name": "args", 1462 | "description": null, 1463 | "args": [], 1464 | "type": { 1465 | "kind": "NON_NULL", 1466 | "name": null, 1467 | "ofType": { 1468 | "kind": "LIST", 1469 | "name": null, 1470 | "ofType": { 1471 | "kind": "NON_NULL", 1472 | "name": null, 1473 | "ofType": { 1474 | "kind": "OBJECT", 1475 | "name": "__InputValue", 1476 | "ofType": null 1477 | } 1478 | } 1479 | } 1480 | }, 1481 | "isDeprecated": false, 1482 | "deprecationReason": null 1483 | }, 1484 | { 1485 | "name": "type", 1486 | "description": null, 1487 | "args": [], 1488 | "type": { 1489 | "kind": "NON_NULL", 1490 | "name": null, 1491 | "ofType": { 1492 | "kind": "OBJECT", 1493 | "name": "__Type", 1494 | "ofType": null 1495 | } 1496 | }, 1497 | "isDeprecated": false, 1498 | "deprecationReason": null 1499 | }, 1500 | { 1501 | "name": "isDeprecated", 1502 | "description": null, 1503 | "args": [], 1504 | "type": { 1505 | "kind": "NON_NULL", 1506 | "name": null, 1507 | "ofType": { 1508 | "kind": "SCALAR", 1509 | "name": "Boolean", 1510 | "ofType": null 1511 | } 1512 | }, 1513 | "isDeprecated": false, 1514 | "deprecationReason": null 1515 | }, 1516 | { 1517 | "name": "deprecationReason", 1518 | "description": null, 1519 | "args": [], 1520 | "type": { 1521 | "kind": "SCALAR", 1522 | "name": "String", 1523 | "ofType": null 1524 | }, 1525 | "isDeprecated": false, 1526 | "deprecationReason": null 1527 | } 1528 | ], 1529 | "inputFields": null, 1530 | "interfaces": [], 1531 | "enumValues": null, 1532 | "possibleTypes": null 1533 | }, 1534 | { 1535 | "kind": "OBJECT", 1536 | "name": "__InputValue", 1537 | "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.", 1538 | "fields": [ 1539 | { 1540 | "name": "name", 1541 | "description": null, 1542 | "args": [], 1543 | "type": { 1544 | "kind": "NON_NULL", 1545 | "name": null, 1546 | "ofType": { 1547 | "kind": "SCALAR", 1548 | "name": "String", 1549 | "ofType": null 1550 | } 1551 | }, 1552 | "isDeprecated": false, 1553 | "deprecationReason": null 1554 | }, 1555 | { 1556 | "name": "description", 1557 | "description": null, 1558 | "args": [], 1559 | "type": { 1560 | "kind": "SCALAR", 1561 | "name": "String", 1562 | "ofType": null 1563 | }, 1564 | "isDeprecated": false, 1565 | "deprecationReason": null 1566 | }, 1567 | { 1568 | "name": "type", 1569 | "description": null, 1570 | "args": [], 1571 | "type": { 1572 | "kind": "NON_NULL", 1573 | "name": null, 1574 | "ofType": { 1575 | "kind": "OBJECT", 1576 | "name": "__Type", 1577 | "ofType": null 1578 | } 1579 | }, 1580 | "isDeprecated": false, 1581 | "deprecationReason": null 1582 | }, 1583 | { 1584 | "name": "defaultValue", 1585 | "description": "A GraphQL-formatted string representing the default value for this input value.", 1586 | "args": [], 1587 | "type": { 1588 | "kind": "SCALAR", 1589 | "name": "String", 1590 | "ofType": null 1591 | }, 1592 | "isDeprecated": false, 1593 | "deprecationReason": null 1594 | } 1595 | ], 1596 | "inputFields": null, 1597 | "interfaces": [], 1598 | "enumValues": null, 1599 | "possibleTypes": null 1600 | }, 1601 | { 1602 | "kind": "OBJECT", 1603 | "name": "__EnumValue", 1604 | "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.", 1605 | "fields": [ 1606 | { 1607 | "name": "name", 1608 | "description": null, 1609 | "args": [], 1610 | "type": { 1611 | "kind": "NON_NULL", 1612 | "name": null, 1613 | "ofType": { 1614 | "kind": "SCALAR", 1615 | "name": "String", 1616 | "ofType": null 1617 | } 1618 | }, 1619 | "isDeprecated": false, 1620 | "deprecationReason": null 1621 | }, 1622 | { 1623 | "name": "description", 1624 | "description": null, 1625 | "args": [], 1626 | "type": { 1627 | "kind": "SCALAR", 1628 | "name": "String", 1629 | "ofType": null 1630 | }, 1631 | "isDeprecated": false, 1632 | "deprecationReason": null 1633 | }, 1634 | { 1635 | "name": "isDeprecated", 1636 | "description": null, 1637 | "args": [], 1638 | "type": { 1639 | "kind": "NON_NULL", 1640 | "name": null, 1641 | "ofType": { 1642 | "kind": "SCALAR", 1643 | "name": "Boolean", 1644 | "ofType": null 1645 | } 1646 | }, 1647 | "isDeprecated": false, 1648 | "deprecationReason": null 1649 | }, 1650 | { 1651 | "name": "deprecationReason", 1652 | "description": null, 1653 | "args": [], 1654 | "type": { 1655 | "kind": "SCALAR", 1656 | "name": "String", 1657 | "ofType": null 1658 | }, 1659 | "isDeprecated": false, 1660 | "deprecationReason": null 1661 | } 1662 | ], 1663 | "inputFields": null, 1664 | "interfaces": [], 1665 | "enumValues": null, 1666 | "possibleTypes": null 1667 | }, 1668 | { 1669 | "kind": "OBJECT", 1670 | "name": "__Directive", 1671 | "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.", 1672 | "fields": [ 1673 | { 1674 | "name": "name", 1675 | "description": null, 1676 | "args": [], 1677 | "type": { 1678 | "kind": "NON_NULL", 1679 | "name": null, 1680 | "ofType": { 1681 | "kind": "SCALAR", 1682 | "name": "String", 1683 | "ofType": null 1684 | } 1685 | }, 1686 | "isDeprecated": false, 1687 | "deprecationReason": null 1688 | }, 1689 | { 1690 | "name": "description", 1691 | "description": null, 1692 | "args": [], 1693 | "type": { 1694 | "kind": "SCALAR", 1695 | "name": "String", 1696 | "ofType": null 1697 | }, 1698 | "isDeprecated": false, 1699 | "deprecationReason": null 1700 | }, 1701 | { 1702 | "name": "locations", 1703 | "description": null, 1704 | "args": [], 1705 | "type": { 1706 | "kind": "NON_NULL", 1707 | "name": null, 1708 | "ofType": { 1709 | "kind": "LIST", 1710 | "name": null, 1711 | "ofType": { 1712 | "kind": "NON_NULL", 1713 | "name": null, 1714 | "ofType": { 1715 | "kind": "ENUM", 1716 | "name": "__DirectiveLocation", 1717 | "ofType": null 1718 | } 1719 | } 1720 | } 1721 | }, 1722 | "isDeprecated": false, 1723 | "deprecationReason": null 1724 | }, 1725 | { 1726 | "name": "args", 1727 | "description": null, 1728 | "args": [], 1729 | "type": { 1730 | "kind": "NON_NULL", 1731 | "name": null, 1732 | "ofType": { 1733 | "kind": "LIST", 1734 | "name": null, 1735 | "ofType": { 1736 | "kind": "NON_NULL", 1737 | "name": null, 1738 | "ofType": { 1739 | "kind": "OBJECT", 1740 | "name": "__InputValue", 1741 | "ofType": null 1742 | } 1743 | } 1744 | } 1745 | }, 1746 | "isDeprecated": false, 1747 | "deprecationReason": null 1748 | }, 1749 | { 1750 | "name": "onOperation", 1751 | "description": null, 1752 | "args": [], 1753 | "type": { 1754 | "kind": "NON_NULL", 1755 | "name": null, 1756 | "ofType": { 1757 | "kind": "SCALAR", 1758 | "name": "Boolean", 1759 | "ofType": null 1760 | } 1761 | }, 1762 | "isDeprecated": true, 1763 | "deprecationReason": "Use `locations`." 1764 | }, 1765 | { 1766 | "name": "onFragment", 1767 | "description": null, 1768 | "args": [], 1769 | "type": { 1770 | "kind": "NON_NULL", 1771 | "name": null, 1772 | "ofType": { 1773 | "kind": "SCALAR", 1774 | "name": "Boolean", 1775 | "ofType": null 1776 | } 1777 | }, 1778 | "isDeprecated": true, 1779 | "deprecationReason": "Use `locations`." 1780 | }, 1781 | { 1782 | "name": "onField", 1783 | "description": null, 1784 | "args": [], 1785 | "type": { 1786 | "kind": "NON_NULL", 1787 | "name": null, 1788 | "ofType": { 1789 | "kind": "SCALAR", 1790 | "name": "Boolean", 1791 | "ofType": null 1792 | } 1793 | }, 1794 | "isDeprecated": true, 1795 | "deprecationReason": "Use `locations`." 1796 | } 1797 | ], 1798 | "inputFields": null, 1799 | "interfaces": [], 1800 | "enumValues": null, 1801 | "possibleTypes": null 1802 | }, 1803 | { 1804 | "kind": "ENUM", 1805 | "name": "__DirectiveLocation", 1806 | "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", 1807 | "fields": null, 1808 | "inputFields": null, 1809 | "interfaces": null, 1810 | "enumValues": [ 1811 | { 1812 | "name": "QUERY", 1813 | "description": "Location adjacent to a query operation.", 1814 | "isDeprecated": false, 1815 | "deprecationReason": null 1816 | }, 1817 | { 1818 | "name": "MUTATION", 1819 | "description": "Location adjacent to a mutation operation.", 1820 | "isDeprecated": false, 1821 | "deprecationReason": null 1822 | }, 1823 | { 1824 | "name": "SUBSCRIPTION", 1825 | "description": "Location adjacent to a subscription operation.", 1826 | "isDeprecated": false, 1827 | "deprecationReason": null 1828 | }, 1829 | { 1830 | "name": "FIELD", 1831 | "description": "Location adjacent to a field.", 1832 | "isDeprecated": false, 1833 | "deprecationReason": null 1834 | }, 1835 | { 1836 | "name": "FRAGMENT_DEFINITION", 1837 | "description": "Location adjacent to a fragment definition.", 1838 | "isDeprecated": false, 1839 | "deprecationReason": null 1840 | }, 1841 | { 1842 | "name": "FRAGMENT_SPREAD", 1843 | "description": "Location adjacent to a fragment spread.", 1844 | "isDeprecated": false, 1845 | "deprecationReason": null 1846 | }, 1847 | { 1848 | "name": "INLINE_FRAGMENT", 1849 | "description": "Location adjacent to an inline fragment.", 1850 | "isDeprecated": false, 1851 | "deprecationReason": null 1852 | }, 1853 | { 1854 | "name": "SCHEMA", 1855 | "description": "Location adjacent to a schema definition.", 1856 | "isDeprecated": false, 1857 | "deprecationReason": null 1858 | }, 1859 | { 1860 | "name": "SCALAR", 1861 | "description": "Location adjacent to a scalar definition.", 1862 | "isDeprecated": false, 1863 | "deprecationReason": null 1864 | }, 1865 | { 1866 | "name": "OBJECT", 1867 | "description": "Location adjacent to an object type definition.", 1868 | "isDeprecated": false, 1869 | "deprecationReason": null 1870 | }, 1871 | { 1872 | "name": "FIELD_DEFINITION", 1873 | "description": "Location adjacent to a field definition.", 1874 | "isDeprecated": false, 1875 | "deprecationReason": null 1876 | }, 1877 | { 1878 | "name": "ARGUMENT_DEFINITION", 1879 | "description": "Location adjacent to an argument definition.", 1880 | "isDeprecated": false, 1881 | "deprecationReason": null 1882 | }, 1883 | { 1884 | "name": "INTERFACE", 1885 | "description": "Location adjacent to an interface definition.", 1886 | "isDeprecated": false, 1887 | "deprecationReason": null 1888 | }, 1889 | { 1890 | "name": "UNION", 1891 | "description": "Location adjacent to a union definition.", 1892 | "isDeprecated": false, 1893 | "deprecationReason": null 1894 | }, 1895 | { 1896 | "name": "ENUM", 1897 | "description": "Location adjacent to an enum definition.", 1898 | "isDeprecated": false, 1899 | "deprecationReason": null 1900 | }, 1901 | { 1902 | "name": "ENUM_VALUE", 1903 | "description": "Location adjacent to an enum value definition.", 1904 | "isDeprecated": false, 1905 | "deprecationReason": null 1906 | }, 1907 | { 1908 | "name": "INPUT_OBJECT", 1909 | "description": "Location adjacent to an input object type definition.", 1910 | "isDeprecated": false, 1911 | "deprecationReason": null 1912 | }, 1913 | { 1914 | "name": "INPUT_FIELD_DEFINITION", 1915 | "description": "Location adjacent to an input object field definition.", 1916 | "isDeprecated": false, 1917 | "deprecationReason": null 1918 | } 1919 | ], 1920 | "possibleTypes": null 1921 | } 1922 | ], 1923 | "directives": [ 1924 | { 1925 | "name": "include", 1926 | "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", 1927 | "locations": [ 1928 | "FIELD", 1929 | "FRAGMENT_SPREAD", 1930 | "INLINE_FRAGMENT" 1931 | ], 1932 | "args": [ 1933 | { 1934 | "name": "if", 1935 | "description": "Included when true.", 1936 | "type": { 1937 | "kind": "NON_NULL", 1938 | "name": null, 1939 | "ofType": { 1940 | "kind": "SCALAR", 1941 | "name": "Boolean", 1942 | "ofType": null 1943 | } 1944 | }, 1945 | "defaultValue": null 1946 | } 1947 | ] 1948 | }, 1949 | { 1950 | "name": "skip", 1951 | "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", 1952 | "locations": [ 1953 | "FIELD", 1954 | "FRAGMENT_SPREAD", 1955 | "INLINE_FRAGMENT" 1956 | ], 1957 | "args": [ 1958 | { 1959 | "name": "if", 1960 | "description": "Skipped when true.", 1961 | "type": { 1962 | "kind": "NON_NULL", 1963 | "name": null, 1964 | "ofType": { 1965 | "kind": "SCALAR", 1966 | "name": "Boolean", 1967 | "ofType": null 1968 | } 1969 | }, 1970 | "defaultValue": null 1971 | } 1972 | ] 1973 | }, 1974 | { 1975 | "name": "deprecated", 1976 | "description": "Marks an element of a GraphQL schema as no longer supported.", 1977 | "locations": [ 1978 | "FIELD_DEFINITION", 1979 | "ENUM_VALUE" 1980 | ], 1981 | "args": [ 1982 | { 1983 | "name": "reason", 1984 | "description": "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted in [Markdown](https://daringfireball.net/projects/markdown/).", 1985 | "type": { 1986 | "kind": "SCALAR", 1987 | "name": "String", 1988 | "ofType": null 1989 | }, 1990 | "defaultValue": "\"No longer supported\"" 1991 | } 1992 | ] 1993 | } 1994 | ] 1995 | } 1996 | } 1997 | } --------------------------------------------------------------------------------