如何使用Prisma构建GraphQL API并部署到DigitalOcean应用平台

作者选择了 COVID-19 救助基金技术教育基金作为 写给捐赠计划的一部分接受捐赠。

介绍

[GraphQL] (https://graphql.org/)是APIs的一种查询语言,由schema定义语言和查询语言组成,它允许API消费者只获取支持灵活查询所需的数据. 图 QL使开发者在满足多个客户端的不同需要的同时,可以进取API,例如iOS,Android,以及一个应用的网络变体. 此外, GraphQL 计划还为 API 添加了一定程度的类型安全性,同时也作为您 API 的一种文档形式.

Prisma是一个开源数据库工具包,包含三个主要工具:

Prisma Client :用于Node.js和TypeScript的自动生成和安全打字查询构建程序.* Prisma Migrate* :声明数据建模和迁移系统.** Prisma Studio* :数据库中查看和编辑数据的GUI。

Prisma 可帮助应用程序开发人员专注于实现增值功能,而不是花费时间处理复杂的数据库工作流(如架构迁移或编写复杂的 SQL 查询)。

在本教程中,您将使用 GraphQL 和 Prisma 结合,因为它们的职责相互补充。GraphQL 为您的数据提供了一个灵活的界面,可用于客户端,如前端和移动应用程序—GraphQL 不会与任何特定数据库相关联。

DigitalOcean's App Platform提供了一个无缝的方式来部署应用程序和提供数据库在云中,而不必担心基础设施。这减少了在云中运行应用程序的操作负担;特别是创建一个管理的PostgreSQL数据库的能力,每天备份和自动故障。

您将使用 Node.js 构建一个 GraphQL API 用于 JavaScript 博客应用程序. 您将首先使用 Apollo Server 构建由内存数据结构支持的 GraphQL API. 然后将 API 部署到 DigitalOcean App Platform. 最后,您将使用 Prisma 来替代内存存储,并在 PostgreSQL 数据库中保持数据并重新部署应用程序。

在教程结束时,您将部署一个 Node.js GraphQL API 到 DigitalOcean,该 API 处理通过 HTTP 发送的 GraphQL 请求,并对 PostgreSQL 数据库执行 CRUD 操作。

您可以在 [DigitalOcean Community Respository] 找到此项目的代码(https://github.com/do-community/prisma-graphql)。

前提条件

在您开始本指南之前,您将需要以下内容:

基本熟悉的 JavaScript, Node.js, GraphQL,和PostgreSQL是有用的,但不严格要求这个教程。

第1步:创建 Node.js 项目

在此步骤中,您将设置一个 Node.js 项目与 npm 并安装apollo-servergraphql的依赖性,该项目将成为您在本教程中构建和部署的 GraphQL API 的基础。

首先,为您的项目创建一个新目录:

1mkdir prisma-graphql

接下来,导航到目录并启动一个空 npm 项目:

1cd prisma-graphql
2npm init --yes

此命令会创建一个最小的 package.json 文件,作为 npm 项目的配置文件。

您将获得以下输出:

 1[secondary_label Output]
 2Wrote to /Users/your_username/workspace/prisma-graphql/package.json:
 3{
 4  "name": "prisma-graphql",
 5  "version": "1.0.0",
 6  "description": "",
 7  "main": "index.js",
 8  "scripts": {
 9    "test": "echo \"Error: no test specified\" && exit 1"
10  },
11  "keywords": [],
12  "author": "",
13  "license": "ISC"
14}

您现在已经准备好在您的项目中配置TypeScript。

建立必要的依赖性:

1npm install apollo-server graphql --save

此命令在您的项目中安装两个包作为依赖:

  • apollo-server是您用来定义 GraphQL 请求如何解决以及如何获取数据的 HTTP 库。

您已经创建了项目并安装了依赖性,在下一步,您将定义 GraphQL 方案。

步骤 2 – 定义 GraphQL 方案和解决方案

在此步骤中,您将定义 GraphQL schema 和相应的 resolvers. 该方案将定义API可以处理的操作。

首先,创建一个名为src的新目录,该目录将包含您的源文件:

1mkdir src

然后运行以下命令来创建该方案的文件:

1nano src/schema.js

将以下代码添加到文件中:

 1[label prisma-graphql/src/schema.js]
 2const { gql } = require('apollo-server')
 3
 4const typeDefs = gql`
 5  type Post {
 6    content: String
 7    id: ID!
 8    published: Boolean!
 9    title: String!
10  }
11
12  type Query {
13    feed: [Post!]!
14    post(id: ID!): Post
15  }
16
17  type Mutation {
18    createDraft(content: String, title: String!): Post!
19    publish(id: ID!): Post
20  }
21`

您使用 gql [标记模板] 定义 GraphQL 方案(https://www.apollographql.com/docs/apollo-server/api/apollo-server/# gql)。 该方案是一个类型定义的集合(因此 typeDefs),它们一起定义可以对您的 API 执行的查询的形状。 这将 GraphQL 方案字符串转换为 Apollo 期望的格式。

该方案引入了三种类型:

  • Post定义了博客应用程序中的帖子的类型,包含四个字段,每个字段随后是其类型:例如,String。 * Query定义了Feed查询,该查询返回了多个帖子,以方块表示,以及Post查询,该查询接受了一个单一的论点,并返回了一个Post。 * Mutation定义了创建草案PostcreateDraft突变,以及接受id并返回Postpublish突变。

每个 GraphQL API 都有一个 query 类型,可能或可能没有一个 mutation 类型,这些类型与常规对象类型相同,但它们是特殊的,因为它们定义了每个 GraphQL 查询的输入点。

接下来,在typeDefs变量下,将posts数组添加到src/schema.js文件中:

 1[label prisma-graphql/src/schema.js]
 2...
 3const posts = [
 4  {
 5    id: 1,
 6    title: 'Subscribe to GraphQL Weekly for community news ',
 7    content: 'https://graphqlweekly.com/',
 8    published: true,
 9  },
10  {
11    id: 2,
12    title: 'Follow DigitalOcean on Twitter',
13    content: 'https://twitter.com/digitalocean',
14    published: true,
15  },
16  {
17    id: 3,
18    title: 'What is GraphQL?',
19    content: 'GraphQL is a query language for APIs',
20    published: false,
21  },
22]

您用三个预定义的帖子来定义帖子数组. 每个帖子对象的结构与您在计划中定义的帖子类型相匹配. 该数组包含将由 API 服务的帖子。

接下来,通过添加您刚刚定义的帖子数组下方的以下代码来定义解决对象:

 1[label prisma-graphql/src/schema.js]
 2...
 3const resolvers = {
 4  Query: {
 5    feed: (parent, args) => {
 6      return posts.filter((post) => post.published)
 7    },
 8    post: (parent, args) => {
 9      return posts.find((post) => post.id === Number(args.id))
10    },
11  },
12  Mutation: {
13    createDraft: (parent, args) => {
14      posts.push({
15        id: posts.length + 1,
16        title: args.title,
17        content: args.content,
18        published: false,
19      })
20      return posts[posts.length - 1]
21    },
22    publish: (parent, args) => {
23      const postToPublish = posts.find((post) => post.id === Number(args.id))
24      postToPublish.published = true
25      return postToPublish
26    },
27  },
28  Post: {
29    content: (parent) => parent.content,
30    id: (parent) => parent.id,
31    published: (parent) => parent.published,
32    title: (parent) => parent.title,
33  },
34}
35
36module.exports = {
37  resolvers,
38  typeDefs,
39}

您将根据与 GraphQL 架构相同的结构定义解析器. 该架构类型中的每个字段都有一个相应的解析函数,其职责是返回您的架构中的该字段的数据。

解决函数获得四个参数:

  • " 父母 " 是指在解决者链中以前的解决者的返回值。 对于顶级解析器,母体被"未定义",因为没有调用之前的解析器. 例如,在进行feed'查询时,query.feed ()' 将使用父母'价值的未定义'来称呼解析器,然后将后'的解析器称为父母'从`食物'解析器返回的对象。
  • args'带有查询的参数。 例如, " 员额 " 查询将获得待取员额的id ' 。
  • `文本'是一个通过解析器链传递的对象,每个解析器可以书写和读取,这使解析器可以分享信息。
  • `info'是查询或变异的AST表示。 您可以阅读更多关于此GraphQL Basics上的Prisma系列的细节. .

由于背景信息在这些解决方案中不必要,所以只有父母火箭被定义。

保存和退出文件一旦完成。

注意: 当解决方案返回与解决方案的名称相同的字段时,例如邮件的四个解决方案,Apollo Server 会自动解决这些解决方案,这意味着您不必明确定义这些解决方案。

1-  Post: {
2-    content: (parent) => parent.content,
3-    id: (parent) => parent.id,
4-    published: (parent) => parent.published,
5-    title: (parent) => parent.title,
6-  },

美元

您可以导出方案和解析器,以便您可以在下一步使用它们来与 Apollo Server 实例化服务器。

第3步:创建GraphQL服务器

在此步骤中,您将使用 Apollo Server 创建 GraphQL 服务器,并将其绑定到端口,以便服务器可以接受连接。

首先,运行以下命令来为服务器创建文件:

1nano src/server.js

将以下代码添加到文件中:

1[label prisma-graphql/src/server.js]
2const { ApolloServer } = require('apollo-server')
3const { resolvers, typeDefs } = require('./schema')
4
5const port = process.env.PORT || 8080
6
7new ApolloServer({ resolvers, typeDefs }).listen({ port }, () =>
8  console.log(`Server ready at: http://localhost:${port}`),
9)

在这里,您实时化服务器,并通过前一个步骤的方案和解决方案。

服务器将连接的端口是从)自动设置,并确保您的服务器一旦部署,就可以接受连接。

保存和退出文件。

您的 GraphQL API 已准备好运行. 使用以下命令启动服务器:

1node src/server.js

您将获得以下输出:

1[secondary_label Output]
2Server ready at: http://localhost:8080

将启动脚本添加到您的 package.json 文件中被认为是很好的做法,以便您的服务器的输入点是清晰的。

首先,通过按CTRL+C来阻止服务器,然后添加启动脚本,打开package.json文件:

1nano package.json

将突出的文本添加到package.json中的脚本对象:

 1[label package.json]
 2{
 3  "name": "prisma-graphql",
 4  "version": "1.0.0",
 5  "description": "",
 6  "main": "index.js",
 7  "scripts": {
 8    "test": "echo \"Error: no test specified\" && exit 1",
 9    "start": "node ./src/server.js"
10  },
11  "keywords": [],
12  "author": "",
13  "license": "ISC",
14  "dependencies": {
15    "apollo-server": "^3.11.1",
16    "graphql": "^16.6.0"
17  }
18}

保存和退出文件。

现在您可以使用以下命令启动服务器:

1npm start

您将获得以下输出:

1[secondary_label Output]
2> [email protected] start
3> node ./src/server.js
4
5Server ready at: http://localhost:8080

要测试 GraphQL API,请从输出中打开 URL,这将引导您到Apollo GraphQL Studio。

Apollo GraphQL Studio

Apollo GraphQL Studio 是一个 IDE,您可以通过发送查询和突变来测试 API。

例如,要测试只返回发布帖子的查询,请在IDE左侧输入以下查询,然后按 运行 或播放按钮发送查询:

1[environment second]
2query {
3  feed {
4    id
5    title
6    content
7    published
8  }
9}

答案将显示一个标题订阅GraphQL Weekly及其URL和跟踪Twitter上的DigitalOcean及其URL。

GraphQL Feed Query

点击上面的栏上的+按钮以创建一个新的卡,然后,要测试createDraft突变,输入以下突变:

1[environment second]
2mutation {
3  createDraft(title: "Deploying a GraphQL API to DigitalOcean") {
4    id
5    title
6    content
7    published
8  }
9}

在使用播放按钮提交突变后,您将在标题字段中收到部署 GraphQL API 到 DigitalOcean的响应,作为响应的一部分。

GraphQL Create Draft Mutation

<$>[注] 注: 您可以通过在)中的字段来选择从突变中返回的字段,例如,如果您只想返回idtitle,则可以发送以下突变:

1[environment second]
2mutation {
3  createDraft(title: "Deploying a GraphQL API to DigitalOcean") {
4    id
5    title
6  }
7}

美元

您已成功创建并测试了 GraphQL 服务器. 在下一步,您将为项目创建一个 GitHub 存储库。

第4步:创建GitHub存储库

在此步骤中,您将为您的项目创建一个GitHub存储库,并推动您的更改,以便GraphQL API可以从GitHub自动部署到App平台。

首先,通过按CTRL+C来停止开发服务器,然后使用以下命令从prisma-graphql文件夹中初始化一个存储库:

1git init

接下来,使用以下两个命令将代码绑定到存储库:

1git add src package-lock.json package.json
2git commit -m 'Initial commit'

现在,这些更改已经对您的本地存储库进行了承诺,您将在GitHub中创建一个存储库,并推动您的更改。

请访问 GitHub以创建一个新的存储库. 为了保持一致性,请命名存储库 prisma-graphql ,然后单击** Create repository** 。

创建存储库后,使用以下命令按下更改,其中包括将默认的本地分支机构重新命名为:

1git remote add origin [email protected]:your_github_username/prisma-graphql.git
2git branch -M main
3git push --set-upstream origin main

您已成功承诺并将更改推向GitHub,接下来,您将连接存储库到App Platform并部署GraphQL API。

步骤5 – 部署到应用平台

在此步骤中,您将刚刚创建的GitHub存储库连接到DigitalOcean,然后配置应用平台,以便在将更改推到GitHub时自动部署GraphQL API。

首先,请访问 DigitalOcean Cloud Console 中的 应用平台页面,然后单击创建应用按钮。

您将看到服务提供商选项,默认情况为 GitHub

如果您尚未将 DigitalOcean 配置为您的 GitHub 帐户,请单击管理访问按钮,将其重定向到 GitHub。

DigitalOcean Cloud console page for "Manage GitHub Access"

您可以选择所有存储库或特定存储库. 点击 安装和授权 ,然后您将被重定向到创建 DigitalOcean App Platform。

选择your_github_username/prisma-graphql存储库,然后单击 Next 。** Autodeploy** 是默认选择的,您可以选择在重置中保持一致性。

Choose Repository

资源 页面上,点击 ** 编辑计划** 按钮选择合适的计划. 选择 ** 基本计划** 与您所需的计划大小(本教程将使用** $ 5.00/mo - 基本计划** )。

Screencapture of the "Edit Payment Plan" page in the App Platform Console, displaying the $5 per month Basic option

然后按 返回 返回创建页面。

如果您按下您的项目名称旁边的笔图标,您可以定制应用程序的配置。

Application Settings

默认情况下,App Platform 会将 HTTP 端口设置为8080,这是您配置的 GraphQL 服务器连接的相同端口。

当您完成自定义配置时,请按 返回 按钮返回设置页面,然后按** 下一步** 按钮移动到** 环境变量** 页面。

您的环境变量目前不需要进一步配置. 点击 Next 按钮。

Screencapture displaying the Environment Variables default setup

Info 页面上,您可以调整** 应用详细信息** 和** 位置** . 编辑您的应用信息,以选择您想要部署应用的区域。

Screencapture of the Info page, displaying the selected location of the application

您将能够在 Review 页面上查看所选的所有选项,然后点击** Create Resources** . 您将被重定向到应用页面,在那里您将看到初始部署的进展。

一旦构建完成,您将收到通知,说明您的应用已经部署。

Screencapture displaying the deployment progress bar with a "went live at" message

您现在可以访问部署的 GraphQL API 在您的 DigitalOcean Console 应用程序名称下方的 URL。 它将通过ondigitalocean.app子域链接。 当您打开 URL 时,GraphQL Playground 将以本教程的第 3 步的方式打开。

您已成功连接您的存储库到 App Platform,并部署了您的 GraphQL API. 接下来,您将开发您的应用程序,并用数据库替换 GraphQL API 的内存数据。

第6步:用PostgreSQL设置 Prisma

到目前为止,您已经建立了 GraphQL API,使用内存帖子数组来存储数据. 如果您的服务器重新启动,所有数据的更改都将丢失. 为了确保您的数据安全存储,您将用PostgreSQL数据库替换帖子数组,并使用Prisma访问数据。

在此步骤中,您将安装 Prisma CLI,创建您的初始 Prisma 方案(Prisma 设置的主要配置文件,包含您的数据库方案),在 Docker 中本地设置 PostgreSQL,并连接 Prisma 到它。

首先,使用以下命令安装 Prisma CLI:

1npm install --save-dev prisma

Prisma CLI 将帮助运行数据库迁移和生成 Prisma 客户端等数据库工作流程。

接下来,您将使用 Docker 设置您的 PostgreSQL 数据库. 使用以下命令创建一个新的 Docker Compose 文件:

1nano docker-compose.yml

将以下代码添加到新创建的文件中:

 1[label prisma-graphql/docker-compose.yml]
 2version: '3.8'
 3services:
 4  postgres:
 5    image: postgres:14
 6    restart: always
 7    environment:
 8      - POSTGRES_USER=test-user
 9      - POSTGRES_PASSWORD=test-password
10    volumes:
11      - postgres:/var/lib/postgresql/data
12    ports:
13      - '5432:5432'
14volumes:
15  postgres:

此 Docker Compose 配置文件负责在您的计算机上启动官方 PostgreSQL Docker 图像。)设置了凭证。您还将使用这些凭证连接 Prisma 到数据库。 用用户凭证替换测试用户测试密码

最后,您定义了 PostgreSQL 将其数据存储的卷,并将计算机上的5432端口绑定到 Docker 容器中的相同端口。

保存和退出文件。

有了此设置,您可以使用以下命令启动 PostgreSQL 数据库服务器:

1docker-compose up -d

可能需要几分钟才能充电。

您可以通过以下命令验证数据库服务器是否正在运行:

1docker ps

这个命令会输出类似的东西:

1[secondary_label Output]
2CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3198f9431bf73 postgres:10.3       "docker-entrypoint.s…"   45 seconds ago Up 11 seconds 0.0.0.0:5432->5432/tcp prisma-graphql_postgres_1

在运行 PostgreSQL 容器时,您现在可以创建您的 Prisma 设置. 从 Prisma CLI 运行以下命令:

1npx prisma init

作为最佳做法,所有Prisma CLI的召唤都应该以npx为前缀,以确保它使用您的本地安装。

这样的输出将打印:

 1[secondary_label Output]
 2✔ Your Prisma schema was created at prisma/schema.prisma
 3  You can now open it in your favorite editor.
 4
 5Next steps:
 61. Set the DATABASE_URL in the .env file to point to your existing database. If your database has no tables yet, read https://pris.ly/d/getting-started
 72. Set the provider of the datasource block in schema.prisma to match your database: postgresql, mysql, sqlite, sqlserver, mongodb or cockroachdb.
 83. Run prisma db pull to turn your database schema into a Prisma schema.
 94. Run prisma generate to generate the Prisma Client. You can then start querying your database.
10
11More information in our documentation:
12https://pris.ly/d/getting-started

在运行命令后,Prisma CLI 会在项目文件夹中生成一个名为 .env 的 [dotenv](https://github.com/motdotla/dotenv) 文件,以定义您的数据库连接 URL,以及一个名为 prisma’ 的新的嵌入文件,其中包含 `schema.prisma' 文件。

要确保 Prisma 知道您的数据库的位置,请打开.env 文件:

1nano .env

调整DATABASE_URL环境变量与您的用户凭据:

1[label prisma-graphql/.env]
2DATABASE_URL="postgresql://test-user:test-password@localhost:5432/my-blog?schema=public"

您使用的数据库凭据是)。

您已成功启动 PostgreSQL 并使用 Prisma 架构配置 Prisma. 在下一步,您将为博客定义数据模型,并使用 Prisma Migrate 创建数据库架构。

第7步:用Prisma迁移定义数据模型

现在,您将定义您的 数据模型在您刚刚创建的 Prisma 架构文件中。此数据模型将随后与 Prisma Migrate 对照到数据库中,该数据模型将生成并发送 SQL 陈述来创建与您的数据模型相符的表格。

由于您正在构建博客,应用程序的主要实体将是 usersposts. 在此步骤中,您将定义一个与 GraphQL 方案中的Post类型的类似结构的Post模型。

<$>[注] 注: GraphQL API 可以被视为数据库的抽象层。在构建 GraphQL API 时,GraphQL 方案通常与您的数据库方案非常相似,但作为抽象,这两个方案不一定具有相同的结构,从而允许您控制您希望在 API 上曝光哪些数据,因为某些数据可能被视为对 API 层敏感或无关。

Prisma 使用自己的数据建模语言(https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-schema# syntax)来定义您的应用数据的形状。

从项目的文件夹中打开您的schema.prisma文件,其中位于package.json:

1nano prisma/schema.prisma

<$>[注] 注: 您可以从终端验证您所在的文件夹,使用pwd命令,该命令将输出当前的工作目录。

添加以下模型定义:

1[label prisma-graphql/prisma/schema.prisma]
2...
3model Post {
4  id Int     @default(autoincrement()) @id
5  title String
6  content String?
7  published Boolean @default(false)
8}

您定义一个 模型 称为 Post 与若干 字段. 该模型将被调至数据库 table;这些字段代表个体 columns

id字段具有以下字段属性:

  • @default(autoincrement()) 为列设置自动增加的默认值. * @id 将列设置为表的主要键。

保存和退出文件。

有了模型,您现在可以使用 Prisma Migrate 创建数据库中的相应表,并使用迁移 dev命令创建和运行迁移文件。

在您的终端中,运行以下命令:

1npx prisma migrate dev --name init --skip-generate

这个命令会在您的文件系统上创建一个新的 migration 并对数据库运行,以创建数据库方案. --name init 旗帜指定迁移的名称(将用来命名在您的文件系统上创建的迁移文件夹)。

这个命令会输出类似的东西:

 1[secondary_label Output]
 2Environment variables loaded from .env
 3Prisma schema loaded from prisma/schema.prisma
 4Datasource "db": PostgreSQL database "my-blog", schema "public" at "localhost:5432"
 5
 6PostgreSQL database my-blog created at localhost:5432
 7
 8Applying migration `20201201110111_init`
 9
10The following migration(s) have been created and applied from new schema changes:
11
12migrations/
13  └─ 20201201110111_init/
14    └─ migration.sql
15
16Your database is now in sync with your schema.

您的prisma/migrations目录现在挤满了 SQL 迁移文件,该方法允许您跟踪数据库方案的更改,并在生产中创建相同的数据库方案。

注意: 如果您已经在我的博客数据库中使用了 Prisma Migrate,并且在prisma/migration文件夹中的迁移与数据库方案之间存在不一致,您将被要求以以下输出重新设置数据库:

1[secondary_label Output]
2? We need to reset the PostgreSQL database "my-blog" at "localhost:5432". All data will be lost.
3Do you want to continue? › (y/N)

您可以通过输入y来解决这个问题,这将重置数据库,请注意这会导致数据库中的所有数据丢失。

在下一步,您将安装 Prisma 客户端并在您的 GraphQL 解析器中使用它。

步骤8 — 在 GraphQL 解决方案中使用 Prisma 客户端

Prisma 客户端是一个自动生成的和安全的 Object Relational Mapper (ORM),您可以使用它来从 Node.js 应用程序中编程读取和写入数据库中的数据。

在您的终端中,安装 Prisma 客户端 npm 包:

1npm install @prisma/client

<$>[注] 注: Prisma 客户端通过将基于 Prisma 方案的代码生成到 node_modules 文件夹中提供丰富的自动完成功能。 为了生成代码,您使用了 npx prisma generate 命令。 通常在创建并运行新迁移后,您会这样做。

创建数据库和 GraphQL 方案并安装 Prisma 客户端后,您现在将使用 Prisma 客户端在 GraphQL 解析器中读取和写入数据库。

创建并打开以下文件:

1nano src/db.js

将以下行添加到新文件中:

1[label prisma-graphql/src/db.js]
2const { PrismaClient } = require('@prisma/client')
3
4module.exports = {
5  prisma: new PrismaClient(),
6}

此代码导入 Prisma 客户端,创建其实例,并导出您将在解决程序中使用的实例。

现在保存并关闭src/db.js文件。

接下来,您将将prisma实例导入到src/schema.js

1nano src/schema.js

添加此行以导入 prisma./db 在文件的顶部:

1[label prisma-graphql/src/schema.js]
2const { prisma } = require('./db')
3...

然后删除)的行:

 1[label prisma-graphql/src/schema.js]
 2...
 3-const posts = [
 4-  {
 5-    id: 1,
 6-    title: 'Subscribe to GraphQL Weekly for community news ',
 7-    content: 'https://graphqlweekly.com/',
 8-    published: true,
 9-  },
10-  {
11-    id: 2,
12-    title: 'Follow DigitalOcean on Twitter',
13-    content: 'https://twitter.com/digitalocean',
14-    published: true,
15-  },
16-  {
17-    id: 3,
18-    title: 'What is GraphQL?',
19-    content: 'GraphQL is a query language for APIs',
20-    published: false,
21-  },
22-]
23...

接下来,您将更新Query解析器以从数据库中获取发布的帖子。 首先,删除resolvers.Query中的现有行,然后通过添加突出的行来更新对象:

 1[label prisma-graphql/src/schema.js]
 2...
 3const resolvers = {
 4  Query: {
 5    feed: (parent, args) => {
 6      return prisma.post.findMany({
 7        where: { published: true },
 8      })
 9    },
10    post: (parent, args) => {
11      return prisma.post.findUnique({
12        where: { id: Number(args.id) },
13      })
14    },
15  },
16...

在这里,您使用两个 Prisma 客户端查询:

  • 「findMany」會收集「public」字段為「false」的帖子。 * 「findUnique」會收集一個單一的帖子,其「id」字段等同於「id」 GraphQL 論點。

根据 GraphQL 规格,ID类型与String相同地进行序列化,因此您将其转换为Number,因为 Prisma 方案中的idint

接下来,您将更新)`行,然后添加突出的行:

 1[label prisma-graphql/src/schema.js]
 2const resolvers = {
 3  ...
 4  Mutation: {
 5    createDraft: (parent, args) => {
 6      return prisma.post.create({
 7        data: {
 8          title: args.title,
 9          content: args.content,
10        },
11      })
12    },
13    publish: (parent, args) => {
14      return prisma.post.update({
15        where: {
16          id: Number(args.id),
17        },
18        data: {
19          published: true,
20        },
21      })
22    },
23  },
24}

您正在使用两个 Prisma 客户端查询:

  • 「創建」以創建「郵件」記錄. * 「更新」以更新「郵件」記錄的發表欄位,其「id」匹配問卷中的記錄。

最后,删除resolvers.Post对象:

1[label prisma-graphql/src/schema.js]
2...
3-Post: {
4-  content: (parent) => parent.content,
5-  id: (parent) => parent.id,
6-  published: (parent) => parent.published,
7-  title: (parent) => parent.title,
8-},
9...

您的schema.js现在应该读到如下:

 1[label prisma-graphql/src/schema.js]
 2const { gql } = require('apollo-server')
 3const { prisma } = require('./db')
 4
 5const typeDefs = gql`
 6  type Post {
 7    content: String
 8    id: ID!
 9    published: Boolean!
10    title: String!
11  }
12
13  type Query {
14    feed: [Post!]!
15    post(id: ID!): Post
16  }
17
18  type Mutation {
19    createDraft(content: String, title: String!): Post!
20    publish(id: ID!): Post
21  }
22`
23
24const resolvers = {
25  Query: {
26    feed: (parent, args) => {
27      return prisma.post.findMany({
28        where: { published: true },
29      })
30    },
31    post: (parent, args) => {
32      return prisma.post.findUnique({
33        where: { id: Number(args.id) },
34      })
35    },
36  },
37  Mutation: {
38    createDraft: (parent, args) => {
39      return prisma.post.create({
40        data: {
41          title: args.title,
42          content: args.content,
43        },
44      })
45    },
46    publish: (parent, args) => {
47      return prisma.post.update({
48        where: {
49          id: Number(args.id),
50        },
51        data: {
52          published: true,
53        },
54      })
55    },
56  },
57}
58
59module.exports = {
60  resolvers,
61  typeDefs,
62}

保存并关闭文件。

现在您已经更新了解决方案以使用 Prisma 客户端,请启动服务器以使用以下命令来测试 GraphQL API 和数据库之间的数据流:

1npm start

再次,您将收到以下输出:

1[secondary_label Output]
2Server ready at: http://localhost:8080

从输出中打开 Apollo GraphQL Studio 地址,并使用相同的查询从 [步骤 3] 测试 GraphQL API(https://andsky.com/tech/tutorials/how-to-build-a-graphql-api-with-prisma-and-deploy-to-digitalocean-s-app-platform# step-3-creating-the-graphql-server)。

现在,您将进行更改,以便将更改部署到 App Platform. 用CTRL+C关闭 Apollo 服务器。

要避免对node_modules文件夹和.env文件进行委托,请检查项目文件夹中的.gitignore文件:

1cat .gitignore

确认您的 .gitignore 文件包含这些行:

1[label prisma-graphql/.gitignore]
2node_modules
3.env

如果没有,则更新文件以匹配。

保存和退出文件。

然後執行以下兩個命令來執行變更:

1git add .
2git commit -m 'Add Prisma'

您将收到这样的输出响应:

 1[secondary_label Output]
 2git commit -m 'Add Prisma'
 3[main 1646d07] Add Prisma
 4 9 files changed, 157 insertions(+), 39 deletions(-)
 5 create mode 100644 .gitignore
 6 create mode 100644 docker-compose.yml
 7 create mode 100644 prisma/migrations/20201201110111_init/migration.sql
 8 create mode 100644 prisma/migrations/migration_lock.toml
 9 create mode 100644 prisma/schema.prisma
10 create mode 100644 src/db.js

您已更新您的 GraphQL 解析器以使用 Prisma 客户端对您的数据库进行查询和突变,然后将所有更改转移到您的远程存储库。

第9步:在应用平台中创建和迁移PostgreSQL数据库

在此步骤中,您将在 App Platform 中将 PostgreSQL 数据库添加到您的应用程序中,然后您将使用 Prisma Migrate 对其进行迁移,以便部署的数据库方案匹配您的本地数据库。

首先,访问 应用平台控制台并选择您在步骤 5 中创建的 prisma-graphql 项目。

接下来,单击创建按钮,并从下载菜单中选择创建/附加数据库,这将引导您到一个页面来配置您的数据库。

Screencapture displaying the Create/Attach Database option in the dropdown menu

选择 Dev 数据库 ,选择一个名称,然后单击** 创建和附加** 。

"Configure your Database"

您将被重定向到 项目 视图,在那里将有创建数据库的进度栏。

Screencapture displaying the Creating Database Progress Bar

创建数据库后,您将从本地机器运行数据库迁移到 DigitalOcean 上的生产数据库。

要获取它,请点击 db 图标在 ** 设置** 卡的** 组件** 部分。

Screencapture displaying the Database Component Settings

连接详细信息 下,按** 查看** ,然后在下滑菜单中选择** 连接字符串** 。

1postgresql://db:some_password@unique_identifier.db.ondigitalocean.com:25060/db?sslmode=require

然后,在终端中运行以下命令,确保您将your_db_connection_string设置为您刚刚复制的 URL:

1DATABASE_URL="your_db_connection_string" npx prisma migrate deploy

此命令将使用 Prisma Migrate 对实时数据库进行迁移。

如果迁移成功,您将收到以下输出:

1[secondary_label Output]
2PostgreSQL database db created at unique_identifier.db.ondigitalocean.com:25060
3
4Prisma Migrate applied the following migration(s):
5
6migrations/
7  └─ 20201201110111_init/
8    └─ migration.sql

您已成功迁移到 DigitalOcean 的生产数据库,该数据库现在符合 Prisma 方案。

注意: 如果您收到以下错误消息:

1[secondary_label Output]
2Error: P1001: Can't reach database server at `unique_identifier.db.ondigitalocean.com`:`25060`

浏览数据库仪表板以确认您的数据库已配置,您可能需要更新或禁用数据库的 可信源

现在,您可以通过使用以下命令按下 Git 更改来部署您的应用:

1git push

注意: **应用平台将在运行时为您的应用程序提供DATABASE_URL环境变量。

如果您打开 App Platform 控制台,您将有部署进度栏。

Screencapture displaying the Deployment Progress Bar

一旦部署成功,您将收到一个 部署直播 消息。

您现在已经使用数据库备份了部署的 GraphQL API。 打开 Live App ,将引导您到Apollo GraphQL Studio。

在最后一步中,您将通过添加用户模型来发展GraphQL API。

第10步:添加用户模型

您的博客图形QL API 有一个名为),这将使您能够代表文章作者,并向每个用户提供多个文章。 然后,您将演化 GraphQL 计划,以便通过 API 创建用户和与用户连接的帖子.

首先,打开 Prisma 方案:

1nano prisma/schema.prisma

添加突出的行,将authorId字段添加到Post模型中,并定义User模型:

 1[label prisma-graphql/prisma/schema.prisma]
 2...
 3model Post {
 4  id Int     @id @default(autoincrement())
 5  title String
 6  content String?
 7  published Boolean @default(false)
 8  author User?   @relation(fields: [authorId], references: [id])
 9  authorId Int?
10}
11
12model User {
13  id Int    @id @default(autoincrement())
14  email String @unique
15  name String
16  posts Post[]
17}

您已将以下项目添加到 Prisma 方案中:

  • 两个关系字段:作者帖子。关系字段定义了Prisma级别的模型之间的连接,并且在数据库中不存在。这些字段用于生成Prisma客户端并访问Prisma客户端的关系。 * autorId字段由@relation属性引用。

帖子模型中的作者字段是可选的,但允许您创建与用户无关的帖子。

保存和退出文件一旦完成。

接下来,使用以下命令在本地创建和应用迁移:

1npx prisma migrate dev --name "add-user"

成功迁移后,您将收到以下消息:

 1[secondary_label Output]
 2Environment variables loaded from .env
 3Prisma schema loaded from prisma/schema.prisma
 4Datasource "db": PostgreSQL database "my-blog", schema "public" at "localhost:5432"
 5
 6Applying migration `20201201123056_add_user`
 7
 8The following migration(s) have been created and applied from new schema changes:
 9
10migrations/
11  └─ 20201201123056_add_user/
12    └─ migration.sql
13
14Your database is now in sync with your schema.
15
16 Generated Prisma Client (4.6.1 | library) to ./node_modules/@prisma/client in 53ms

该命令还会生成 Prisma 客户端,以便您可以使用新的表和字段。

现在,您将对 App Platform 上的生产数据库进行迁移,以便数据库方案与本地数据库相同。

1DATABASE_URL="your_db_connection_string" npx prisma migrate deploy

您将获得以下输出:

 1[secondary_label Output]
 2Environment variables loaded from .env
 3Prisma schema loaded from prisma/schema.prisma
 4Datasource "db": PostgreSQL database "db", schema "public" at "unique_identifier.db.ondigitalocean.com:25060"
 5
 62 migrations found in prisma/migrations
 7
 8Applying migration `20201201123056_add_user`
 9
10The following migration have been applied:
11
12migrations/
13  └─ 20201201123056_add_user/
14    └─ migration.sql
15
16All migrations have been successfully applied.

您现在将更新 GraphQL 方案和解决方案,以使用更新的数据库方案。

打开src/schema.js文件:

1nano src/schema.js

更新「typeDefs」以以下列出的行:

 1[label prisma-graphql/src/schema.js]
 2...
 3const typeDefs = gql`
 4  type User {
 5    email: String!
 6    id: ID!
 7    name: String
 8    posts: [Post!]!
 9  }
10
11  type Post {
12    content: String
13    id: ID!
14    published: Boolean!
15    title: String!
16    author: User
17  }
18
19  type Query {
20    feed: [Post!]!
21    post(id: ID!): Post
22  }
23
24  type Mutation {
25    createUser(data: UserCreateInput!): User!
26    createDraft(authorEmail: String, content: String, title: String!): Post!
27    publish(id: ID!): Post
28  }
29
30  input UserCreateInput {
31    email: String!
32    name: String
33    posts: [PostCreateWithoutAuthorInput!]
34  }
35
36  input PostCreateWithoutAuthorInput {
37    content: String
38    published: Boolean
39    title: String!
40  }
41`
42...

在此更新代码中,您将添加以下更改到 GraphQL 方案:

  • 用户类型,返回一组邮件。 * 作者字段到邮件类型。 * CreateUser突变,预计UserCreateInput作为其输入类型。 * PostCreateWithoutAuthorInput输入类型用于创建CreateUser突变的一部分的UserCreateInput输入。

随着方案更新,您现在将更新解决方案,以匹配方案。

更新resolvers对象以如下所突出的行:

 1[label prisma-graphql/src/schema.js]
 2...
 3const resolvers = {
 4  Query: {
 5    feed: (parent, args) => {
 6      return prisma.post.findMany({
 7        where: { published: true },
 8      })
 9    },
10    post: (parent, args) => {
11      return prisma.post.findUnique({
12        where: { id: Number(args.id) },
13      })
14    },
15  },
16  Mutation: {
17    createDraft: (parent, args) => {
18      return prisma.post.create({
19        data: {
20          title: args.title,
21          content: args.content,
22          published: false,
23          author: args.authorEmail && {
24            connect: { email: args.authorEmail },
25          },
26        },
27      })
28    },
29    publish: (parent, args) => {
30      return prisma.post.update({
31        where: { id: Number(args.id) },
32        data: {
33          published: true,
34        },
35      })
36    },
37    createUser: (parent, args) => {
38      return prisma.user.create({
39        data: {
40          email: args.data.email,
41          name: args.data.name,
42          posts: {
43            create: args.data.posts,
44          },
45        },
46      })
47    },
48  },
49  User: {
50    posts: (parent, args) => {
51      return prisma.user
52        .findUnique({
53          where: { id: parent.id },
54        })
55        .posts()
56    },
57  },
58  Post: {
59    author: (parent, args) => {
60      return prisma.post
61        .findUnique({
62          where: { id: parent.id },
63        })
64        .author()
65    },
66  },
67}
68...

)来创建创建的草案与现有用户之间的关系。

新的 createUser 突变解析器使用 nested writes创建用户和相关帖子。

在)来查找关系。

保存和退出文件。

启动服务器来测试 GraphQL API:

1npm start

首先,用以下 GraphQL 突变来测试 CreateUser 解析器:

1[environment second]
2mutation {
3  createUser(data: { email: "[email protected]", name: "Natalia" }) {
4    email
5    id
6  }
7}

这种变异将创建一个用户。

接下来,测试createDraft解析器与以下突变:

 1[environment second]
 2mutation {
 3  createDraft(
 4    authorEmail: "[email protected]"
 5    title: "Deploying a GraphQL API to App Platform"
 6  ) {
 7    id
 8    title
 9    content
10    published
11    author {
12      id
13      name
14    }
15  }
16}

当查询的返回值为邮件时,您可以获取作者

完成测试后关闭服务器。

然后进行更改,并按下部署 API:

1git add .
2git commit -m "add user model"
3git push

可能需要几分钟才能部署您的更新。

您已成功地使用 Prisma Migrate 开发了您的数据库方案,并在您的 GraphQL API 中曝光了新模型。

结论

在本文中,您使用 Prisma 构建了 GraphQL API,并将其部署到 DigitalOcean 应用平台上。您用 Apollo Server 定义了 GraphQL 方案和解决方案,然后在您的 GraphQL 解决方案中使用 Prisma Client 来持续和查询 PostgreSQL 数据库中的数据。

如果您有兴趣探索数据库中的数据,请查看 Prisma Studio。您还可以访问 Prisma 文档了解 Prisma 的不同方面,并探索在 prisma-examples存储库中一些准备好运行的示例项目。

您可以在 DigitalOcean 社区库找到该项目的代码。

Published At
Categories with 技术
comments powered by Disqus