From 2b2ff3d1a75acbf2d72f22ca11eed844460feea8 Mon Sep 17 00:00:00 2001 From: Ryan Chung <> Date: Wed, 25 Dec 2024 22:28:42 -0500 Subject: [PATCH 1/3] update execution page to use async/await instead of promise-based APIs --- src/pages/learn/execution.mdx | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/pages/learn/execution.mdx b/src/pages/learn/execution.mdx index 5fca44a03a..875da8bc8d 100644 --- a/src/pages/learn/execution.mdx +++ b/src/pages/learn/execution.mdx @@ -58,10 +58,9 @@ 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) - ) +async function Query_human(obj, args, context, info) { + const userData = await context.db.loadHumanByID(args.id); + return new Human(userData); } ``` @@ -81,14 +80,13 @@ 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) - ) +async function Query_human(obj, args, context, info) { + const userData = await context.db.loadHumanByID(args.id); + return new Human(userData); } ``` -The `id` argument in the GraphQL query specifies the user whose data is requested, while `context` provides access to retrieve this data from a database. Since loading from a database is an asynchronous operation, this returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). In JavaScript, Promises are used to work with asynchronous values, but the same concept exists in many languages, often called _Futures_, _Tasks_, or _Deferred_. When the database returns the data, we can construct and return a new `Human` object. +The `id` argument in the GraphQL query specifies the user whose data is requested, while `context` provides access to retrieve this data from a database. Since loading from a database is an asynchronous operation, we can utilize [async](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) / [await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await). In JavaScript, `async` / `await` are used to work with asynchronous values, where `async` indicates that the function contains asynchronous operations, and `await` halts the execution of the function until the [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) is resolved. The concept of Promises exists in many languages, often called _Futures_, _Tasks_, or _Deferred_. When the database returns the data, we can construct and return a new `Human` object. Notice that while the resolver function needs to be aware of Promises, the GraphQL query does not. It simply expects the `human` field to return something that can be further resolved to a scalar `name` value. During execution, GraphQL will wait for Promises, Futures, and Tasks to be completed before continuing and will do so with optimal concurrency. @@ -129,16 +127,17 @@ 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) - ) - ) +async function Human_starships(obj, args, context, info) { + const starships = []; + for (const id of obj.starshipIDs) { + const shipData = await context.db.loadStarshipByID(id); + starships.push(new Starship(shipData)); + } + return starships; } ``` -The resolver for this field is not just returning a Promise, it's returning a _list_ of Promises. The `Human` object had a list of IDs of the `Starships` they piloted, but we need to load all of those IDs to get real Starship objects. +The resolver for this field is returning a _list_ of the results of Promises by asynchronously requesting each ID from the database. The `Human` object had a list of IDs of the `Starships` they piloted, but we need to load all of those IDs to get real Starship objects. GraphQL will wait for all of these Promises concurrently before continuing, and when left with a list of objects, it will continue yet again to load the `name` field on each of these items concurrently. From 14156a19343f23b72f18a4e8c06e923b4d12da7b Mon Sep 17 00:00:00 2001 From: Ryan Chung Date: Wed, 25 Dec 2024 22:28:42 -0500 Subject: [PATCH 2/3] update execution page to use async/await instead of promise-based APIs --- src/pages/learn/execution.mdx | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/pages/learn/execution.mdx b/src/pages/learn/execution.mdx index 5fca44a03a..875da8bc8d 100644 --- a/src/pages/learn/execution.mdx +++ b/src/pages/learn/execution.mdx @@ -58,10 +58,9 @@ 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) - ) +async function Query_human(obj, args, context, info) { + const userData = await context.db.loadHumanByID(args.id); + return new Human(userData); } ``` @@ -81,14 +80,13 @@ 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) - ) +async function Query_human(obj, args, context, info) { + const userData = await context.db.loadHumanByID(args.id); + return new Human(userData); } ``` -The `id` argument in the GraphQL query specifies the user whose data is requested, while `context` provides access to retrieve this data from a database. Since loading from a database is an asynchronous operation, this returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). In JavaScript, Promises are used to work with asynchronous values, but the same concept exists in many languages, often called _Futures_, _Tasks_, or _Deferred_. When the database returns the data, we can construct and return a new `Human` object. +The `id` argument in the GraphQL query specifies the user whose data is requested, while `context` provides access to retrieve this data from a database. Since loading from a database is an asynchronous operation, we can utilize [async](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) / [await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await). In JavaScript, `async` / `await` are used to work with asynchronous values, where `async` indicates that the function contains asynchronous operations, and `await` halts the execution of the function until the [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) is resolved. The concept of Promises exists in many languages, often called _Futures_, _Tasks_, or _Deferred_. When the database returns the data, we can construct and return a new `Human` object. Notice that while the resolver function needs to be aware of Promises, the GraphQL query does not. It simply expects the `human` field to return something that can be further resolved to a scalar `name` value. During execution, GraphQL will wait for Promises, Futures, and Tasks to be completed before continuing and will do so with optimal concurrency. @@ -129,16 +127,17 @@ 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) - ) - ) +async function Human_starships(obj, args, context, info) { + const starships = []; + for (const id of obj.starshipIDs) { + const shipData = await context.db.loadStarshipByID(id); + starships.push(new Starship(shipData)); + } + return starships; } ``` -The resolver for this field is not just returning a Promise, it's returning a _list_ of Promises. The `Human` object had a list of IDs of the `Starships` they piloted, but we need to load all of those IDs to get real Starship objects. +The resolver for this field is returning a _list_ of the results of Promises by asynchronously requesting each ID from the database. The `Human` object had a list of IDs of the `Starships` they piloted, but we need to load all of those IDs to get real Starship objects. GraphQL will wait for all of these Promises concurrently before continuing, and when left with a list of objects, it will continue yet again to load the `name` field on each of these items concurrently. From 771af94317fb5630ef5c49c21bcaa1f48fed086d Mon Sep 17 00:00:00 2001 From: Saihajpreet Singh Date: Fri, 27 Dec 2024 12:36:57 +0100 Subject: [PATCH 3/3] add ts ignore for user schema (#1913) --- src/components/marked/users-schema.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/marked/users-schema.ts b/src/components/marked/users-schema.ts index f80f44614a..672aa25571 100644 --- a/src/components/marked/users-schema.ts +++ b/src/components/marked/users-schema.ts @@ -67,6 +67,7 @@ const ImageType = new GraphQLObjectType({ // @ts-expect-error -- fixme const FriendConnection = new GraphQLObjectType({ name: "FriendConnection", + // @ts-expect-error -- fixme fields: () => ({ totalCount: { type: GraphQLInt }, friends: { type: new GraphQLList(UserType) },