本文属使用Prisma构建GraphQL服务系列。
本文介绍如何使用typescript开发prisma服务。将使用graphql-yoga作为web服务器,并使用prisma-binding连接Prisma数据库服务。
本文代码可从GitHub上的GraphQL样板项目中找到。
先安装node和Docker吧,骚年
安装CLI
本教程使用Prisma CLI管理Prisma数据库服务,第一步先安装CLI工具。
打开终端,全局安装Prisma CLI:
# 1
npm install -g prisma
确保已安装了Docker,再继续.
初始化本地环境,后续可将Prisma服务部署在本地,
## 2
prisma local start
说明:这行命令从Docker下载两个镜像文件,比较大,耐心等待。
构建GraphQL服务
现在可以使用prisma init
命令构建GraphQL 服务。注意,这条命令将触发选择模版的交互式会话。
prisma init
命令my-app
参数,Prisma CLI将创建my-app
目录,此目录下存放项目所有文件。
## 3
prisma init my-app
- 当提示
how you want to set up your Prisma service?
时,选择GraphQL server/fullstack boilerplate(recommended)
选项。 - 接着CLI提示选择GraphQL 样板(
select a GraphQL boilerplate as foundation for your project
)作为基础时,选择typescript-basic样板。 - 最终,提示何处部署(
which cluster you want to deploy
)时,选择local
cluster。
注意,此处的cluster与Docker中的集群还是有点差别,但可以如此理解。
prisma init
命令执行完成后,Prisma 数据库服务部署完成,可以通过 http://localhost:4466/my-app/dev
访问。
如你所知,数据库服务的HTTP端点由以下组件组成:
-
cluster的域(指
~/.prisma/config.yml
文件中的host
属性):http://localhost:4466/my-app/dev
; -
Prisma
service
名字,在prisma.yml
文件中指定:my-app
; - 服务部署
stage
,默认为:dev
。
注意,此端点在src/index.ts
中引用,实例化Prisma
,并绑定application schema与Prisma schema:
const server = new GraphQLServer({
typeDefs: './src/schema.graphql', // points to the application schema
resolvers,
context: req => ({
...req,
db: new Prisma({
endpoint: 'http://localhost:4466/my-app/dev', // the endpoint of the Prisma DB service
secret: 'mysecret123', // specified in `database/prisma.yml`
debug: true, // log all GraphQL queries & mutations
}),
}),
})
文件结构如下:
了解以下:
-
/
(根目录)-
.graphqlconfig.yml
:GraphQL配置文件,包含端点和schema配置. 由graphql-cli
和GraphQL Playground使用。 -
package.json
: npm包管理文件,详见package.json
-
-
/database
-
database/prisma.yml
: 数据库服务配置文件; -
database/datamodel.graphql
数据模型定义(SDL); -
database/seed.graphql
: 初始数据。
-
-
/src
-
src/schema.graphql
定义application schema,指明向客户端公开的GraphQL API ; -
src/generated/prisma.graphql
定义 Prisma schema,根据/database/datamodel.graphql
生成,包含数据模型的CRUD(* Create、Retrieve、Update、Delete) API定义,不要手动修改此文件*,而是通过修改数据模型/database/datamodel.graphql
文件,并通过prisma deploy
命令自动生成。 -
src/index.ts
服务入口, 将所有东西组合起来,通过graphql-yoga
启动GraphQLServer
。
-
最重要的两个文件
database/datamodel.graphql
和src/schema.graphql
。
-
database/datamodel.graphql
:定义数据模型; -
src/schema.graphql
:定义向客户端公开的API。
典型的database/datamodel.graphql`数据模型如下:
type Post {
id: ID! @unique
isPublished: Boolean!
title: String!
text: String!
}
基于此数据模型,Prisma生成Prisma schema,即GraphQL schema,定义了CRUD API,此schema保存在src/generated/prisma.graphql
中,并由CLI在部署时更新。
现在可以启动服务了....
第三步:启动服务
调用package.json
中定义的dev
script,其将启动服务,且打开一个GraphQL Playground程序。
## 4
cd my-app
yarn dev
注意,Playground可同时使用两个API:
-
app
:application schema,即公开的Web服务GraphQL API(在src/schema.graphql
定义) -
database
:Prisma schema,即Prisma数据库服务提供的GraphQL CRUD API(在database/datamodel.graphql
定义)。
可以简单理解为:app
为对外公开的服务API,供客户端调用;database
为数据库,供自己使用,对客户端不可见。
注意,Playground自动生成文档,显示所有支持的GraphQL API操作(如查询query、突变mutation和订阅subscription),如上图右边所示.
一旦Playground打开,可以发送查询和突变。
针对appliction schema发送查询和突变
使用 app
Playground访问application schema中定义的GraphQL API。
粘贴如下代码到左侧面板中app
Playground,点击Play-button(CMD+Enter):
mutation {
createDraft(
title: "GraphQL is awesome!",
text: "It really is."
) {
id
}
}
如果此时发送feed
Query,服务仍然返回空数组,因为feed
仅仅返回Post
中isPublished
属性true
的数据(createDraft
突变创建的数据isPublished
为false
),可以通过publish
突变先发布一个Post
。
复制调用createDraft
返回Post
的id
,替换如下代码中__POST_ID__
占位符:
mutation {
publish(id: "__POST_ID__") {
id
isPublished
}
}
执行上面突变后,有一条数据isPublished
为true
了,即可调用feed
Query,返回已经发布了的Post
:
query {
feed {
id
title
text
}
}
这与访问传统REST API有点像:在数据库之上封装了一层向外公开的API。
针对Prisma API发送查询和突变
Prisma scheme(src/generated/prisma.graphql
)定义GraphQL CRUD API,使用database
Playground访问。
现在直接针对数据库API,所以不受application scheme逻辑限制,可以使用完整的CRUD功能发布Post
。
粘贴如下代码到左侧面板中database
Playground,点击Play-button(CMD+Enter):
mutation {
createPost(
data: {
title: "What I love most about GraphQL",
text: "That it is declarative.",
isPublished: true
}
) {
id
}
}
通过mutation
创建Post
数据,其isPublished
字段为true
,所以可用feed
query返回。
在database
Playground,当然也可以针对现有的Post
直接发送update
和 delete
mutation,依照规则,必须先获取其id
值。
在database
Playground发送如下查询:
{
posts {
id
title
}
}
从返回的数组中任意取一个id
值,替换如下代码中的__POST_ID__
占位符:
mutation {
updatePost(
where: { id: "__POST_ID__" },
data: { text: "The awesome community." }
) {
id
title
text
}
}
将对应id
的text
属性修改为The awesome community.
,
最后,删除Post
,发送如下mutation(再次使用上面的id
替换__POST_ID__
占位符):
mutation {
deletePost(
where: { id: "__POST_ID__" }
) {
id
title
text
}
}
这与用SQL直接访问数据库有点像,供系统内部使用