diff --git a/website/pages/docs/authentication-and-express-middleware.mdx b/website/pages/docs/authentication-and-express-middleware.mdx index c03f444496..4052f7ee26 100644 --- a/website/pages/docs/authentication-and-express-middleware.mdx +++ b/website/pages/docs/authentication-and-express-middleware.mdx @@ -61,7 +61,14 @@ const { const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', - fields: { ip: { type: GraphQLString } }, + fields: { + ip: { + type: GraphQLString, + resolve: (_, args, context) => { + return context.ip; + } + } + }, }), }); @@ -70,19 +77,12 @@ function loggingMiddleware(req, res, next) { next(); } -const root = { - ip(args, context) { - return context.ip; - }, -}; - const app = express(); app.use(loggingMiddleware); app.all( '/graphql', createHandler({ schema: schema, - rootValue: root, context: (req) => ({ ip: req.raw.ip, }), @@ -90,8 +90,8 @@ app.all( ); app.listen(4000); console.log('Running a GraphQL API server at localhost:4000/graphql'); -```` +``` diff --git a/website/pages/docs/basic-types.mdx b/website/pages/docs/basic-types.mdx index ea68466aa5..90f7c7f9cf 100644 --- a/website/pages/docs/basic-types.mdx +++ b/website/pages/docs/basic-types.mdx @@ -39,7 +39,7 @@ const root = { return Math.random(); }, rollThreeDice() { - return [1, 2, 3].map((\_) => 1 + Math.floor(Math.random() \* 6)); + return [1, 2, 3].map((_) => 1 + Math.floor(Math.random() * 6)); }, }; @@ -73,33 +73,27 @@ const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', fields: { - quoteOfTheDay: { type: GraphQLString }, - random: { type: GraphQLFloat }, - rollThreeDice: { type: new GraphQLList(GraphQLFloat) }, + quoteOfTheDay: { + type: GraphQLString, + resolve: () => Math.random() < 0.5 ? 'Take it easy' : 'Salvation lies within' + }, + random: { + type: GraphQLFloat, + resolve: () => Math.random() + }, + rollThreeDice: { + type: new GraphQLList(GraphQLFloat), + resolve: () => [1, 2, 3].map((_) => 1 + Math.floor(Math.random() * 6)) + }, }, }), }); -// The root provides a resolver function for each API endpoint -const root = { - quoteOfTheDay() { - return Math.random() < 0.5 ? 'Take it easy' : 'Salvation lies within'; - }, - random() { - return Math.random(); - }, - rollThreeDice() { - return [1, 2, 3].map((_) => 1 + Math.floor(Math.random() * 6)); - }, -}; - const app = express(); - app.all( '/graphql', createHandler({ schema: schema, - rootValue: root, }), ); diff --git a/website/pages/docs/constructing-types.mdx b/website/pages/docs/constructing-types.mdx index 2ae7b93872..2062ed4dad 100644 --- a/website/pages/docs/constructing-types.mdx +++ b/website/pages/docs/constructing-types.mdx @@ -86,7 +86,7 @@ const userType = new graphql.GraphQLObjectType({ }, }); -// Define the Query type +// Define the Query type with inline resolver const queryType = new graphql.GraphQLObjectType({ name: 'Query', fields: { diff --git a/website/pages/docs/getting-started.mdx b/website/pages/docs/getting-started.mdx index 5a9349879e..b813db40b4 100644 --- a/website/pages/docs/getting-started.mdx +++ b/website/pages/docs/getting-started.mdx @@ -28,7 +28,7 @@ npm install graphql --save ## Writing Code -To handle GraphQL queries, we need a schema that defines the `Query` type, and we need an API root with a function called a “resolver” for each API endpoint. For an API that just returns “Hello world!”, we can put this code in a file named `server.js`: +To handle GraphQL queries, we need a schema that defines the `Query` type, and we need an API root with a function called a "resolver" for each API endpoint. For an API that just returns "Hello world!", we can put this code in a file named `server.js`: @@ -54,7 +54,7 @@ graphql({ console.log(response); }); -```` +``` ```javascript @@ -65,29 +65,22 @@ const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', fields: { - hello: { type: GraphQLString }, + hello: { + type: GraphQLString, + resolve: () => 'Hello world!' + }, }, }), }); -// The rootValue provides a resolver function for each API endpoint -const rootValue = { - hello() { - return 'Hello world!'; - }, -}; - -// Run the GraphQL query '{ hello }' and print out the response graphql({ schema, source: '{ hello }', - rootValue, }).then((response) => { console.log(response); }); -```` - - +``` + If you run this with: @@ -108,4 +101,4 @@ You should see the GraphQL response printed out: Congratulations - you just executed a GraphQL query! -For practical applications, you'll probably want to run GraphQL queries from an API server, rather than executing GraphQL with a command line tool. To use GraphQL for an API server over HTTP, check out [Running an Express GraphQL Server](./running-an-express-graphql-server). +For practical applications, you'll probably want to run GraphQL queries from an API server, rather than executing GraphQL with a command line tool. To use GraphQL for an API server over HTTP, check out [Running an Express GraphQL Server](./running-an-express-graphql-server). \ No newline at end of file diff --git a/website/pages/docs/mutations-and-input-types.mdx b/website/pages/docs/mutations-and-input-types.mdx index 0971d1ae11..065ef37a9e 100644 --- a/website/pages/docs/mutations-and-input-types.mdx +++ b/website/pages/docs/mutations-and-input-types.mdx @@ -6,7 +6,7 @@ import { Tabs } from 'nextra/components'; If you have an API endpoint that alters data, like inserting data into a database or altering data already in a database, you should make this endpoint a `Mutation` rather than a `Query`. This is as simple as making the API endpoint part of the top-level `Mutation` type instead of the top-level `Query` type. -Let's say we have a “message of the day” server, where anyone can update the message of the day, and anyone can read the current one. The GraphQL schema for this is simply: +Let's say we have a "message of the day" server, where anyone can update the message of the day, and anyone can read the current one. The GraphQL schema for this is simply: @@ -18,7 +18,7 @@ type Mutation { type Query { getMessage: String } -```` +``` ```js @@ -42,7 +42,7 @@ const schema = new GraphQLSchema({ }, }), }); -```` +``` @@ -64,7 +64,7 @@ const root = { }; ``` -You don't need anything more than this to implement mutations. But in many cases, you will find a number of different mutations that all accept the same input parameters. A common example is that creating an object in a database and updating an object in a database often take the same parameters. To make your schema simpler, you can use “input types” for this, by using the `input` keyword instead of the `type` keyword. +You don't need anything more than this to implement mutations. But in many cases, you will find a number of different mutations that all accept the same input parameters. A common example is that creating an object in a database and updating an object in a database often take the same parameters. To make your schema simpler, you can use "input types" for this, by using the `input` keyword instead of the `type` keyword. For example, instead of a single message of the day, let's say we have many messages, indexed in a database by the `id` field, and each message has both a `content` string and an `author` string. We want a mutation API both for creating a new message and for updating an old message. We could use the schema: @@ -91,7 +91,7 @@ type Mutation { updateMessage(id: ID!, input: MessageInput): Message } -```` +``` ```js @@ -104,6 +104,9 @@ const { GraphQLNonNull, } = require('graphql'); +// Maps username to content +const fakeDatabase = {}; + const MessageInput = new GraphQLInputObjectType({ name: 'MessageInput', fields: { @@ -130,6 +133,16 @@ const schema = new GraphQLSchema({ args: { id: { type: new GraphQLNonNull(GraphQLID) }, }, + resolve: (_, { id }) => { + if (!fakeDatabase[id]) { + throw new Error('no message exists with id ' + id); + } + return fakeDatabase[id] ? { + id, + content: fakeDatabase[id].content, + author: fakeDatabase[id].author, + } : null; + } }, }, }), @@ -141,6 +154,16 @@ const schema = new GraphQLSchema({ args: { input: { type: new GraphQLNonNull(MessageInput) }, }, + resolve: (_, { input }) => { + // Create a random id for our "database". + const id = require('crypto').randomBytes(10).toString('hex'); + fakeDatabase[id] = input; + return { + id, + content: input.content, + author: input.author, + }; + } }, updateMessage: { type: Message, @@ -148,11 +171,23 @@ const schema = new GraphQLSchema({ id: { type: new GraphQLNonNull(GraphQLID) }, input: { type: new GraphQLNonNull(MessageInput) }, }, + resolve: (_, { id, input }) => { + if (!fakeDatabase[id]) { + throw new Error('no message exists with id ' + id); + } + // This replaces all old data, but some apps might want partial update. + fakeDatabase[id] = input; + return { + id, + content: input.content, + author: input.author, + }; + } }, }, }), }); -```` +``` @@ -204,46 +239,18 @@ class Message { } } -// Maps username to content -const fakeDatabase = {}; - -const root = { - getMessage({ id }) { - if (!fakeDatabase[id]) { - throw new Error('no message exists with id ' + id); - } - return new Message(id, fakeDatabase[id]); - }, - createMessage({ input }) { - // Create a random id for our "database". - const id = require('crypto').randomBytes(10).toString('hex'); - - fakeDatabase[id] = input; - return new Message(id, input); - }, - updateMessage({ id, input }) { - if (!fakeDatabase[id]) { - throw new Error('no message exists with id ' + id); - } - // This replaces all old data, but some apps might want partial update. - fakeDatabase[id] = input; - return new Message(id, input); - }, -}; - const app = express(); app.all( '/graphql', createHandler({ schema: schema, - rootValue: root, }), ); app.listen(4000, () => { console.log('Running a GraphQL API server at localhost:4000/graphql'); }); -```` +``` ```js @@ -258,6 +265,18 @@ const { GraphQLNonNull, } = require('graphql'); +// If Message had any complex fields, we'd put them on this object. +class Message { + constructor(id, { content, author }) { + this.id = id; + this.content = content; + this.author = author; + } +} + +// Maps username to content +const fakeDatabase = {}; + const MessageInput = new GraphQLInputObjectType({ name: 'MessageInput', fields: { @@ -284,6 +303,16 @@ const schema = new GraphQLSchema({ args: { id: { type: new GraphQLNonNull(GraphQLID) }, }, + resolve: (_, { id }) => { + if (!fakeDatabase[id]) { + throw new Error('no message exists with id ' + id); + } + return fakeDatabase[id] ? { + id, + content: fakeDatabase[id].content, + author: fakeDatabase[id].author, + } : null; + } }, }, }), @@ -295,6 +324,16 @@ const schema = new GraphQLSchema({ args: { input: { type: new GraphQLNonNull(MessageInput) }, }, + resolve: (_, { input }) => { + // Create a random id for our "database". + const id = require('crypto').randomBytes(10).toString('hex'); + fakeDatabase[id] = input; + return { + id, + content: input.content, + author: input.author, + }; + } }, updateMessage: { type: Message, @@ -302,59 +341,34 @@ const schema = new GraphQLSchema({ id: { type: new GraphQLNonNull(GraphQLID) }, input: { type: new GraphQLNonNull(MessageInput) }, }, + resolve: (_, { id, input }) => { + if (!fakeDatabase[id]) { + throw new Error('no message exists with id ' + id); + } + // This replaces all old data, but some apps might want partial update. + fakeDatabase[id] = input; + return { + id, + content: input.content, + author: input.author, + }; + } }, }, }), }); -// If Message had any complex fields, we'd put them on this object. -class Message { - constructor(id, { content, author }) { - this.id = id; - this.content = content; - this.author = author; - } -} - -// Maps username to content -const fakeDatabase = {}; - -const root = { - getMessage({ id }) { - if (!fakeDatabase[id]) { - throw new Error('no message exists with id ' + id); - } - return new Message(id, fakeDatabase[id]); - }, - createMessage({ input }) { - // Create a random id for our "database". - const id = require('crypto').randomBytes(10).toString('hex'); - - fakeDatabase[id] = input; - return new Message(id, input); - }, - updateMessage({ id, input }) { - if (!fakeDatabase[id]) { - throw new Error('no message exists with id ' + id); - } - // This replaces all old data, but some apps might want partial update. - fakeDatabase[id] = input; - return new Message(id, input); - }, -}; - const app = express(); app.all( '/graphql', createHandler({ schema: schema, - rootValue: root, }), ); app.listen(4000, () => { console.log('Running a GraphQL API server at localhost:4000/graphql'); }); -```` +``` diff --git a/website/pages/docs/object-types.mdx b/website/pages/docs/object-types.mdx index f425792ea8..ed0cfef5da 100644 --- a/website/pages/docs/object-types.mdx +++ b/website/pages/docs/object-types.mdx @@ -43,7 +43,6 @@ new GraphQLObjectType({ }, }, }) - ```` @@ -60,7 +59,7 @@ type RandomDie { type Query { getDie(numSides: Int): RandomDie } -```` +``` @@ -72,17 +71,37 @@ const { GraphQLString, GraphQLList, GraphQLFloat, + GraphQLSchema, } = require('graphql'); const RandomDie = new GraphQLObjectType({ name: 'RandomDie', fields: { + numSides: { + type: new GraphQLNonNull(GraphQLInt), + resolve: function(die) { + return die.numSides; + } + }, + rollOnce: { + type: new GraphQLNonNull(GraphQLInt), + resolve: function(die) { + return 1 + Math.floor(Math.random() * die.numSides); + } + }, roll: { type: new GraphQLList(GraphQLInt), args: { numRolls: { type: new GraphQLNonNull(GraphQLInt) + }, + }, + resolve: function(die, { numRolls }) { + const output = []; + for (let i = 0; i < numRolls; i++) { + output.push(1 + Math.floor(Math.random() * die.numSides)); } + return output; } } } @@ -98,13 +117,17 @@ const schema = new GraphQLSchema({ numSides: { type: GraphQLInt } + }, + resolve: (_, { numSides }) => { + return { + numSides: numSides || 6, + } } } } }) }); - -```` +``` @@ -134,7 +157,7 @@ const root = { return new RandomDie(numSides || 6); }, }; -```` +``` For fields that don't use any arguments, you can use either properties on the object or instance methods. So for the example code above, both `numSides` and `rollOnce` can actually be used to implement GraphQL fields, so that code also implements the schema of: @@ -148,9 +171,8 @@ type RandomDie { } type Query { -getDie(numSides: Int): RandomDie + getDie(numSides: Int): RandomDie } - ```` @@ -162,6 +184,7 @@ const { GraphQLString, GraphQLList, GraphQLFloat, + GraphQLSchema, } = require('graphql'); const RandomDie = new GraphQLObjectType({ @@ -169,9 +192,11 @@ const RandomDie = new GraphQLObjectType({ fields: { numSides: { type: new GraphQLNonNull(GraphQLInt), + resolve: (die) => die.numSides }, rollOnce: { type: new GraphQLNonNull(GraphQLInt), + resolve: (die) => 1 + Math.floor(Math.random() * die.numSides) }, roll: { type: new GraphQLList(GraphQLInt), @@ -179,6 +204,13 @@ const RandomDie = new GraphQLObjectType({ numRolls: { type: new GraphQLNonNull(GraphQLInt) }, + }, + resolve: (die, { numRolls }) => { + const output = []; + for (let i = 0; i < numRolls; i++) { + output.push(1 + Math.floor(Math.random() * die.numSides)); + } + return output; } } } @@ -194,6 +226,11 @@ const schema = new GraphQLSchema({ numSides: { type: GraphQLInt } + }, + resolve: (_, { numSides }) => { + return { + numSides: numSides || 6, + } } } } @@ -233,7 +270,7 @@ class RandomDie { } rollOnce() { - return 1 + Math.floor(Math.random() \* this.numSides); + return 1 + Math.floor(Math.random() * this.numSides); } roll({ numRolls }) { @@ -282,9 +319,11 @@ const RandomDie = new GraphQLObjectType({ fields: { numSides: { type: new GraphQLNonNull(GraphQLInt), + resolve: (die) => die.numSides }, rollOnce: { type: new GraphQLNonNull(GraphQLInt), + resolve: (die) => 1 + Math.floor(Math.random() * die.numSides) }, roll: { type: new GraphQLList(GraphQLInt), @@ -292,6 +331,13 @@ const RandomDie = new GraphQLObjectType({ numRolls: { type: new GraphQLNonNull(GraphQLInt) }, + }, + resolve: (die, { numRolls }) => { + const output = []; + for (let i = 0; i < numRolls; i++) { + output.push(1 + Math.floor(Math.random() * die.numSides)); + } + return output; } } } @@ -305,7 +351,12 @@ const schema = new GraphQLSchema({ type: RandomDie, args: { numSides: { - type: GraphQLInt + type: GraphQLInt, + } + }, + resolve: (_, { numSides }) => { + return { + numSides: numSides || 6, } } } @@ -313,44 +364,16 @@ const schema = new GraphQLSchema({ }) }); -// This class implements the RandomDie GraphQL type -class RandomDie { - constructor(numSides) { - this.numSides = numSides; - } - - rollOnce() { - return 1 + Math.floor(Math.random() * this.numSides); - } - - roll({ numRolls }) { - const output = []; - for (let i = 0; i < numRolls; i++) { - output.push(this.rollOnce()); - } - return output; - } -} - -// The root provides the top-level API endpoints -const root = { - getDie({ numSides }) { - return new RandomDie(numSides || 6); - }, -}; - const app = express(); app.all( '/graphql', createHandler({ schema: schema, - rootValue: root, }), ); app.listen(4000); console.log('Running a GraphQL API server at localhost:4000/graphql'); -```` - +``` diff --git a/website/pages/docs/passing-arguments.mdx b/website/pages/docs/passing-arguments.mdx index e3c300ef06..54d9489235 100644 --- a/website/pages/docs/passing-arguments.mdx +++ b/website/pages/docs/passing-arguments.mdx @@ -12,7 +12,7 @@ type Query { } ``` -Instead of hard coding “three”, we might want a more general function that rolls `numDice` dice, each of which have `numSides` sides. We can add arguments to the GraphQL schema language like this: +Instead of hard coding "three", we might want a more general function that rolls `numDice` dice, each of which have `numSides` sides. We can add arguments to the GraphQL schema language like this: @@ -24,39 +24,55 @@ type Query { ```js +const express = require('express'); +const { createHandler } = require('graphql-http/lib/use/express'); const { GraphQLObjectType, - GraphQLNonNull, - GraphQLInt, - GraphQLString, + GraphQLSchema, GraphQLList, GraphQLFloat, + GraphQLInt, + GraphQLNonNull, } = require('graphql'); -new GraphQLObjectType({ - name: 'Query', - fields: { - rollDice: { - type: new GraphQLList(GraphQLFloat), - args: { - numDice: { - type: new GraphQLNonNull(GraphQLInt) - }, - numSides: { - type: new GraphQLNonNull(GraphQLInt) +const schema = new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'Query', + fields: { + rollDice: { + type: new GraphQLList(GraphQLFloat), + args: { + numDice: { type: new GraphQLNonNull(GraphQLInt) }, + numSides: { type: GraphQLInt }, }, + resolve: (_, { numDice, numSides }) => { + const output = []; + for (let i = 0; i < numDice; i++) { + output.push(1 + Math.floor(Math.random() * (numSides || 6))); + } + return output; + } }, }, - }, -}) + }), +}); -```` +const app = express(); +app.all( + '/graphql', + createHandler({ + schema: schema, + }), +); +app.listen(4000); +console.log('Running a GraphQL API server at localhost:4000/graphql'); +``` The exclamation point in `Int!` indicates that `numDice` can't be null, which means we can skip a bit of validation logic to make our server code simpler. We can let `numSides` be null and assume that by default a die has 6 sides. -So far, our resolver functions took no arguments. When a resolver takes arguments, they are passed as one “args” object, as the first argument to the function. So rollDice could be implemented as: +So far, our resolver functions took no arguments. When a resolver takes arguments, they are passed as one "args" object, as the first argument to the function. So rollDice could be implemented as: ```js const root = { @@ -68,7 +84,7 @@ const root = { return output; }, }; -```` +``` It's convenient to use [ES6 destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) for these parameters, since you know what format they will be. So we can also write `rollDice` as @@ -119,8 +135,7 @@ app.all( ); app.listen(4000); console.log('Running a GraphQL API server at localhost:4000/graphql'); - -```` +``` ```js @@ -133,6 +148,7 @@ const { GraphQLString, GraphQLList, GraphQLFloat, + GraphQLSchema, } = require('graphql'); // Construct a schema, using GraphQL schema language @@ -150,34 +166,28 @@ const schema = new GraphQLSchema({ type: new GraphQLNonNull(GraphQLInt) }, }, + resolve: (_, { numDice, numSides }) => { + const output = []; + for (let i = 0; i < numDice; i++) { + output.push(1 + Math.floor(Math.random() * (numSides || 6))); + } + return output; + } }, }, }) }) -// The root provides a resolver function for each API endpoint -const root = { - rollDice({ numDice, numSides }) { - const output = []; - for (let i = 0; i < numDice; i++) { - output.push(1 + Math.floor(Math.random() * (numSides || 6))); - } - return output; - }, -}; - const app = express(); app.all( '/graphql', createHandler({ schema: schema, - rootValue: root, }), ); app.listen(4000); console.log('Running a GraphQL API server at localhost:4000/graphql'); -```` - +``` diff --git a/website/pages/docs/running-an-express-graphql-server.mdx b/website/pages/docs/running-an-express-graphql-server.mdx index e01dabb922..e9f03b0e11 100644 --- a/website/pages/docs/running-an-express-graphql-server.mdx +++ b/website/pages/docs/running-an-express-graphql-server.mdx @@ -11,7 +11,7 @@ The simplest way to run a GraphQL API server is to use [Express](https://express npm install express graphql-http graphql --save ``` -Let's modify our “hello world” example so that it's an API server rather than a script that runs a single query. We can use the 'express' module to run a webserver, and instead of executing a query directly with the `graphql` function, we can use the `graphql-http` library to mount a GraphQL API server on the “/graphql” HTTP endpoint: +Let's modify our "hello world" example so that it's an API server rather than a script that runs a single query. We can use the 'express' module to run a webserver, and instead of executing a query directly with the `graphql` function, we can use the `graphql-http` library to mount a GraphQL API server on the "/graphql" HTTP endpoint: @@ -45,11 +45,11 @@ app.all( app.listen(4000); console.log('Running a GraphQL API server at http://localhost:4000/graphql'); -```` +``` ```javascript -const { GraphQLObjectType, GraphQLSchema } = require('graphql'); +const { GraphQLObjectType, GraphQLSchema, GraphQLString } = require('graphql'); const { createHandler } = require('graphql-http/lib/use/express'); const express = require('express'); @@ -58,18 +58,14 @@ const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', fields: { - hello: { type: GraphQLString }, + hello: { + type: GraphQLString, + resolve: () => 'Hello world!' + }, }, }), }); -// The root provides a resolver function for each API endpoint -const root = { - hello() { - return 'Hello world!'; - }, -}; - const app = express(); // Create and use the GraphQL handler. @@ -77,16 +73,15 @@ app.all( '/graphql', createHandler({ schema: schema, - rootValue: root, }), ); // Start the server at port app.listen(4000); console.log('Running a GraphQL API server at http://localhost:4000/graphql'); -```` - +``` + You can run this GraphQL server with: