使用apollo-server、prisma和MySQL构建GraphQL服务器
首先
我总结了使用apollo-server + prisma + MySQL构建GraphQL服务器的步骤。
apollo-server 是什么?
https://www.apollographql.com/docs/ 是指什么?
Prisma 是什么?
参考链接:https://www.prisma.io/docs/concepts/overview/what-is-prisma
所有步骤
首先需要安装 Node.js 才能继续下一步操作,接下来的步骤是使用 npm 进行操作,但您也可以根据个人喜好使用 yarn 或其他工具。首先仅使用 apollo-server 搭建 GraphQL 服务器,然后使用 prisma 与 MySQL 进行连接,最后将它们两者连接在一起。
构建apollo-server
可以按照官方的 Get started 指南快速简便地创建。请参考链接 https://www.apollographql.com/docs/apollo-server/getting-started。
按照这个步骤,每个文件应该按照以下方式进行。
※由于上述URL推荐使用TypeScript,这里也将使用它。
{
"name": "graphql-server-example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"compile": "tsc",
"start": "npm run compile && node ./dist/index.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@apollo/server": "^4.0.4",
"graphql": "^16.6.0"
},
"devDependencies": {
"@types/node": "^18.11.7",
"typescript": "^4.8.4"
}
}
{
"compilerOptions": {
"rootDirs": ["src"],
"outDir": "dist",
"lib": ["es2020"],
"target": "es2020",
"module": "esnext",
"moduleResolution": "node",
"esModuleInterop": true,
"types": ["node"]
}
}
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
// GraphQLサーバで利用するデータ形式(=スキーマ)を定義します。
const typeDefs = `
# データソースのデータ形式です。
type Book {
title: String
author: String
}
# 利用するクエリが返すデータ形式を定義します。
# この場合、booksは0件以上のBookデータの配列を表します。
type Query {
books: [Book]
}
`;
// データセットです。
// 今回は安価に作成するため、定数で定義します。
const books = [
{
title: 'The Awakening',
author: 'Kate Chopin',
},
{
title: 'City of Glass',
author: 'Paul Auster',
},
];
// クエリ実行時、どのようなデータを返すか設定(リゾルバ)をします。
// この場合、上記のデータセットをそのまま返します。
const resolvers = {
Query: {
books: () => books,
},
};
// スキーマとリゾルバを指定し、apollo-server起動準備をします。
const server = new ApolloServer({
typeDefs,
resolvers,
});
// apollo-serverをポート番号:4000で起動します。
const { url } = await startStandaloneServer(server, {
listen: { port: 4000 },
});
console.log(`? Server ready at: ${url}`);
按照公式的说明,启动以下内容
% npm start
Prisma 和 MySQL 的协同配合
由于其他人已经在Docker等平台上发布了MySQL的构建过程,请参考他们的方法。本文不再对MySQL的构建进行介绍。
本次我们将根据已存在于MySQL中的表来创建schema.prisma(使用prisma db pull命令)。
我会在下面准备好表格和记录。
CREATE TABLE `test` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL COMMENT '名前',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '日時',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='テスト';
INSERT INTO `test` (`id`, `name`) VALUES ('1', 'テスト1');
INSERT INTO `test` (`id`, `name`) VALUES ('2', 'テスト2');
INSERT INTO `test` (`id`, `name`) VALUES ('3', 'テスト3');
接下来,需要安装 Prisma 客户端和 Prisma CLI。
安装后,进行 Prisma 的设置(init)。
https://www.prisma.io/docs/concepts/overview/what-is-prisma
https://www.prisma.io/docs/reference/api-reference/command-reference
% npm install @prisma/client prisma
% npx prisma init
接下来,我们需要编辑 prisma/schema.prisma 和 .env 文件,以连接到 MySQL 数据库。
https://www.prisma.io/docs/concepts/database-connectors/mysql
DATABASE_URL="mysql://USER:PASSWORD@HOST:PORT/DATABASE"
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
接下来,从 MySQL 中获取表信息,并执行 prisma 的 generate 命令。
% npx prisma db pull
% npx prisma generate
接下来,为了与apollo-server集成,我们需要编辑 src/index.ts 文件,按照以下方式进行修改。
https://www.prisma.io/apollo
https://www.prisma.io/docs/concepts/components/prisma-client/crud
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
import { PrismaClient } from '@prisma/client';
// prismaの利用
const prisma = new PrismaClient();
const typeDefs = `
# 上記SQLで作成したテーブルの定義
type Test {
id: Int
name: String
created_at: String
}
type Query {
Test: [Test]
}
`;
// testテーブルのレコードを返す
const resolvers = {
Query: {
Test: () => prisma.test.findMany()
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
});
const { url } = await startStandaloneServer(server, {
listen: { port: 4000 },
});
console.log(`? Server ready at: ${url}`);
只需以下一种方式将其以中文进行释义:
当您再次启动 apollo-server 时,
% npm start
虽然我认为已经成功地处理了,但仍然发生了一些错误。
事实上,在 GraphQL 中默认情况下只提供了以下类型(标量类型),无法正确地获取 MySQL 的 BigInt 和 DateTime 类型。
请参考:https://www.apollographql.com/docs/apollo-server/schema/schema#scalar-types
因此,所需要的是定制标量,在此处可以找到:https://www.apollographql.com/docs/apollo-server/schema/custom-scalars
这次我们将使用 graphql-scalars 来很好地组织它们。
https://www.the-guild.dev/graphql/scalars/docs
https://www.the-guild.dev/graphql/scalars/docs/usage/apollo-server
引入graphql-scalars
本次我们将介绍graphql-scalars,它提供了各种自定义标量的支持。
https://www.the-guild.dev/graphql/scalars/docs
使用方法在这里
https://www.the-guild.dev/graphql/scalars/docs/usage/apollo-server
按照以上内容,您需要编辑 src/index.ts 如下。
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
import { PrismaClient } from '@prisma/client';
import {
typeDefs as scalarTypeDefs,
resolvers as scalarResolvers,
} from 'graphql-scalars';
const prisma = new PrismaClient();
const typeDefs = `
type Test {
id: BigInt
name: String
created_at: DateTime
}
type Query {
Test: [Test]
}
`;
const resolvers = {
Query: {
Test: () => prisma.test.findMany()
},
};
const server = new ApolloServer({
resolvers: {
...scalarResolvers,
...resolvers,
},
typeDefs: [
...scalarTypeDefs,
typeDefs,
],
});
const { url } = await startStandaloneServer(server, {
listen: { port: 4000 },
});
console.log(`? Server ready at: ${url}`);
当您再次启动 apollo-server,
% npm start
这次成功取得了。但是尽管日期字段以JST保存在表中,却出现了UTC格式和实际时间不一致的问题。Prisma正在努力解决,但似乎进展不太活跃…
https://github.com/prisma/prisma/discussions/4153 及 https://github.com/prisma/prisma/issues/3292 这两个链接是关于 Prisma 的讨论和问题。
在尚未得到处理之前,似乎只能由API调用方进行相应处理。
结束时
通过上述步骤,我们发现可以使用现有的MySQL相对简单地构建GraphQL服务器。
除了我们介绍的内容外,还有指定记录提取条件,执行记录的插入、更新和删除等功能。但只要按照官方文档操作,也应该能够实现这些功能。