使用Next.js + GraphQL构建Todo应用程序(中篇)
首先
最近我学习了GraphQL,利用Next.js + GraphQL + GraphQL CodeGenerator + Prisma搭建了一个Todo应用程序,现在我会简单介绍一下,并在这里记录下来。

环境
-
- Macbook Air
-
- node
v18.13.0
pnpm
7.27.0
索引
前編
Next Create App
GraphQLサーバー構築
Subscription
DB・Prisma
中編 ? 今ここ
GraphQL Schema
GraphQL Context
GraphQL Code Generator
GraphQL Resolver
GraphQLサーバー修正
後編
フロント側準備
フロント側実装
编写中文文章
这是GraphQL阶段的中间部分
1. GraphQL架构
.
├── src
│ ├── graphql
│ │ ├── typeDefs
│ │ │ ├─ common.graphql
│ │ │ └─ todo.graphql
│ │ │
我們將在這樣的文件結構下進行創建。
為了將來增加模式時的方便,我們打算在common.graphql中定義共用的模式。
schema
Query
ListTodos: Todo一覧を取得する
Mutation
addTodo: contentを元にTodoを作成する
updateTodo: idとdoneから、todoの状態を更新する
deleteTodo: idから、todoを削除する
create file
$ mkdir src/graphql src/graphql/typeDefs
$ touch src/graphql/typeDefs/todo.graphql src/graphql/typeDefs/common.graphql
edit file
todo.graphql
type Todo {
id: ID!
content: String!
done: Boolean!
createdAt: DateTime
}
type Query {
listTodos: [Todo!]!
}
type Mutation {
addTodo(content: String!): Todo!
updateTodo(id: ID!, done: Boolean!): Todo!
deleteTodo(id: ID!): Todo!
}
fragment TodoFragment on Todo {
id
content
done
createdAt
}
query ListTodos {
listTodos {
…TodoFragment
}
}
mutation AddTodo($content: String!) {
addTodo(content: $content) {
…TodoFragment
}
}
mutation UpdateTodo($id: ID!, $done: Boolean!) {
updateTodo(id: $id, done: $done) {
…TodoFragment
}
}
mutation DeleteTodo($id: ID!) {
deleteTodo(id: $id) {
…TodoFragment
}
}
common.graphql
scalar DateTime
2. GraphQL上下文的配置
.
├── src
│ ├── graphql
│ │ ├── context
│ │ │ ├── index.ts
create file
$ mkdir src/graphql/context
$ touch src/graphql/context/index.ts
edit file
src/graphql/context/index.ts
import { PrismaClient } from “@prisma/client”;
const prisma = new PrismaClient();
export type Context = {
prisma: typeof prisma;
};
export const createContext = () => {
return {
prisma: prisma,
};
};
3. GraphQL 代码生成器
.
├── src
│ ├── graphql
| | ├── typeDefs
| | | ├── common.graphql
| | | └── todo.graphql
│ │ ├── context
│ │ │ ├── index.ts
install
# dependencies
$ pnpm add graphql @graphql-tools/graphql-file-loader @graphql-tools/load @graphql-tools/schema
# devDependencies
pnpm add -D @graphql-codegen/cli @graphql-codegen/schema-ast @graphql-codegen/typescript @graphql-codegen/typescript-resolvers @graphql-codegen/typescript-operations @graphql-codegen/typescript-react-apollo ts-node
create codegen.yml
$ touch codegen.yml
codegen.yml
generates:
src/generated/schema.graphql:
schema:
– “src/graphql/typeDefs/**/*.graphql”
plugins:
– schema-ast
src/generated/resolvers-types.ts:
schema:
– “src/graphql/typeDefs/**/*.graphql”
plugins:
– typescript
– typescript-resolvers
config:
contextType: “@/graphql/context/#Context”
mapperTypeSuffix: Model
mappers:
Todo: “@prisma/client#Todo”
scalars:
DateTime: string
src/generated/request.ts:
schema:
– “src/graphql/typeDefs/**/*.graphql”
documents:
– “src/graphql/typeDefs/**/*.graphql”
plugins:
– typescript
– typescript-operations
– typescript-react-apollo
config:
scalars:
DateTime: string
run graphql-codegen
$ pnpm graphql-codegen
✔ Parse Configuration
✔ Generate outputs
実行すると以下のような構成でresolver用の型定義ファイルなどが生成されます
.
├── src
│ ├── generated
│ │ ├── request.ts
│ │ ├── resolvers-type.ts
│ │ └── schema.graphql
4. GraphQL 解析器
.
├── src
│ ├── graphql
│ │ ├── resolvers
│ │ │ └─ index.ts
│ │ │
create file
$ mkdir src/graphql/resolvers
$ touch src/graphql/resolvers/index.ts
edit file
3. GraphQL Code Generatorで作成したresolvers-typesを利用してresolverを設定していきます。
src/graphql/resolvers/index.ts
import { Resolvers } from “@/generated/resolvers-types”;
export const resolvers: Resolvers = {
Query: {
listTodos: async (_parent, _args, { prisma }) => {
return await prisma.todo.findMany();
},
},
Mutation: {
addTodo: async (_parent, { content }, { prisma }) => {
return await prisma.todo.create({
data: { content, createdAt: new Date().toISOString() },
});
},
updateTodo: async (_parent, { id, done }, { prisma }) => {
return await prisma.todo.update({
where: { id },
data: { done },
});
},
deleteTodo: async (_parent, { id }, { prisma }) => {
return await prisma.todo.delete({
where: { id },
});
},
},
};

5. 修复GraphQL服务器
将通过GraphQL Code Generator生成的文件和使用GraphQL Resolver创建的文件进行导入。
import { createYoga, createSchema } from "graphql-yoga";
import { readFileSync } from "fs";
import { join } from "path";
import { resolvers } from "@/graphql/resolvers";
import { createContext } from "@/graphql/context";
const path = join(process.cwd(), "src", "generated", "schema.graphql");
const typeDefs = readFileSync(path).toString("utf-8");
const schema = createSchema({
typeDefs,
resolvers,
})
const graphqlEndpoint = "/api/graphql";
export default createYoga({
graphqlEndpoint,
schema,
context: createContext,
});
让我们访问localhost:3000/api/graphql,并尝试发送一个查询(Query)。

看起来动了起来?
这样就完成了GraphQL服务器的设置。
下一次
接下来,我们将进行前端设置。
-
- 後編
フロント側準備
フロント側実装