From 9ab408e9f9737b75ff6154cc66900299811bd50d Mon Sep 17 00:00:00 2001 From: sarahxsanders Date: Mon, 9 Jun 2025 20:29:16 -0400 Subject: [PATCH] modernize js code samples --- .../authentication-and-express-middleware.mdx | 34 +++--- src/pages/graphql-js/basic-types.mdx | 30 ++--- src/pages/graphql-js/constructing-types.mdx | 72 ++++++------ src/pages/graphql-js/graphql-clients.mdx | 31 ++++-- src/pages/graphql-js/language.mdx | 40 +++---- .../graphql-js/mutations-and-input-types.mdx | 93 ++++++++-------- src/pages/graphql-js/object-types.mdx | 57 +++++----- src/pages/graphql-js/passing-arguments.mdx | 58 ++++++---- .../running-an-express-graphql-server.mdx | 43 ++++---- src/pages/graphql-js/type.mdx | 103 +++++++++++------- src/pages/graphql-js/utilities.mdx | 2 +- src/pages/learn/authorization.mdx | 33 +++--- src/pages/learn/execution.mdx | 34 +++--- src/pages/learn/index.mdx | 12 +- src/pages/learn/mutations.mdx | 10 +- 15 files changed, 357 insertions(+), 295 deletions(-) diff --git a/src/pages/graphql-js/authentication-and-express-middleware.mdx b/src/pages/graphql-js/authentication-and-express-middleware.mdx index 617eb0fa05..0f3cd9df6d 100644 --- a/src/pages/graphql-js/authentication-and-express-middleware.mdx +++ b/src/pages/graphql-js/authentication-and-express-middleware.mdx @@ -10,41 +10,41 @@ To use middleware with a GraphQL resolver, just use the middleware like you woul For example, let's say we wanted our server to log the IP address of every request, and we also want to write an API that returns the IP address of the caller. We can do the former with middleware, and the latter by accessing the `request` object in a resolver. Here's server code that implements this: ```js -var express = require("express") -var { createHandler } = require("graphql-http/lib/use/express") -var { buildSchema } = require("graphql") +import express from "express"; +import { createHandler } from "graphql-http/lib/use/express"; +import { buildSchema } from "graphql"; -var schema = buildSchema(` +const schema = buildSchema(` type Query { ip: String } -`) +`); function loggingMiddleware(req, res, next) { - console.log("ip:", req.ip) - next() + console.log("ip:", req.ip); + next(); } -var root = { +const root = { ip(args, context) { - return context.ip + return context.ip; }, -} +}; -var app = express() -app.use(loggingMiddleware) +const app = express(); +app.use(loggingMiddleware); app.all( "/graphql", createHandler({ - schema: schema, + schema, rootValue: root, - context: req => ({ + context: (req) => ({ ip: req.raw.ip, }), }) -) -app.listen(4000) -console.log("Running a GraphQL API server at localhost:4000/graphql") +); +app.listen(4000); +console.log("Running a GraphQL API server at localhost:4000/graphql"); ``` In a REST API, authentication is often handled with a header, that contains an auth token which proves what user is making this request. Express middleware processes these headers and puts authentication data on the Express `request` object. Some middleware modules that handle authentication like this are [Passport](http://passportjs.org/), [express-jwt](https://github.com/auth0/express-jwt), and [express-session](https://github.com/expressjs/session). Each of these modules works with `graphql-http`. diff --git a/src/pages/graphql-js/basic-types.mdx b/src/pages/graphql-js/basic-types.mdx index 37339d0f9c..e28f487721 100644 --- a/src/pages/graphql-js/basic-types.mdx +++ b/src/pages/graphql-js/basic-types.mdx @@ -13,42 +13,42 @@ To use a list type, surround the type in square brackets, so `[Int]` is a list o Each of these types maps straightforwardly to JavaScript, so you can just return plain old JavaScript objects in APIs that return these types. Here's an example that shows how to use some of these basic types: ```js -var express = require("express") -var { createHandler } = require("graphql-http/lib/use/express") -var { buildSchema } = require("graphql") +import express from "express"; +import { createHandler } from "graphql-http/lib/use/express"; +import { buildSchema } from "graphql"; // Construct a schema, using GraphQL schema language -var schema = buildSchema(` +const schema = buildSchema(` type Query { quoteOfTheDay: String random: Float! rollThreeDice: [Int] } -`) +`); // The root provides a resolver function for each API endpoint -var root = { +const root = { quoteOfTheDay() { - return Math.random() < 0.5 ? "Take it easy" : "Salvation lies within" + return Math.random() < 0.5 ? "Take it easy" : "Salvation lies within"; }, random() { - return Math.random() + 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)); }, -} +}; -var app = express() +const app = express(); app.all( "/graphql", createHandler({ - schema: schema, + schema, rootValue: root, }) -) -app.listen(4000) -console.log("Running a GraphQL API server at localhost:4000/graphql") +); +app.listen(4000); +console.log("Running a GraphQL API server at localhost:4000/graphql"); ``` If you run this code with `node server.js` and browse to http://localhost:4000/graphql you can try out these APIs. diff --git a/src/pages/graphql-js/constructing-types.mdx b/src/pages/graphql-js/constructing-types.mdx index 1352adfbc9..5ffdcb1425 100644 --- a/src/pages/graphql-js/constructing-types.mdx +++ b/src/pages/graphql-js/constructing-types.mdx @@ -9,11 +9,11 @@ When you are using the `GraphQLSchema` constructor to create a schema, instead o For example, let's say we are building a simple API that lets you fetch user data for a few hardcoded users based on an id. Using `buildSchema` we could write a server with: ```js -var express = require("express") -var { createHandler } = require("graphql-http/lib/use/express") -var { buildSchema } = require("graphql") +import express from "express"; +import { createHandler } from "graphql-http/lib/use/express"; +import { buildSchema } from "graphql"; -var schema = buildSchema(` +const schema = buildSchema(` type User { id: String name: String @@ -22,10 +22,10 @@ var schema = buildSchema(` type Query { user(id: String): User } -`) +`); // Maps id to User object -var fakeDatabase = { +const fakeDatabase = { a: { id: "a", name: "alice", @@ -34,35 +34,39 @@ var fakeDatabase = { id: "b", name: "bob", }, -} +}; -var root = { +const root = { user({ id }) { - return fakeDatabase[id] + return fakeDatabase[id]; }, -} +}; -var app = express() +const app = express(); app.all( "/graphql", createHandler({ - schema: schema, + schema, rootValue: root, }) -) -app.listen(4000) -console.log("Running a GraphQL API server at localhost:4000/graphql") +); +app.listen(4000); +console.log("Running a GraphQL API server at localhost:4000/graphql"); ``` We can implement this same API without using GraphQL schema language: ```js -var express = require("express") -var { createHandler } = require("graphql-http/lib/use/express") -var graphql = require("graphql") +import express from "express"; +import { createHandler } from "graphql-http/lib/use/express"; +import { + GraphQLObjectType, + GraphQLString, + GraphQLSchema, +} from "graphql"; // Maps id to User object -var fakeDatabase = { +const fakeDatabase = { a: { id: "a", name: "alice", @@ -71,45 +75,45 @@ var fakeDatabase = { id: "b", name: "bob", }, -} +}; // Define the User type -var userType = new graphql.GraphQLObjectType({ +const userType = new GraphQLObjectType({ name: "User", fields: { - id: { type: graphql.GraphQLString }, - name: { type: graphql.GraphQLString }, + id: { type: GraphQLString }, + name: { type: GraphQLString }, }, -}) +}); // Define the Query type -var queryType = new graphql.GraphQLObjectType({ +const queryType = new GraphQLObjectType({ name: "Query", fields: { user: { type: userType, // `args` describes the arguments that the `user` query accepts args: { - id: { type: graphql.GraphQLString }, + id: { type: GraphQLString }, }, resolve: (_, { id }) => { - return fakeDatabase[id] + return fakeDatabase[id]; }, }, }, -}) +}); -var schema = new graphql.GraphQLSchema({ query: queryType }) +const schema = new GraphQLSchema({ query: queryType }); -var app = express() +const app = express(); app.all( "/graphql", createHandler({ - schema: schema, + schema, }) -) -app.listen(4000) -console.log("Running a GraphQL API server at localhost:4000/graphql") +); +app.listen(4000); +console.log("Running a GraphQL API server at localhost:4000/graphql"); ``` When we use this method of creating the API, the root level resolvers are implemented on the `Query` and `Mutation` types rather than on a `root` object. diff --git a/src/pages/graphql-js/graphql-clients.mdx b/src/pages/graphql-js/graphql-clients.mdx index b97162a037..7da0e87570 100644 --- a/src/pages/graphql-js/graphql-clients.mdx +++ b/src/pages/graphql-js/graphql-clients.mdx @@ -32,8 +32,13 @@ fetch("/graphql", { }, body: JSON.stringify({ query: "{ hello }" }), }) - .then(r => r.json()) - .then(data => console.log("data returned:", data)) + .then(response => response.json()) + .then(data => { + console.log("Data returned:", data); + }) + .catch(error => { + console.error("Request failed:", error); + }); ``` You should see the data returned, logged in the console: @@ -55,11 +60,14 @@ type Query { You could access this from JavaScript with the code: ```js -var dice = 3 -var sides = 6 -var query = /* GraphQL */`query RollDice($dice: Int!, $sides: Int) { - rollDice(numDice: $dice, numSides: $sides) -}` +const dice = 3; +const sides = 6; + +const query = /* GraphQL */ ` + query RollDice($dice: Int!, $sides: Int) { + rollDice(numDice: $dice, numSides: $sides) + } +`; fetch("/graphql", { method: "POST", @@ -72,8 +80,13 @@ fetch("/graphql", { variables: { dice, sides }, }), }) - .then(r => r.json()) - .then(data => console.log("data returned:", data)) + .then(response => response.json()) + .then(data => { + console.log("Data returned:", data); + }) + .catch(error => { + console.error("Request failed:", error); + }); ``` Using this syntax for variables is a good idea because it automatically prevents bugs due to escaping, and it makes it easier to monitor your server. diff --git a/src/pages/graphql-js/language.mdx b/src/pages/graphql-js/language.mdx index b1bb642e1d..6c1cd010af 100644 --- a/src/pages/graphql-js/language.mdx +++ b/src/pages/graphql-js/language.mdx @@ -198,7 +198,9 @@ a new version of the AST with the changes applied will be returned from the visit function. ```js -var editedAST = visit(ast, { +import { visit } from "graphql"; + +const editedAST = visit(ast, { enter(node, key, parent, path, ancestors) { // @return // undefined: no action @@ -215,7 +217,7 @@ var editedAST = visit(ast, { // null: delete this node // any value: replace this node with the returned value }, -}) +}); ``` Alternatively to providing enter() and leave() functions, a visitor can @@ -227,10 +229,10 @@ visitor API: ```js visit(ast, { - Kind(node) { - // enter the "Kind" node + Field(node) { + console.log("Visiting a Field node:", node.name.value); }, -}) +}); ``` 2. Named visitors that trigger upon entering and leaving a node of @@ -238,15 +240,15 @@ visit(ast, { ```js visit(ast, { - Kind: { + Field: { enter(node) { - // enter the "Kind" node + console.log("Entering Field:", node.name.value); }, leave(node) { - // leave the "Kind" node - } - } -}) + console.log("Leaving Field:", node.name.value); + }, + }, +}); ``` 3. Generic visitors that trigger upon entering and leaving any node. @@ -254,12 +256,12 @@ visit(ast, { ```js visit(ast, { enter(node) { - // enter any node + console.log("Entering", node.kind); }, leave(node) { - // leave any node + console.log("Leaving", node.kind); }, -}) +}); ``` 4. Parallel visitors for entering and leaving nodes of a specific kind. @@ -267,16 +269,16 @@ visit(ast, { ```js visit(ast, { enter: { - Kind(node) { - // enter the "Kind" node + Name(node) { + console.log("Entering a Name node:", node.value); }, }, leave: { - Kind(node) { - // leave the "Kind" node + Name(node) { + console.log("Leaving a Name node:", node.value); }, }, -}) +}); ``` ### `BREAK` diff --git a/src/pages/graphql-js/mutations-and-input-types.mdx b/src/pages/graphql-js/mutations-and-input-types.mdx index 2b61c733bf..7a366e83a8 100644 --- a/src/pages/graphql-js/mutations-and-input-types.mdx +++ b/src/pages/graphql-js/mutations-and-input-types.mdx @@ -21,16 +21,17 @@ It's often convenient to have a mutation that maps to a database create or updat Both mutations and queries can be handled by root resolvers, so the root that implements this schema can simply be: ```js -var fakeDatabase = {} -var root = { +const fakeDatabase = {}; + +const root = { setMessage({ message }) { - fakeDatabase.message = message - return message + fakeDatabase.message = message; + return message; }, getMessage() { - return fakeDatabase.message + return fakeDatabase.message; }, -} +}; ``` 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. @@ -68,12 +69,13 @@ Naming input types with `Input` on the end is a useful convention, because you w Here's some runnable code that implements this schema, keeping the data in memory: ```js -var express = require("express") -var { createHandler } = require("graphql-http/lib/use/express") -var { buildSchema } = require("graphql") +import express from "express"; +import { createHandler } from "graphql-http/lib/use/express"; +import { buildSchema } from "graphql"; +import { randomBytes } from "crypto"; -// Construct a schema, using GraphQL schema language -var schema = buildSchema(/* GraphQL */` +// Construct a schema using GraphQL schema language +const schema = buildSchema(/* GraphQL */ ` input MessageInput { content: String author: String @@ -93,55 +95,52 @@ var schema = buildSchema(/* GraphQL */` createMessage(input: MessageInput): Message updateMessage(id: ID!, input: MessageInput): Message } -`) +`); // 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 + this.id = id; + this.content = content; + this.author = author; } } -// Maps username to content -var fakeDatabase = {} +// Fake in-memory database +const fakeDatabase = {}; -var root = { +const root = { getMessage({ id }) { if (!fakeDatabase[id]) { - throw new Error("no message exists with id " + id) + throw new Error("No message exists with id " + id); } - return new Message(id, fakeDatabase[id]) + return new Message(id, fakeDatabase[id]); }, createMessage({ input }) { - // Create a random id for our "database". - var id = require("crypto").randomBytes(10).toString("hex") - - fakeDatabase[id] = input - return new Message(id, input) + const id = 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) + 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) + fakeDatabase[id] = input; + return new Message(id, input); }, -} +}; -var app = express() +const app = express(); app.all( "/graphql", createHandler({ - schema: schema, + schema, rootValue: root, }) -) +); app.listen(4000, () => { - console.log("Running a GraphQL API server at localhost:4000/graphql") -}) + console.log("Running a GraphQL API server at localhost:4000/graphql"); +}); ``` To call a mutation, you must use the keyword `mutation` before your GraphQL query. To pass an input type, provide the data written as if it's a JSON object. For example, with the server defined above, you can create a new message and return the `id` of the new message with this operation: @@ -160,13 +159,16 @@ mutation { You can use variables to simplify mutation client logic just like you can with queries. For example, some JavaScript code that calls the server to execute this mutation is: ```js -var author = "andy" -var content = "hope is a good thing" -var query = /* GraphQL */`mutation CreateMessage($input: MessageInput) { - createMessage(input: $input) { - id +const author = "andy"; +const content = "hope is a good thing"; + +const query = /* GraphQL */ ` + mutation CreateMessage($input: MessageInput) { + createMessage(input: $input) { + id + } } -}` +`; fetch("/graphql", { method: "POST", @@ -184,8 +186,13 @@ fetch("/graphql", { }, }), }) - .then(r => r.json()) - .then(data => console.log("data returned:", data)) + .then(response => response.json()) + .then(data => { + console.log("Data returned:", data); + }) + .catch(error => { + console.error("Request failed:", error); + }); ``` One particular type of mutation is operations that change users, like signing up a new user. While you can implement this using GraphQL mutations, you can reuse many existing libraries if you learn about [GraphQL with authentication and Express middleware](/graphql-js/authentication-and-express-middleware/). diff --git a/src/pages/graphql-js/object-types.mdx b/src/pages/graphql-js/object-types.mdx index e54439ea91..b568e2f99d 100644 --- a/src/pages/graphql-js/object-types.mdx +++ b/src/pages/graphql-js/object-types.mdx @@ -29,27 +29,27 @@ Instead of a root-level resolver for the `RandomDie` type, we can instead use an ```js class RandomDie { constructor(numSides) { - this.numSides = numSides + this.numSides = numSides; } rollOnce() { - return 1 + Math.floor(Math.random() * this.numSides) + return 1 + Math.floor(Math.random() * this.numSides); } roll({ numRolls }) { - var output = [] - for (var i = 0; i < numRolls; i++) { - output.push(this.rollOnce()) + const output = []; + for (let i = 0; i < numRolls; i++) { + output.push(this.rollOnce()); } - return output + return output; } } -var root = { +const root = { getDie({ numSides }) { - return new RandomDie(numSides || 6) + 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: @@ -69,12 +69,12 @@ type Query { Putting this all together, here is some sample code that runs a server with this GraphQL API: ```js -var express = require("express") -var { createHandler } = require("graphql-http/lib/use/express") -var { buildSchema } = require("graphql") +import express from "express"; +import { createHandler } from "graphql-http/lib/use/express"; +import { buildSchema } from "graphql"; // Construct a schema, using GraphQL schema language -var schema = buildSchema(/* GraphQL */` +const schema = buildSchema(/* GraphQL */ ` type RandomDie { numSides: Int! rollOnce: Int! @@ -84,44 +84,45 @@ var schema = buildSchema(/* GraphQL */` type Query { getDie(numSides: Int): RandomDie } -`) +`); // This class implements the RandomDie GraphQL type class RandomDie { constructor(numSides) { - this.numSides = numSides + this.numSides = numSides; } rollOnce() { - return 1 + Math.floor(Math.random() * this.numSides) + return 1 + Math.floor(Math.random() * this.numSides); } roll({ numRolls }) { - var output = [] - for (var i = 0; i < numRolls; i++) { - output.push(this.rollOnce()) + const output = []; + for (let i = 0; i < numRolls; i++) { + output.push(this.rollOnce()); } - return output + return output; } } // The root provides the top-level API endpoints -var root = { +const root = { getDie({ numSides }) { - return new RandomDie(numSides || 6) + return new RandomDie(numSides || 6); }, -} +}; -var app = express() +const app = express(); app.all( "/graphql", createHandler({ - schema: schema, + schema, rootValue: root, }) -) -app.listen(4000) -console.log("Running a GraphQL API server at localhost:4000/graphql") +); +app.listen(4000, () => { + console.log("Running a GraphQL API server at localhost:4000/graphql"); +}); ``` When you issue a GraphQL query against an API that returns object types, you can call multiple methods on the object at once by nesting the GraphQL field names. For example, if you wanted to call both `rollOnce` to roll a die once, and `roll` to roll a die three times, you could do it with this query: diff --git a/src/pages/graphql-js/passing-arguments.mdx b/src/pages/graphql-js/passing-arguments.mdx index 4878410b0c..0fd38b4fa1 100644 --- a/src/pages/graphql-js/passing-arguments.mdx +++ b/src/pages/graphql-js/passing-arguments.mdx @@ -53,38 +53,40 @@ If you're familiar with destructuring, this is a bit nicer because the line of c The entire code for a server that hosts this `rollDice` API is: ```js -var express = require("express") -var { createHandler } = require("graphql-http/lib/use/express") -var { buildSchema } = require("graphql") +import express from "express"; +import { createHandler } from "graphql-http/lib/use/express"; +import { buildSchema } from "graphql"; -// Construct a schema, using GraphQL schema language -var schema = buildSchema(/* GraphQL */` +// Construct a schema using GraphQL schema language +const schema = buildSchema(/* GraphQL */ ` type Query { rollDice(numDice: Int!, numSides: Int): [Int] } -`) +`); // The root provides a resolver function for each API endpoint -var root = { +const root = { rollDice({ numDice, numSides }) { - var output = [] - for (var i = 0; i < numDice; i++) { - output.push(1 + Math.floor(Math.random() * (numSides || 6))) + const output = []; + const sides = numSides || 6; + for (let i = 0; i < numDice; i++) { + output.push(1 + Math.floor(Math.random() * sides)); } - return output + return output; }, -} +}; -var app = express() +const app = express(); app.all( "/graphql", createHandler({ - schema: schema, + schema, rootValue: root, }) -) -app.listen(4000) -console.log("Running a GraphQL API server at localhost:4000/graphql") +); +app.listen(4000, () => { + console.log("Running a GraphQL API server at localhost:4000/graphql"); +}); ``` When you call this API, you have to pass each argument by name. So for the server above, you could issue this GraphQL query to roll three six-sided dice: @@ -102,11 +104,14 @@ When you're passing arguments in code, it's generally better to avoid constructi For example, some JavaScript code that calls our server above is: ```js -var dice = 3 -var sides = 6 -var query = /* GraphQL */`query RollDice($dice: Int!, $sides: Int) { - rollDice(numDice: $dice, numSides: $sides) -}` +const dice = 3; +const sides = 6; + +const query = /* GraphQL */ ` + query RollDice($dice: Int!, $sides: Int) { + rollDice(numDice: $dice, numSides: $sides) + } +`; fetch("/graphql", { method: "POST", @@ -119,8 +124,13 @@ fetch("/graphql", { variables: { dice, sides }, }), }) - .then(r => r.json()) - .then(data => console.log("data returned:", data)) + .then(response => response.json()) + .then(data => { + console.log("Data returned:", data); + }) + .catch(error => { + console.error("Request failed:", error); + }); ``` Using `$dice` and `$sides` as variables in GraphQL means we don't have to worry about escaping on the client side. diff --git a/src/pages/graphql-js/running-an-express-graphql-server.mdx b/src/pages/graphql-js/running-an-express-graphql-server.mdx index 230b67a5e9..6789f42b51 100644 --- a/src/pages/graphql-js/running-an-express-graphql-server.mdx +++ b/src/pages/graphql-js/running-an-express-graphql-server.mdx @@ -12,38 +12,39 @@ 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: ```js -var express = require("express") -var { createHandler } = require("graphql-http/lib/use/express") -var { buildSchema } = require("graphql") +import express from "express"; +import { createHandler } from "graphql-http/lib/use/express"; +import { buildSchema } from "graphql"; -// Construct a schema, using GraphQL schema language -var schema = buildSchema(` +// Construct a schema using GraphQL schema language +const schema = buildSchema(` type Query { hello: String } -`) +`); // The root provides a resolver function for each API endpoint -var root = { +const root = { hello() { - return "Hello world!" + return "Hello world!"; }, -} +}; -var app = express() +const app = express(); -// Create and use the GraphQL handler. +// Create and use the GraphQL handler app.all( "/graphql", createHandler({ - schema: schema, + schema, rootValue: root, }) -) +); -// Start the server at port -app.listen(4000) -console.log("Running a GraphQL API server at http://localhost:4000/graphql") +// Start the server at port 4000 +app.listen(4000, () => { + console.log("Running a GraphQL API server at http://localhost:4000/graphql"); +}); ``` You can run this GraphQL server with: @@ -61,13 +62,13 @@ One easy way to add it to your server is via the MIT-licensed [ruru](https://git To do so, install the `ruru` module with `npm install --save ruru` and then add the following to your `server.js` file, then restart the `node server.js` command: ```js -var { ruruHTML } = require("ruru/server") +import { ruruHTML } from "ruru/server"; -// Serve the GraphiQL IDE. +// Serve the GraphiQL IDE app.get("/", (_req, res) => { - res.type("html") - res.end(ruruHTML({ endpoint: "/graphql" })) -}) + res.type("html"); + res.end(ruruHTML({ endpoint: "/graphql" })); +}); ``` If you navigate to [http://localhost:4000](http://localhost:4000), you should see an interface that lets you enter queries; diff --git a/src/pages/graphql-js/type.mdx b/src/pages/graphql-js/type.mdx index d3cc9619ad..186879e460 100644 --- a/src/pages/graphql-js/type.mdx +++ b/src/pages/graphql-js/type.mdx @@ -125,9 +125,11 @@ validator and executor. #### Example ```js -var MyAppSchema = new GraphQLSchema({ +import { GraphQLSchema } from "graphql"; + +const MyAppSchema = new GraphQLSchema({ query: MyAppQueryRootType, - mutation: MyAppMutationRootType + mutation: MyAppMutationRootType, }); ``` @@ -156,21 +158,23 @@ functions used to ensure validity. #### Example ```js -var OddType = new GraphQLScalarType({ +import { GraphQLScalarType, Kind } from "graphql"; + +function oddValue(value) { + return value % 2 === 1 ? value : null; +} + +const OddType = new GraphQLScalarType({ name: "Odd", serialize: oddValue, parseValue: oddValue, parseLiteral(ast) { if (ast.kind === Kind.INT) { - return oddValue(parseInt(ast.value, 10)) + return oddValue(parseInt(ast.value, 10)); } - return null - } -}) - -function oddValue(value) { - return value % 2 === 1 ? value : null -} + return null; + }, +}); ``` ### GraphQLObjectType @@ -251,7 +255,9 @@ that value can always be referenced with `this`. #### Examples ```js -var AddressType = new GraphQLObjectType({ +import { GraphQLObjectType, GraphQLString, GraphQLInt } from "graphql"; + +const AddressType = new GraphQLObjectType({ name: "Address", fields: { street: { type: GraphQLString }, @@ -259,19 +265,19 @@ var AddressType = new GraphQLObjectType({ formatted: { type: GraphQLString, resolve(obj) { - return obj.number + " " + obj.street - } - } - } -}) + return `${obj.number} ${obj.street}`; + }, + }, + }, +}); -var PersonType = new GraphQLObjectType({ +const PersonType = new GraphQLObjectType({ name: "Person", fields: () => ({ name: { type: GraphQLString }, - bestFriend: { type: PersonType } - }) -}) + bestFriend: { type: PersonType }, + }), +}); ``` ### GraphQLInterfaceType @@ -297,12 +303,14 @@ when the field is resolved. #### Example ```js -var EntityType = new GraphQLInterfaceType({ +import { GraphQLInterfaceType, GraphQLString } from "graphql"; + +const EntityType = new GraphQLInterfaceType({ name: "Entity", fields: { - name: { type: GraphQLString } - } -}) + name: { type: GraphQLString }, + }, +}); ``` ### GraphQLUnionType @@ -329,18 +337,21 @@ to determine which type is actually used when the field is resolved. ### Example ```js -var PetType = new GraphQLUnionType({ +import { GraphQLUnionType } from "graphql"; + +const PetType = new GraphQLUnionType({ name: "Pet", types: [DogType, CatType], resolveType(value) { if (value instanceof Dog) { - return DogType + return DogType; } if (value instanceof Cat) { - return CatType + return CatType; } + return null; }, -}) +}); ``` ### GraphQLEnumType @@ -384,14 +395,16 @@ will be used as its internal value. #### Example ```js -var RGBType = new GraphQLEnumType({ +import { GraphQLEnumType } from "graphql"; + +const RGBType = new GraphQLEnumType({ name: "RGB", values: { RED: { value: 0 }, GREEN: { value: 1 }, BLUE: { value: 2 }, }, -}) +}); ``` ### GraphQLInputObjectType @@ -439,14 +452,20 @@ Using `NonNull` will ensure that a value must be provided by the query #### Example ```js -var GeoPoint = new GraphQLInputObjectType({ +import { + GraphQLInputObjectType, + GraphQLNonNull, + GraphQLFloat, +} from "graphql"; + +const GeoPoint = new GraphQLInputObjectType({ name: "GeoPoint", fields: { lat: { type: new GraphQLNonNull(GraphQLFloat) }, lon: { type: new GraphQLNonNull(GraphQLFloat) }, alt: { type: GraphQLFloat, defaultValue: 0 }, }, -}) +}); ``` ### GraphQLList @@ -464,13 +483,15 @@ an object type. #### Example ```js -var PersonType = new GraphQLObjectType({ +import { GraphQLObjectType, GraphQLList } from "graphql"; + +const PersonType = new GraphQLObjectType({ name: "Person", fields: () => ({ parents: { type: new GraphQLList(PersonType) }, children: { type: new GraphQLList(PersonType) }, }), -}) +}); ``` ### GraphQLNonNull @@ -490,12 +511,18 @@ usually the id field of a database row will never be null. #### Example ```js -var RowType = new GraphQLObjectType({ +import { + GraphQLObjectType, + GraphQLNonNull, + GraphQLString, +} from "graphql"; + +const RowType = new GraphQLObjectType({ name: "Row", fields: () => ({ - id: { type: new GraphQLNonNull(String) }, + id: { type: new GraphQLNonNull(GraphQLString) }, }), -}) +}); ``` ## Predicates diff --git a/src/pages/graphql-js/utilities.mdx b/src/pages/graphql-js/utilities.mdx index ed8f5cb229..f55c9d9216 100644 --- a/src/pages/graphql-js/utilities.mdx +++ b/src/pages/graphql-js/utilities.mdx @@ -96,7 +96,7 @@ var { introspectionQuery } = require("graphql") // CommonJS ### introspectionQuery ```js -var introspectionQuery: string +const introspectionQuery = `...`; // a GraphQL introspection query string ``` A GraphQL query that queries a server's introspection system for enough diff --git a/src/pages/learn/authorization.mdx b/src/pages/learn/authorization.mdx index f23fab82ef..8ca5e0b6ec 100644 --- a/src/pages/learn/authorization.mdx +++ b/src/pages/learn/authorization.mdx @@ -25,11 +25,11 @@ If a post's body should only be visible to the user who authored it, then we wil ```js function Post_body(obj, args, context, info) { - // return the post body only if the user is the post's author - if (context.user && (context.user.id === obj.authorId)) { - return obj.body + // Return the post body only if the user is the post's author + if (context.user && context.user.id === obj.authorId) { + return obj.body; } - return null + return null; } ``` @@ -38,25 +38,26 @@ Notice that we define "author owns a post" by checking whether the post's `autho Defining authorization logic inside the resolver is fine when learning GraphQL or prototyping. However, for a production codebase, delegate authorization logic to the business logic layer. Here’s an example of how authorization of the `Post` type's fields could be implemented separately: ```js -// authorization logic lives inside `postRepository` +// Authorization logic lives inside `postRepository` export const postRepository = { getBody({ user, post }) { - if (user?.id && (user.id === post.authorId)) { - return post.body - } - return null - } -} + const isAuthor = user?.id === post.authorId; + return isAuthor ? post.body : null; + }, +}; ``` The resolver function for the post's `body` field would then call a `postRepository` method instead of implementing the authorization logic directly: ```js -import { postRepository } from 'postRepository' - -function Post_body(obj, args, context, info) { - // return the post body only if the user is the post's author - return postRepository.getBody({ user: context.user, post: obj }) +import { postRepository } from "postRepository"; + +function resolvePostBody(obj, args, context, info) { + // Return the post body only if the user is the post's author + return postRepository.getBody({ + user: context.user, + post: obj, + }); } ``` diff --git a/src/pages/learn/execution.mdx b/src/pages/learn/execution.mdx index 5fca44a03a..6f3efa82c8 100644 --- a/src/pages/learn/execution.mdx +++ b/src/pages/learn/execution.mdx @@ -58,10 +58,8 @@ At the top level of every GraphQL server is an Object type that represents the p In this example, our `Query` type provides a field called `human` which accepts the argument `id`. The resolver function for this field likely accesses a database and then constructs and returns a `Human` type: ```js -function Query_human(obj, args, context, info) { - return context.db.loadHumanByID(args.id).then( - userData => new Human(userData) - ) +function resolveHumanQuery(obj, args, context, info) { + return context.db.loadHumanByID(args.id).then(userData => new Human(userData)); } ``` @@ -81,10 +79,8 @@ Note that while a query operation could technically write data to the underlying Let's take a closer look at what's happening in this resolver function: ```js -function Query_human(obj, args, context, info) { - return context.db.loadHumanByID(args.id).then( - userData => new Human(userData) - ) +function resolveHuman(obj, args, context, info) { + return context.db.loadHumanByID(args.id).then(userData => new Human(userData)); } ``` @@ -97,8 +93,8 @@ Notice that while the resolver function needs to be aware of Promises, the Graph Now that a `Human` object is available, GraphQL execution can continue with the fields requested for this type: ```js -function Human_name(obj, args, context, info) { - return obj.name +function resolveHumanName(obj, args, context, info) { + return obj.name; } ``` @@ -113,11 +109,11 @@ Many GraphQL libraries let you omit resolvers this simple, assuming that if a re While the `name` field is being resolved, the `appearsIn` and `starships` fields can be resolved concurrently. The `appearsIn` field could also have a trivial resolver, but let's take a closer look: ```js -Human: { +const Human = { appearsIn(obj) { - return obj.appearsIn // returns [ 4, 5, 6 ] - } -} + return obj.appearsIn; // e.g. [4, 5, 6] + }, +}; ``` Notice that our type system claims `appearsIn` will return Enum types with known values, however, this function is returning numbers! Indeed if we look up at the result we'll see that the appropriate values for the Enum type are being returned. What's going on? @@ -129,12 +125,12 @@ This is an example of _scalar coercion_. The type system knows what to expect an We've already seen some of what happens when a field returns a list of things with the `appearsIn` field above. It returned a [List type](/learn/schema/#lists) containing Enum type values, and since that's what the type system expected, each item in the list was coerced to the appropriate value. What happens when the `starships` field is resolved? ```js -function Human_starships (obj, args, context, info) { - return obj.starshipIDs.map( - id => context.db.loadStarshipByID(id).then( - shipData => new Starship(shipData) +function resolveHumanStarships(obj, args, context, info) { + return Promise.all( + obj.starshipIDs.map(id => + context.db.loadStarshipByID(id).then(shipData => new Starship(shipData)) ) - ) + ); } ``` diff --git a/src/pages/learn/index.mdx b/src/pages/learn/index.mdx index ac6ba9c291..ada9acfe38 100644 --- a/src/pages/learn/index.mdx +++ b/src/pages/learn/index.mdx @@ -25,14 +25,14 @@ type User { Along with functions for each field on each type: ```js -// Provide data for the `me` field on the `Query` type -function Query_me(query, args, context, info) { - return context.request.auth.user +// Resolver for the `me` field on the `Query` type +function resolveQueryMe(_parent, _args, context, _info) { + return context.request.auth.user; } -// Provide data for the `name` field on the `User` type -function User_name(user, args, context, info) { - return context.db.getUserFullName(user.id) +// Resolver for the `name` field on the `User` type +function resolveUserName(user, _args, context, _info) { + return context.db.getUserFullName(user.id); } ``` diff --git a/src/pages/learn/mutations.mdx b/src/pages/learn/mutations.mdx index 641c83c2af..57351f6edf 100644 --- a/src/pages/learn/mutations.mdx +++ b/src/pages/learn/mutations.mdx @@ -58,13 +58,13 @@ While the `createReview` field could be defined with any valid output type in th Recall that GraphQL is meant to work with your existing code and data, so the actual creation of the review is up to you when clients send this operation to the GraphQL server. A hypothetical function that writes the new review to a database during a `createReview` mutation might look like this: ```js -Mutation: { - createReview(obj, args, context, info) { +const Mutation = { + createReview(_obj, args, context, _info) { return context.db .createNewReview(args.episode, args.review) - .then((reviewData) => new Review(reviewData)) - } -} + .then(reviewData => new Review(reviewData)); + }, +}; ``` You can learn more about how GraphQL provides data for fields on the [Execution page](/learn/execution).