prisma orm_如何使用Node.js和Prisma构建GraphQL服务器

司空坚
2023-12-01

prisma orm

介绍 (Introduction)

Prisma is a data layer that turns a database into a GraphQL API. We can look at it as a kind of Object-Relational Mapper (ORM), but it’s much more powerful than traditional ORMs. With Prisma, we get a server (Prisma server) that acts as a proxy for our database and a high-performance query engine that runs on the server, which generates actual database queries for us. In addition to these, we also get a client (Prisma client), which we can use to interact with the server. Prisma also adds an event system to our database, so we can subscribe to database events in realtime.

Prisma是将数据库转换为GraphQL API的数据层。 我们可以将其视为一种对象关系映射器(ORM),但它比传统的ORM强大得多。 使用Prisma,我们可以获得一个服务器(Prisma服务器)作为数据库的代理,并在服务器上运行高性能查询引擎,该引擎为我们生成实际的数据库查询。 除这些以外,我们还获得了一个客户端(Prisma客户端),可用于与服务器交互。 Prisma还向我们的数据库添加了一个事件系统,因此我们可以实时订阅数据库事件。

Prisma works with both new and existing databases. In the case of an existing database, Prisma will generate the datamodel based on the database schema.

Prisma可与新数据库和现有数据库一起使用。 对于现有数据库,Prisma将基于数据库架构生成数据模型。

In this tutorial, you will build a GraphQL server using Prisma as a data layer.

在本教程中,您将使用Prisma作为数据层构建GraphQL服务器。

先决条件 (Prerequisites)

This tutorial assumes the following:

本教程假定以下内容:

  • Node.js and npm installed on your computer

    计算机上安装了Node.js和npm

  • Basic knowledge of GraphQL

    GraphQL的基础知识

棱镜工作原理概述 (Overview of How Prisma Works)

Having seen what Prisma is, let’s take a look at how it works. First, let’s look at how it works with a new database:

了解了Prisma是什么之后,让我们看一下它的工作原理。 首先,让我们看一下它如何与新数据库一起工作:

Prisma的新数据库 (New Database with Prisma)

  • Create a new Prisma service

    创建一个新的Prisma服务
  • Set up and connect Prisma with your database

    设置Prisma并将其与数据库连接
  • Define the datamodel

    定义数据模型
  • Deploy the Prisma API

    部署Prisma API
  • Generate the Prisma client for your programming language of choice

    为您选择的编程语言生成Prisma客户端
  • Create a GraphQL server that uses the Prisma client to interact with your database

    创建一个使用Prisma客户端与您的数据库进行交互的GraphQL服务器

Now, let’s see how it works with an existing database.

现在,让我们看看它如何与现有数据库一起工作。

具有Prisma的现有数据库 (Existing Database with Prisma)

  • Create a new Prisma service

    创建一个新的Prisma服务
  • Set up and connect Prisma with your existing database, using the Prisma Docker image

    使用Prisma Docker映像设置Prisma并将其与现有数据库连接
  • Generate the datamodel from your database schema

    从数据库架构生成数据模型
  • Deploy the Prisma API

    部署Prisma API
  • Generate the Prisma client for your programming language of choice

    为您选择的编程语言生成Prisma客户端
  • Create a GraphQL server that uses the Prisma client to interact with your database

    创建一个使用Prisma客户端与您的数据库进行交互的GraphQL服务器

Note: To use Prisma locally, you need to have Docker installed on your machine. Also, using an existing database with Prisma currently only works when using PostgreSQL databases.

注意:要在本地使用Prisma,您需要在计算机上安装Docker。 另外,将现有数据库与Prisma一起使用目前仅在使用PostgreSQL数据库时有效。

第1步-设置项目 (Step 1 — Setting Up the Project)

To get started with Prisma, we need to install the Prisma CLI. There are a couple of ways to install the CLI, but we’ll be installing it using npm:

要开始使用Prisma,我们需要安装Prisma CLI。 有两种安装CLI的方法,但是我们将使用npm进行安装:

  • npm install -g prisma

    npm install -g棱镜

With the CLI installed, we can start using it. We’ll use it to create a new Prisma service:

安装CLI后,我们就可以开始使用它了。 我们将使用它来创建新的Prisma服务:

  • prisma init test-task-manager

    棱镜初始测试任务管理器

Choose Demo server from the prompt to use an hosted demo server that already has a database included, then we’ll be redirected to log in (or sign up if we don’t have an account yet) to Prisma Cloud to grant the CLI permissions to our account.

从提示中选择Demo server ,以使用已包含数据库的托管演示服务器,然后将我们重定向到Prisma Cloud(如果没有帐户,则进行登录)以授予CLI权限到我们的帐户。

Note: Because we are using the demo server, which is hosted on Prisma cloud, we will need a Prisma cloud account. An account with Prisma cloud is not necessary to use Prisma itself.

注意:由于我们正在使用演示服务器,该服务器托管在Prisma云上,因此我们需要一个Prisma云帐户。 使用Prisma本身不需要使用Prisma云帐户。

Back to the terminal, choose any of the provided regions of the demo server. Then choose the defaults for both the name for our service and the name for our stage, that is, test-task-manager and dev respectively. Lastly, select Prisma JavaScript Client as the programming language for the generated Prisma client.

返回终端,选择演示服务器提供的任何区域。 然后为我们的服务名称和阶段名称选择默认值,分别是test-task-managerdev 。 最后,选择Prisma JavaScript Client作为生成的Prisma客户端的编程语言。

This will create two files: datamodel.prisma and prisma.yml inside the project directory. Also, a Prisma client will be auto-generated. We’ll go through these files shortly.

这将创建两个文件: datamodel.prismaprisma.yml项目目录内。 此外,Prisma客户端将自动生成。 我们将很快处理这些文件。

Based on the types defined inside datamodel.prisma, a GraphQL API is exposed with CRUD (Create, Read, Update, and Delete) and realtime operations. This API is called the Prisma API.

基于内部定义的类型datamodel.prisma ,一个GraphQL API进行曝光CRUD(创建,读取,更新和删除)和实时操作。 该API称为Prisma API。

Now, let’s deploy our newly created Prisma API:

现在,让我们部署我们新创建的Prisma API:

  • cd test-task-manager

    cd测试任务管理器
  • prisma deploy

    棱柱形展开

This will deploy the default User type that Prisma created for us to our selected region. It will also display the live endpoints (HTTP and Websocket. We are only interested in HTTP in this tutorial) for our Prisma GraphQL database.

这会将Prisma为我们创建的默认User类型部署到我们选择的区域。 它还将显示Prisma GraphQL数据库的实时端点(HTTP和Websocket。我们仅对本教程中的HTTP感兴趣)。

Now, we can take our new Prisma API for a spin in the GraphQL Playground:

现在,我们可以在GraphQL Playground中试用我们的新Prisma API:

  • prisma playground

    棱镜游乐园

We can access this at http://localhost:3000/playground.

我们可以在http://localhost:3000/playground访问它。

Let’s create a new user with the following mutation:

让我们创建一个具有以下突变的新用户:

mutation {
  createUser(data: { name: "Chimezie" }) {
    id
    name
  }
}

了解Prisma文件 (Understanding the Prisma Files)

Before we dive deep into building the GraphQL server for our app, let’s quickly go through the files Prisma generated for us.

在深入研究为我们的应用构建GraphQL服务器之前,让我们快速浏览一下Prisma为我们生成的文件。

  • prisma.yml: This is the configuration file for Prisma. It contains everything that’s required to set up a Prisma service.

    prisma.yml :这是Prisma的配置文件。 它包含设置Prisma服务所需的一切。

  • datamodel.priama: Specifies the datamodel for our application that will be mapped to the database. In other words, it is used to define our database schema.

    datamodel.priama :指定将映射到数据库的应用程序的数据模型。 换句话说,它用于定义我们的数据库模式。

  • generated/prisma-client: Contains the auto-generated Prisma client library, which can be used to interact with the Prisma API.

    generated/prisma-client :包含自动生成的Prisma客户端库,该库可用于与Prisma API进行交互。

第2步-创建GraphQL服务器 (Step 2 — Creating a GraphQL Server)

If all our GraphQL API will do is perform basic CRUD operations, then we would be fine with just the GraphQL API Prisma generated for us. In most cases we would want more than that, so we need to create a GraphQL server to handle our domain-specific logic as well as integrate with third-party services.

如果我们所有的GraphQL API所要做的就是执行基本的CRUD操作,那么只使用为我们生成的GraphQL API Prisma就可以了。 在大多数情况下,我们会想要更多,因此我们需要创建一个GraphQL服务器来处理特定于域的逻辑以及与第三方服务集成。

We’ll be using graphql-yoga to create our GraphQL server. Let’s install it along with the other dependency we’ll be needing:

我们将使用graphql-yoga创建我们的GraphQL服务器。 让我们将其与我们将需要的其他依赖项一起安装:

  • yarn add graphql-yoga prisma-client-lib

    纱线添加graphql-yoga pyramida-client-lib

prisma-client-lib is needed to run the Prisma client that was generated for us.

prisma-client-lib运行为我们生成的Prisma客户端。

Once that’s done installing, create a new directory called src directly within the project’s root directory.

安装完成后,直接在项目的根目录中创建一个名为src的新目录。

  • mkdir src

    mkdir src

Then let’s move the generated directory inside the src directory:

然后,将generated目录移动到src目录中:

mv generated src

Next, update prisma.yml to reflect the new location:

接下来,更新prisma.yml以反映新位置:

# prisma.yml

generate:
  - generator: javascript-client
    output: ./src/generated/prisma-client/

Within the src directory, create a new file called index.js:

src目录中,创建一个名为index.js的新文件:

  • cd src

    光盘src
  • touch index.js

    触摸index.js

Then add the following code to it:

然后向其中添加以下代码:

// src/index.js

const { prisma } = require('./generated/prisma-client')
const { GraphQLServer } = require('graphql-yoga')
const resolvers = require('./resolvers')

const server = new GraphQLServer({
  typeDefs: './src/schema.graphql',
  resolvers,
  context: {
    prisma
  }
})

server.start(() => console.log('Server is running on http://localhost:4000'))

Here we import the Prisma client, graphql-yoga, and our resolver functions (we’ll create in a moment). Then we create a new GraphQL server, passing to it our schema (we’ll create this in a moment), the resolver functions, and lastly the context, which contains the Prisma client. We pass the Prisma client to the context so that we’ll be able to use it inside our resolver functions. Finally, we start the GraphQL server.

在这里,我们导入Prisma客户端graphql-yoga和我们的解析器功能(我们将在稍后创建)。 然后,我们创建一个新的GraphQL服务器,将架构(稍后将创建它),解析器功能以及最后包含Prisma客户端的上下文传递给它。 我们将Prisma客户端传递给上下文,以便可以在解析器函数中使用它。 最后,我们启动GraphQL服务器。

第3步-更新数据模型 (Step 3 — Updating the Datamodel)

Let’s define the datamodel of our app. The app will be made up of two types: Project and Task. Update datamodel.prisma as follows:

让我们定义应用程序的数据模型。 该应用将由两种类型组成: ProjectTask 。 如下更新datamodel.prisma

# datamodel.prisma

type Project {
  id: ID! @unique
  name: String!
  tasks: [Task!]!
}

type Task {
  id: ID! @unique
  title: String!
  project: Project!
  isCompleted: Boolean! @default(value: false)
}

The Project type has three fields; the ID of the project, the name of the project, and lastly the project’s tasks. We use the @unique directive on the id field because we want it to be unique for each project. It will be set as the primary key on the database table. All the fields are required (denoted with !). The tasks field will return a list of tasks that makes up the project because it is enclosed in []. Notice it has two !, which means the list of tasks cannot contain null, but the whole list can be empty.

Project类型具有三个字段; 项目的ID,项目的名称,最后是项目的任务。 我们在id字段上使用@unique指令,因为我们希望它对于每个项目都是唯一的。 它将被设置为数据库表上的主键。 所有字段都是必填字段(以!表示)。 tasks字段将返回组成项目的任务列表,因为它包含在[] 。 注意它有两个! ,这意味着任务列表不能包含null ,但是整个列表可以为空。

The Task type is similar to the Project type. It has a project field, which will be the particular project the task belongs to. Then it has an isCompleted field, which indicates whether a task has been completed or not. We give the field a default value of false using the @default directive.

Task类型类似于Project类型。 它有一个project字段,它将是任务所属的特定项目。 然后,它具有isCompleted字段,该字段指示任务是否已完成。 我们使用@default指令为该字段提供默认值false

Note: The default value must always be in double quotes, even for non-string types such as Boolean or Int.

注意:即使对于非字符串类型(例如Boolean或Int),默认值也必须始终用双引号引起来。

With our datamodel, Project and Type have a one-to-many relationship. A project can have many tasks (because of the tasks field on the Project type) and a task belongs to a project (again, because of the project field on the Task type).

使用我们的数据模型, ProjectType具有一对多关系。 一个项目可以有许多任务(由于Project类型上的tasks字段),并且一个任务属于一个项目(同样由于Task类型上的project字段)。

Note: It is required to use the @relation directive to define a relation when a relation is ambiguous.

注意:当关系不明确时,需要使用@relation指令来定义关系。

For the changes on our datamodel to take effect, we need to redeploy the Prisma API:

为了使数据模型上的更改生效,我们需要重新部署Prisma API:

  • prisma deploy

    棱柱形展开

Warning: If you get this warning You already have nodes for this model. This change will result in data loss for the User type., this is because we created a user earlier and now we don’t need the User type anymore. We just need to force the deploy with prisma deploy --force.

警告:如果收到此警告, You already have nodes for this model. This change will result in data loss for the User type. You already have nodes for this model. This change will result in data loss for the User type. ,这是因为我们之前创建了一个用户,现在不再需要User类型。 我们只需要使用prisma deploy --force强制prisma deploy --force

Also, we need to regenerate the Prisma client. We can do that by running the following command:

另外,我们需要重新生成Prisma客户端。 我们可以通过运行以下命令来做到这一点:

  • prisma generate

    棱镜生成

步骤4 —定义架构 (Step 4 — Defining the Schema)

Now let’s start defining the schema that would make up our GraphQL API. Within the src directory, create a new file called schema.graphql:

现在,让我们开始定义构成GraphQL API的架构。 在src目录中,创建一个名为schema.graphql的新文件:

  • touch schema.graphql

    触摸schema.graphql

Then add the following code in the newly created file:

然后在新创建的文件中添加以下代码:

# src/schema.graphql

type Query {
  projectById(projectId: ID!): Project
  completedTasks: [Task!]!
}

type Mutation {
  createProject(name: String!): Project
  createTask(title: String!, projectId: ID!): Task
  markTaskAsCompleted(taskId: ID!): Task
}

type Project {
  id: ID!
  name: String!
  tasks: [Task!]!
}

type Task {
  id: ID!
  title: String!
  project: Project!
  isCompleted: Boolean!
}

We define a query to fetch a project by its ID and fetch tasks that have been marked as completed respectively. Also, we define the mutations to create a new project, create a new task, and to mark a task as completed. Finally, we define the schema for the types in our datamodel.

我们定义一个查询,以按其ID提取项目并获取分别标记为已完成的任务。 此外,我们定义了变异以创建新项目,创建新任务并将任务标记为已完成。 最后,我们为数据模型中的类型定义模式。

Note: Redefining the schema for the types in the datamodel can be redundant and not easily maintainable, especially for large projects. To avoid redefining them, we can use tools like https://github.com/prisma/graphql-import.

注意:为数据模型中的类型重新定义架构可能是多余的,并且不易维护,尤其是对于大型项目。 为了避免重新定义它们,我们可以使用https://github.com/prisma/graphql-import之类的工具。

第5步—创建解析器功能 (Step 5 — Creating the Resolver Functions)

With the schema defined, let’s create the resolver functions that would handle them. Inside the src directory, create a new file called resolvers.js and add the following code in it:

定义了架构后,让我们创建用于处理它们的解析器函数。 在src目录中,创建一个名为resolvers.js的新文件,并在其中添加以下代码:

// src/resolvers.js

const resolvers = {
  Query: {
    projectById (root, { projectId }, { prisma }) {
      return prisma.project({ id: projectId })
    },
    completedTasks (root, args, { prisma }) {
      return prisma.tasks({ where: { isCompleted: true } })
    }
  },
  Mutation: {
    createProject (root, { name }, { prisma }) {
      return prisma.createProject({ name })
    },
    createTask (root, { title, projectId }, { prisma }) {
      return prisma.createTask({
        title,
        project: { connect: { id: projectId } }
      })
    },
    markTaskAsCompleted (root, { taskId }, { prisma }) {
      return prisma.updateTask({
        where: { id: taskId },
        data: { isCompleted: true }
      })
    }
  },
  Project: {
    tasks (root, args, { prisma }) {
      return prisma.project({ id: root.id }).tasks()
    }
  },
  Task: {
    project (root, args, { prisma }) {
      return prisma.task({ id: root.id }).project()
    }
  }
}

module.exports = resolvers

We start by creating the resolver functions for the queries. Remember, we passed the Prisma client to the context, so we extract it from the context and use it to interact with the Prisma API. The projectById() returns the project whose ID matches the supplied project ID. The completedTasks() does nearly the same thing, but instead it returns a list of tasks that have been marked as completed (that is, isCompleted is true).

我们首先为查询创建解析器功能。 记住,我们将Prisma客户端传递给了上下文,因此我们从上下文中提取了它,并使用它与Prisma API进行交互。 projectById()返回其ID与提供的项目ID匹配的项目。 completedTasks()做几乎相同的事情,但是它返回已标记为已完成的任务列表(即isCompletedtrue )。

If we look at the generated Prisma client, we’ll see that CRUD operations have been generated for us. All we need to do is use them. The createProject() calls the createProject() on the Prisma client, which accepts the data we want to insert, in our case just the name of the project since the project’s ID will be auto-generated for us. In the same vein, the createTask() uses the createTask() on the Prisma client, but in addition to the data to be inserted, we connect the task to the project (through the supplied project ID) it belongs to. The markTaskAsCompleted() updates a task by setting isCompleted to true. It uses the updateTask(), which accepts two arguments: a where clause to get the task to be updated and the data to update it with.

如果我们查看生成的Prisma客户端,将会看到已经为我们生成了CRUD操作。 我们需要做的就是使用它们。 该createProject()调用createProject()的Prisma的客户端,它接受我们要插入的数据,在我们的案例项目,因为该项目的ID会自动生成对我们的只是名字上。 在同样的createTask()使用createTask()的Prisma的客户端上,但除了要插入的数据,我们的任务连接到项目(通过提供的项目ID),它属于。 markTaskAsCompleted()通过将isCompleted设置为true来更新任务。 它使用updateTask() ,它接受两个参数: where子句获取要更新的任务,以及用于更新任务的数据。

Lastly, we create the resolver functions to fetch the custom fields (tasks and project) on the types on our schema.

最后,我们创建解析器函数以获取架构类型上的自定义字段( tasksproject )。

Note: Use the singular form of a model to query for a single object and use the plural form of the model to query for a list of objects. You will notice we are using the singular form of Project to fetch a single project prisma.project({ id: projectId }) and the plural form of Task to fetch a list of tasks prisma.tasks({ where: { isCompleted: true } }).

注意:使用模型的单数形式查询单个对象,并使用模型的复数形式查询对象列表。 您会注意到我们使用Project的单数形式来获取单个项目pyramida.project({id:projectId}),使用Task的复数形式来获取任务列表pyramida.tasks({其中:{isCompleted:true} })。

第6步-测试 (Step 6 — Testing It Out)

Now we can test out our app. First, let’s start the GraphQL server:

现在我们可以测试我们的应用了。 首先,让我们启动GraphQL服务器:

node src/index.js

The server will be up and running at http://localhost:4000 and opening it will load up the GraphQL Playground.

服务器将在http://localhost:4000上启动并运行,打开该服务器将加载GraphQL Playground。

结论 (Conclusion)

In this tutorial, we looked at what Prisma is, then at how to get started with it by building a GraphQL server. We also looked at how to test our GraphQL server using the GraphQL Playground. If you would like to learn more about Prisma, check out the official Prisma docs.

在本教程中,我们研究了Prisma是什么,然后研究了如何通过构建GraphQL服务器来开始使用Prisma。 我们还研究了如何使用GraphQL Playground测试GraphQL服务器。 如果您想了解有关Prisma的更多信息,请查阅Prisma官方文档

翻译自: https://www.digitalocean.com/community/tutorials/how-to-build-a-graphql-server-with-node-js-and-prisma

prisma orm

 类似资料: