From 81585309e8735f576fae50e838661c2398c76184 Mon Sep 17 00:00:00 2001 From: urigo Date: Thu, 12 Dec 2024 11:59:29 +0200 Subject: [PATCH 1/3] Tutorial - Update Link.comments return type --- .../src/schema/base/resolvers/Link.ts | 8 +--- .../hackernews/src/schema/base/schema.graphql | 2 +- .../tutorial/basic/08-graph-relations.mdx | 44 +++++++++++++------ .../11-setting-up-graphql-code-generator.mdx | 18 +++----- 4 files changed, 38 insertions(+), 34 deletions(-) diff --git a/examples/hackernews/src/schema/base/resolvers/Link.ts b/examples/hackernews/src/schema/base/resolvers/Link.ts index c5dd9c450..afbb6dc05 100644 --- a/examples/hackernews/src/schema/base/resolvers/Link.ts +++ b/examples/hackernews/src/schema/base/resolvers/Link.ts @@ -1,16 +1,12 @@ import type { LinkResolvers } from '../../types.generated'; export const Link: LinkResolvers = { - comments: async (parent, _arg, context) => { - const comments = await context.prisma.comment.findMany({ + comments: (parent, _arg, context) => { + return context.prisma.comment.findMany({ orderBy: { createdAt: 'desc' }, where: { linkId: parent.id, }, }); - if (comments.length === 0) { - return null; - } - return comments; }, }; diff --git a/examples/hackernews/src/schema/base/schema.graphql b/examples/hackernews/src/schema/base/schema.graphql index 3b75655d3..f99fc91f0 100644 --- a/examples/hackernews/src/schema/base/schema.graphql +++ b/examples/hackernews/src/schema/base/schema.graphql @@ -14,7 +14,7 @@ type Link { id: ID! description: String! url: String! - comments: [Comment!] + comments: [Comment!]! } type Comment { diff --git a/website/src/pages/tutorial/basic/08-graph-relations.mdx b/website/src/pages/tutorial/basic/08-graph-relations.mdx index bfa23434a..c14802338 100644 --- a/website/src/pages/tutorial/basic/08-graph-relations.mdx +++ b/website/src/pages/tutorial/basic/08-graph-relations.mdx @@ -392,22 +392,42 @@ type Link { id: ID! description: String! url: String! - comments: [Comment!] + comments: [Comment!]! } ``` On the Prisma API level, the method call for loading will always return an array. It does not distinguish between an empty array and an array with comments. -On the GraphQL schema, we could follow the same practice, and make the comments array non-nullable -(`[Comment!]!`). +On the GraphQL schema, we have three options: -In our example, we've choosen the nullable option, as it indicates the API the need to handle that -case, when they will generate the types on their end. +1. `comments: [Comment]` +2. `comments: [Comment!]` +3. `comments: [Comment!]!` -Up next, you implement the corresponding `Link.comments` resolver. For this, you need to touch the -`Link` object types resolver map. Because of the nullable type, we will first check if there are any -comments and if there are none, we'll return null. +Let's try to explain the differences between the options. We'll also describe the Typescript return +value of each option (which will be automatically generated in the later Codegen chapter). + +Option 1, `[Comment]`, means that each element of the array can be Comment or null and the array +itself can be null. The Typescript return type of that resolver would be +`Array | null`. It means there are too many ways and cases to describe when we +return an empty array. The client will have to deal with many cases. + +Option 2, `[Comment!]`, means each element of the array must be Comment, but the array can return +empty or null. The Typescript return type of that resolver would be `Array | null`. if the +backend returns null or an empty array [], they can both mean +`there's no Comment related to the Link`. Meaning we have two ways to represent the same concept - +which makes it harder for the client to handle that case. + +Option 3, `[Comment!]!`, means each element of the array must be Comment. The Typescript return type +for of resolver would be `Array`. With `[Comment!]!`, the server can only return an empty +array `[]`. This means it's easier for the client to handle because there's only one way to +represent the `there's no Comment related to the Link` concept. + +For the reasons above we'll chose option `3` for our implementation. + +Now let's implement the corresponding `Link.comments` resolver. For this, you need to touch the +`Link` object types resolver map. As we also have the createdAt field on comments, let's sort the comments by that field when we return them to the user. @@ -419,17 +439,13 @@ const resolvers = { // ... other resolver maps ... Link: { // ... other field resolver functions - async comments(parent: Link, args: {}, context: GraphQLContext) { - const comments = await context.prisma.comment.findMany({ + comments(parent: Link, args: {}, context: GraphQLContext) { + return context.prisma.comment.findMany({ orderBy: { createdAt: 'desc' }, where: { linkId: parent.id } }) - if (comments.length === 0) { - return null - } - return comments } } // ... other resolver maps ... diff --git a/website/src/pages/tutorial/basic/11-setting-up-graphql-code-generator.mdx b/website/src/pages/tutorial/basic/11-setting-up-graphql-code-generator.mdx index 1150c8737..1f95fefb2 100644 --- a/website/src/pages/tutorial/basic/11-setting-up-graphql-code-generator.mdx +++ b/website/src/pages/tutorial/basic/11-setting-up-graphql-code-generator.mdx @@ -49,7 +49,7 @@ type Link { id: ID! description: String! url: String! - comments: [Comment!] + comments: [Comment!]! } type Comment { @@ -230,17 +230,13 @@ const resolvers = { id: (parent: Link) => parent.id, description: (parent: Link) => parent.description, url: (parent: Link) => parent.url, - async comments(parent: Link, args: {}, context: GraphQLContext) { - const comments = await context.prisma.comment.findMany({ + comments(parent: Link, args: {}, context: GraphQLContext) { + return context.prisma.comment.findMany({ orderBy: { createdAt: 'desc' }, where: { linkId: parent.id } }) - if (comments.length === 0) { - return null - } - return comments } } } @@ -303,17 +299,13 @@ Now, you can simply remove the comments, and migrate the existing `comments` res import type { LinkResolvers } from './../../types.generated' export const Link: LinkResolvers = { - async comments: async (parent, _arg, context) => { - const comments = await context.prisma.comment.findMany({ + comments: async (parent, _arg, context) => { + return context.prisma.comment.findMany({ orderBy: { createdAt: 'desc' }, where: { linkId: parent.id } }) - if (comments.length === 0) { - return null - } - return comments } } ``` From aa644c83fb08d13a73161576d2c041b0ecdb2dc1 Mon Sep 17 00:00:00 2001 From: Uri Goldshtein Date: Thu, 12 Dec 2024 13:34:25 +0200 Subject: [PATCH 2/3] Update website/src/pages/tutorial/basic/08-graph-relations.mdx Co-authored-by: Valentin Cocaud --- website/src/pages/tutorial/basic/08-graph-relations.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/pages/tutorial/basic/08-graph-relations.mdx b/website/src/pages/tutorial/basic/08-graph-relations.mdx index c14802338..dd66e563d 100644 --- a/website/src/pages/tutorial/basic/08-graph-relations.mdx +++ b/website/src/pages/tutorial/basic/08-graph-relations.mdx @@ -414,7 +414,7 @@ itself can be null. The Typescript return type of that resolver would be return an empty array. The client will have to deal with many cases. Option 2, `[Comment!]`, means each element of the array must be Comment, but the array can return -empty or null. The Typescript return type of that resolver would be `Array | null`. if the +empty or null. The Typescript return type of that resolver would be `Array | null`. If the backend returns null or an empty array [], they can both mean `there's no Comment related to the Link`. Meaning we have two ways to represent the same concept - which makes it harder for the client to handle that case. From d258f21cb27c078c31d78b6101c834d4e9e5d1df Mon Sep 17 00:00:00 2001 From: urigo Date: Thu, 12 Dec 2024 14:01:23 +0200 Subject: [PATCH 3/3] fix syntax error --- website/src/pages/tutorial/basic/08-graph-relations.mdx | 2 +- .../tutorial/basic/11-setting-up-graphql-code-generator.mdx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/website/src/pages/tutorial/basic/08-graph-relations.mdx b/website/src/pages/tutorial/basic/08-graph-relations.mdx index dd66e563d..6f0f863e7 100644 --- a/website/src/pages/tutorial/basic/08-graph-relations.mdx +++ b/website/src/pages/tutorial/basic/08-graph-relations.mdx @@ -439,7 +439,7 @@ const resolvers = { // ... other resolver maps ... Link: { // ... other field resolver functions - comments(parent: Link, args: {}, context: GraphQLContext) { + comments: (parent: Link, args: {}, context: GraphQLContext) => { return context.prisma.comment.findMany({ orderBy: { createdAt: 'desc' }, where: { diff --git a/website/src/pages/tutorial/basic/11-setting-up-graphql-code-generator.mdx b/website/src/pages/tutorial/basic/11-setting-up-graphql-code-generator.mdx index 1f95fefb2..fbfd8158f 100644 --- a/website/src/pages/tutorial/basic/11-setting-up-graphql-code-generator.mdx +++ b/website/src/pages/tutorial/basic/11-setting-up-graphql-code-generator.mdx @@ -230,7 +230,7 @@ const resolvers = { id: (parent: Link) => parent.id, description: (parent: Link) => parent.description, url: (parent: Link) => parent.url, - comments(parent: Link, args: {}, context: GraphQLContext) { + comments: (parent: Link, args: {}, context: GraphQLContext) => { return context.prisma.comment.findMany({ orderBy: { createdAt: 'desc' }, where: { @@ -299,7 +299,7 @@ Now, you can simply remove the comments, and migrate the existing `comments` res import type { LinkResolvers } from './../../types.generated' export const Link: LinkResolvers = { - comments: async (parent, _arg, context) => { + comments: (parent, _arg, context) => { return context.prisma.comment.findMany({ orderBy: { createdAt: 'desc' }, where: {