使用Prisma构建连接到MySQL的GraphQL API服务器

首先

我们将基于Prisma和graphql-yoga,按照Prisma官方的基础教程“从零开始构建GraphQL服务器”,来编写GraphQL服务器。

本篇文章以与上述教程略有不同的方式表述

    • 言語:TypeScript

 

    DB:ローカルに立てるDocker上のMySQL

我将为您介绍。

在开始教程之前,对于Prisma是什么的人,请问。

    • prisma – 最速 GraphQL Server実装

 

    Prisma.ioでGraphQL APIサーバーを楽して作る

阅读周围的内容,大致了解Prisma,并参考官方的方式。

    Prisma Introduction: What, Why & How

建议您试着确认一下。

目标读者

    • GraphQLに関する知識をある程度有している方

 

    • GraphQL APIを提供するサーバーを簡単に素早く作りたい方

 

    • データベースは自前のMySQLを使いたい方

 

    言語はTypeScriptで書きたい方

执行环境

    • Mac OS Mojave: v10.14.2

 

    • node: v11.2.0

 

    • npm: v6.5.0

 

    • yarn: v1.12.3

 

    • docker: v17.09.1-ce

 

    • prisma: v1.23.4

 

    graphql: v3.0.4

構築GraphQL API服务器(用于前端的后端)

首先,我们将开始构建面向外部提供GraphQL API的BFF。
随后,我们将构建一个不向外部公开的针对内部的Prisma服务器进行封装的架构。

创建并初始化NPM项目目录

mkdir prisma-yoga-mysql-typescript-sample
cd prisma-yoga-mysql-typescript-sample
npm init -y

创建src/index.ts文件

mkdir src
touch src/index.ts

安装graphql-yoga

yarn add graphql-yoga

安装nodemon、ts-node和TypeScript

在这个教程中,我们将在src/index.js中编写代码并执行。然而,为了在TypeScript中完成同样的操作,我们需要安装ts-node库,它可以让我们直接在Node.js上运行TS文件而无需编译,并且还需要安装nodemon来监视文件,并在文件更改时重新启动Node进程。

yarn add -D nodemon ts-node typescript 

更新package.json文件

为了能够通过运行”yarn start”脚本,将package.json文件中的scripts字段的值修改为以下内容。

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "nodemon --ext ts,yaml,graphql --exec 'ts-node' src/index.ts"
  },

只监视扩展名为ts、yaml和graphql的文件。

新增写入到 src/index.ts 文件中

import { GraphQLServer } from 'graphql-yoga';

// GraphQL SDLに沿ってschemaを定義
const typeDefs = `
  type Query {
    description: String
  }
`;

// GraphQL APIのリクエストに応えるための実装
const resolvers = {
  Query: {
    description: () => `This is the API for a simple blogging application`,
  },
};

const server = new GraphQLServer({
  typeDefs,
  resolvers,
});

server.start(() =>
  console.log(`The server is running on http://localhost:4000`),
);

当您在此保存时,如果在命令行上执行”yarn start”,则应该会在http://localhost:4000上启动服务器。

如果成功执行以下查询并返回结果,则访问http://localhost:4000。

{
  description
}
スクリーンショット 2019-01-07 3.44.41.png

创建src/schema.graphql

为了重新定义GraphQL模式,并且与已经分配给src/index.ts的typeDefs不同,我们将创建一个名为schema.graphql的文件。

touch src/schema.graphql
type Query {
  posts: [Post!]!
  post(id: ID!): Post
  description: String!
}

type Mutation {
  createDraft(title: String!, content: String): Post
  deletePost(id: ID!): Post
  publish(id: ID!): Post
}

type Post {
  id: ID!
  title: String!
  content: String!
  published: Boolean!
}

src/index.ts的更新

为了加载上面创建的模式,请将src/index.ts按以下方式修改。

import { GraphQLServer } from 'graphql-yoga';

// GraphQL SDLに沿ってschemaを定義
// const typeDefs = `
//   type Query {
//     description: String
//   }
// `;

// GraphQL APIのリクエストに応えるための実装
const resolvers = {
  Query: {
    description: () => `This is the API for a simple blogging application`,
  },
};

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

server.start(() =>
  console.log(`The server is running on http://localhost:4000`),
);

在每个保存之后,如果由nodemon重新启动了进程,请直接访问http://localhost:4000,如果模式已经反映如下,那就没问题了。

スクリーンショット 2019-01-07 4.13.42.png

搭建针对Prisma服务器的内部端构建。

从这里开始使用Prisma构建一个面向内部的服务器。
即将创建的面向内部的GraphQL API服务器将直接对数据库执行查询。

Prisma CLI的全局安装

如果您尚未能够使用prisma命令,请进行全局安装。
(附注:本文章假设Prisma的版本为1.23.4,如果CLI未安装1.23.4版本,它将无法正常运行)

npm install -g prisma@1.23.4

创建数据库目录

当在项目的根目录下执行下列Prisma命令时。

prisma init database

由于我们选择使用REPL来实现,所以我们分别选择”创建新数据库”、”MySQL”和”Prisma TypeScript客户端”。请注意,这与原始教程中的第13步骤所选择的不同。

 % prisma init database
? Set up a new Prisma server or deploy to an existing server? 

  Set up a new Prisma server for local development (based on docker-compose):
  Use existing database      Connect to existing database 
❯ Create new database        Set up a local database using Docker 

  Or deploy to an existing Prisma server:
  Demo server                Hosted demo environment incl. database (requires login) 
  Use other server           Manually provide endpoint of a running Prisma server

? What kind of database do you want to deploy to? (Use arrow keys)
❯ MySQL             MySQL compliant databases like MySQL or MariaDB 
  PostgreSQL        PostgreSQL database 
  MongoDB           Mongo Database 

? Select the programming language for the generated Prisma client 
❯ Prisma TypeScript Client 
  Prisma Flow Client 
  Prisma JavaScript Client 
  Prisma Go Client 
  Don't generate 

执行命令后,应该会创建一个名为database的目录,并按照以下结构组织:
(原始教程中提到应该创建database/datamodel.graphql,但在prisima 1.23.4版本上执行时,将创建database/datamodel.prisma代替)

├── database
│   ├── datamodel.prisma // DBのテーブル構造元となる型定義
│   ├── docker-compose.yml
│   ├── generated
│   │   └── prisma-client
│   │       ├── index.ts
│   │       └── prisma-schema.ts
│   └── prisma.yml // Prismaサーバーの設定ファイル
├── package.json
├── src
    ├── index.ts
    └── schema.graphql

数据模型.prisma的更新

请按照本教程的指导,使用以下内容重写datamodel.prisma。

type Post {
  id: ID! @unique
  title: String!
  content: String!
  published: Boolean! @default(value: "false")
}

我认为您可能能够大致想象上述内容的定义,一旦部署这个应用,它会与”Post”表进行映射,并且称为“id~published”的字段部分会被映射到各个列上。
“!”表示不为空,”@unique”表示该字段的值在整个表中是唯一的。
“@default”表示如果在插入记录时没有指定”published”的值,那么将自动分配false作为默认值。

如果您想详细了解在此出现的@unique、@default等被称为指令的内容,请参考GraphQL的官方文档等。

设置DB连接端口

以下是一个示例,用中文来重新表达给定的语句:

这个设置是可选的,但如果您想直接连接到数据库,请根据以下方式修改 database/docker-compose.yml文件中的services.mysql.ports的值。

  mysql:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: prisma
    volumes:
      - mysql:/var/lib/mysql
    ports:
      - "3333:3306"

启动Docker容器

要部署Prisma,需要确保能够连接到数据库。
在命令行中,切换到包含docker-compose.yml文件的database目录,并执行docker-compose up命令,启动Docker容器。

cd database 
docker-compose up

Prisma的部署

在启动了Docker容器后,使用另一个命令行窗口再次进入database目录,并执行prisma deploy命令,将其部署到database/prisma.yml文件中所指定的 http://localhost:4466 地址上。

cd database
prisma deploy

部署完成后,将同时对数据库执行迁移操作。
完成部署后,访问 http://localhost:4466 ,打开 DOCS 页面,您会发现 Post 表的增删改查功能已经实现了。

スクリーンショット 2019-01-07 5.53.19.png

另外,如果在上述進行了用於數據庫連接的端口設定,您可以使用Sequel Pro等數據庫客戶端工具以以下設定來訪問數據庫。(用戶名、密碼和端口可以通過docker-compose.yml進行更改)

スクリーンショット 2019-11-07 12.58.35.png

将Prisma服务器与BFF进行关联

最后,我们将对Prisma服务器进行直接操作,并将其与BFF(用于向外部公开的GraphQL API服务器)进行绑定,通过公开的GraphQL API执行Prisma服务器的GraphQL API,并使其能够对数据库进行操作。

创建与Prisma服务器的关联设置文件。

前往项目根目录,创建.graphqlconfig.yml文件,并按以下方式进行配置。

touch .graphqlconfig.yml 
projects:
  database:
    schemaPath: src/generated/prisma.graphql
    extensions:
      prisma: database/prisma.yml
  app:
    schemaPath: src/schema.graphql
    extensions:
      endpoints:
        default: http://localhost:4000

创建Prisma的模式文件。

执行以下命令,在上述Yaml文件的projects.database.schemaPath指定的路径中生成模式文件。

graphql get-schema

安装 prisma-binding

安装所需的库prisma-binding来进行链接。

yarn add prisma-binding

src/index.ts的更新

使用安装的prisma-binding库中的Prisma类来修改src/index.ts,以便使用src/generated/prisma.graphql文件在上面创建。

import { GraphQLServer } from 'graphql-yoga';
import { Prisma } from 'prisma-binding';
import { IResolvers } from 'graphql-middleware/dist/types';

const resolvers: IResolvers = {
  Query: {
    posts(parent, args, ctx, info) {
      return ctx.db.query.posts({}, info);
    },
    post(parent, args, ctx, info) {
      return ctx.db.query.post({ where: { id: args.id } }, info);
    },
  },
  Mutation: {
    createDraft(parent, { title, content }, ctx, info) {
      return ctx.db.mutation.createPost(
        {
          data: {
            title,
            content,
          },
        },
        info,
      );
    },
    deletePost(parent, { id }, ctx, info) {
      return ctx.db.mutation.deletePost({ where: { id } }, info);
    },
    publish(parent, { id }, ctx, info) {
      return ctx.db.mutation.updatePost(
        {
          where: { id },
          data: { published: true },
        },
        info,
      );
    },
  },
};

const server = new GraphQLServer({
  typeDefs: './src/schema.graphql',
  resolvers,
  context: req => ({
    ...req,
    db: new Prisma({
      typeDefs: 'src/generated/prisma.graphql', // the generated Prisma DB schema
      endpoint: 'http://localhost:4466', // the endpoint of the Prisma DB service
      // secret: "mysecret123", // specified in database/prisma.yml
      debug: true, // log all GraphQL queries & mutations
    }),
  }),
});

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

升级 src/schema.graphql。

我们可以通过以下方式对src/schema.graphql进行修改,以便能够使用在src/generated/prisma.graphql中定义的Post类型。

# import Post from "./generated/prisma.graphql"

type Query {
  posts: [Post!]!
  post(id: ID!): Post
  description: String!
}

type Mutation {
  createDraft(title: String!, content: String): Post
  deletePost(id: ID!): Post
  publish(id: ID!): Post
}

最后

Prisma可以解决N+1问题吗?据下述文章所述,Prisma能解决N+1问题,因此我们希望能在实际应用中使用它。

源代码

你可以从以下的GitHub链接中找到我们最新创建的样本:
https://github.com/galoi/prisma-yoga-mysql-typescript-sample

另外,我参考了其他的文章。

    GraphQLの旅(2) Prismaで開発したGraphQL APIを公開
广告
将在 10 秒后关闭
bannerAds