前言
在进行 Web 开发时,我们经常需要与数据库进行交互。传统的方式是使用关系型数据库(如 MySQL、PostgreSQL、Oracle 等),配合 ORM 框架进行操作。但是,ORM 操作往往只需要使用其中的一小部分功能,而数据库本身又具有复杂的查询和处理能力。这时,GraphQL 可以作为一种更灵活、更高效的查询语言,调用数据库的完整功能。
本文将介绍如何使用 GraphQL 和 PostgreSQL 进行集成。你将学到:
- GraphQL 基础语法及其优势;
- PostgreSQL 结构和基础操作;
- 使用 GraphQL 和 PostgreSQL 进行集成开发的完整流程。
GraphQL 入门
什么是 GraphQL
GraphQL 是一种查询语言,由 Facebook 开发。它可以更加高效、灵活地请求数据,完全取代传统的 RESTful API 设计。
- 高效:可以精确控制所需数据,避免无谓的网络传输。
- 灵活:查询语句可以嵌套,支持多个服务端返回不同的数据,更适合前端工程化开发。
- 可视化:有多种可视化工具,方便查看响应数据结构。
GraphQL 基础语法
GraphQL 查询文本由字段和类型组成,如下:
query { fieldName(arg1: Value1, arg2: Value2) { subField1 subField2 } }
query
:定义查询操作,后面跟着查询语句。fieldName
:查询请求中的字段名。arg1: Value1
:可选参数。subField1
:查询请求中的子字段名,可以嵌套。
例如,下面的查询请求,请求名称为 hello
,查询了 users
表中所有行的 name
和 email
字段:
query hello { users { name email } }
使用 GraphQL 进行数据库查询
使用 GraphQL 查询语句,可以代替传统 ORM 方式,直接向数据库请求数据。在这个过程中,需要使用一些类库/框架来执行 GraphQL 语句:
graphql
:GraphQL 类库,可以通过 JavaScript 对象或者字符串,解析、执行 GraphQL 语言。同时 GraphQL 语言也可以编译成可执行程序。express-graphql
:基于 Express 和 graphql 的 GraphQL 服务端。
下面是使用上述类库完成的一个简单查询用户信息,使用的数据库是 PostgreSQL:
-- -------------------- ---- ------- ----- - -------- ----------- - - ------------------- ----- - --- - - ---------------- -- -- ---------- ------ ----- ------- - ------------------- ----- ----------- - --------------------------- -- -- -- ----------------- ----- ------ - ------------- ---- ---- - --- --- ----- ------- ------ ------- - ---- ----- - ------ ------- -------- ----- ---- - --- -- -- -- ------------------ ----- ---- - - ------ ----- -- -- - -- -- ---------- ------ ---- --- ----- ---- - ----- -------------- - ---- -------- ------ ----- -- ----- ----- -- -- -- -- - ----- ---- - ----- -------------- - ---- ----- ----- ------- ---- -- ------------ --- -- - ------ ----- - ------ -------- -- -- -- -- ------- ------ ------- ---- --------------- ----- --- - ---------- ------------------- ------------- ------- ---------- ----- --------- ----- -- -- ------- ----------- ---- -- -- ---- ---------------- -- -- -------------------- -- ---------------------------------
以上代码中,我们首先定义了 GraphQL 的 Schema,包括了 User 类型和一个查询操作。然后实现 Resolver,即查询操作的具体实现。最后,使用 Express 框架的 express-graphql 中间件,将 Schema 和 Resolver 集成起来,启动 GraphQL 服务。
通过 GraphiQL 直接查询获取数据库中的数据,查询请求为:
query { users { id name email } }
GraphQL 对比 RESTful API
在传统的 RESTful API 访问方式中,前端通常需要向服务端发起多个请求获取数据。但是,这种方式存在很多缺点,例如不够灵活、冗余的数据传输等。如果把上面查询 users
表的例子,用 RESTful API 的形式访问,可能需要写成这样:
fetch('http://localhost:3000/users') .then(response => response.json()) .then(users => { // 对 users 执行其他操作 });
这样返回的是完整的用户列表信息,有时会存在冗余数据,不够灵活。但是,使用 GraphQL 则可以精确控制所需数据。例如,如果只需要查询 users
表中指定列的数据,可以这样写:
query { users { name email } }
这样,返回的数据就只包括 name
和 email
字段,不再有冗余数据。
PostgreSQL 入门
什么是 PostgreSQL
PostgreSQL 是一个关系数据库管理系统,具有丰富的功能和强大的性能。它支持许多高级的数据类型和功能,例如阵列、JSON 和 XML 支持。在开源界中,它是最成熟的关系型数据库之一。
PostgreSQL 数据库操作
使用 PostgreSQL,涉及到的操作有以下几种:
- 增加记录:
INSERT INTO
; - 修改记录:
UPDATE
; - 删除记录:
DELETE FROM
; - 查询记录:
SELECT
。
下面是 PostgreSQL 连接代码的实现,我们使用的是 pg-promise
模块:
-- -------------------- ---- ------- ----- --------- - ------------------------ ----- -- - ----------- ----- ------------ ----- ----- --------- ------------- ----- ----------- --------- --------- --- -------------- - - --- ---------- --- --- --
连接成功后,可以使用 db
对象执行 PostgreSQL 相应的操作。例如,下面是增加、修改、删除和查询的实现:
-- -------------------- ---- ------- -- ---- ----- --------------- ---- ----- ------ ------ ------ ---- ----- --------- ---------------------- -- ---- ----- --------------- ----- --- ----- - -- ----- -- - ---- ------------------- ---- -- ---- ----- --------------- ---- ----- ----- ---- - ---- ------- -- ---- ----- ---- - ----- -------------- - ---- --------
GraphQL 和 PostgreSQL 的集成使用
介绍了 GraphQL 和 PostgreSQL 的基础知识后,下面将介绍如何进行集成使用。
1. 安装相关模块
首先,需要安装以下模块:
npm install graphql express express-graphql pg-promise
其中:
graphql
:GraphQL 类库。express-graphql
:可以使用此类库快速搭建 GraphQL 服务端。express
:常用的 Node.js Web 框架。pg-promise
:用于连接 PostgreSQL。
2. PostgreSQL 数据库初始化
在开始之前,需要先在 PostgreSQL 数据库中创建相应的表。这里以 users
表为例:
CREATE TABLE users ( id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL );
3. 编写 GraphQL Schema 和 Resolver
GraphQL 的 Schema 和 Resolver 是这种异步查询语言的核心。下面,假设我们已经连接上 PostgreSQL 数据库并且初始化表。我们编写了一个简单的 Schema,查询用户表的所有字段:
-- -------------------- ---- ------- ----- - ----------- - - ------------------- ----- ------ - ------------- ---- ---- - --- --- ----- ------- ------ ------- - ---- ----- - ------ ------ - --- ----- ---- - - ------ ----- -- -- ----- -------------- - ---- -------- --
以上代码中,我们定义了一个 User 类型用来描述用户,用户包含 id,name 和 email 三个属性。同时,我们定义了一个 Query 类型,包含了 users 属性,其返回值是一个 User 类型的数组。
我们还需要一个 Resolver,用于提供如何获取数据的逻辑。在这里,我们使用 pg-promise 作为数据库连接池,使用 db.any 函数执行 postgresql 中的所有语句。因为我们所需要的数据是一个用户列表,所以可以直接使用 SELECT * FROM users
获取所有用户。返回的用户列表数据将包含了数据库中表的全部字段。
端口号:4000
完整代码为:
-- -------------------- ---- ------- ----- - -------- ----------- - - ------------------- ----- - --- - - ---------------- -- -- ---------- ------ ----- ------- - ------------------- ----- ----------- - --------------------------- ----- ------ - ------------- ---- ---- - --- --- ----- ------- ------ ------- - ---- ----- - ------ ------ - --- ----- -- - ----- ----- ------------ ----- ----- --------- ------------- ----- ----------- --------- --------- --- ----- ---- - - ------ ----- -- -- ----- -------------- - ---- -------- -- ----- --- - ---------- ------------------- ------------- ------- ---------- ----- --------- ----- -- -- ------- ----------- ---- ---------------- -- -- -------------------- -- ---------------------------------
4. 验证 GraphQL 服务端
在使用工具比如 GraphiQL 或者 Hermes 来调试 API 时,可以直接通过浏览器发送请求,在输入框中输入查询语句,例如下面的语句将从 GraphQL 服务端查询所有用户的信息:
query { users { id, name, email } }
如果一切正常,服务端将返回所有用户的信息,并将其打印在终端或 GraphiQL 的查看器中:
-- -------------------- ---- ------- - ------- - -------- - - ----- ---- ------- -------- -------- ------------------- -- - ----- ---- ------- ------ -------- ----------------- - - - -
5. 在 GraphQL 中集成 CRUD 操作
在上面的例子中,我们只是查询了 users 表的所有数据,并且只查询了 name 和 email 这两个字段。但在现实开发情况中,我们可能需要查询数据的一部分,还可能需要增加、删除、修改记录等操作。因为 GraphQL 的优势在于其高效灵活的查询语言,因此,我们肯定需要知道如何使用 GraphQL 实现 CRUD 操作。
查询
查询用户信息,会根据传入的 id 判断查询哪个指定的用户:
type Query { user(id: ID!): User }
实现 Resolver 的部分代码为
-- -------------------- ---- ------- ----- ---- - - ----- ----- -- -- -- -- - ----- ---- - ----- -------------- - ---- ----- ----- ------- ---- -- ------------ --- -- - ------ ----- - ------ -------- -- --
通过传入的 id 查询数据库中的相应记录,返回一条 JSON 数据
API 调用方式为:
query { user(id: "1") { id name email } }
添加用户
在 GraphQL 中,我们需要为它编写一个 mutation。因为它操作了数据库,所以它必须是一个 mutation,而不是 query。在这个例子中,我们将创建一个新的用户记录。
type Mutation { createUser(name: String!, email: String!): User }
注意:在mutation类型字段中,每一个字段需要添加封装类型Input。如下:
-- -------------------- ---- ------- ---- -------- - ----------------- ----------------- ---- - ----- --------------- - ----- ------- ------ ------- -
实现 Resolver 的代码为
const root = { createUser: async ({ input }) => { const newRow = await db.one('INSERT INTO users (name, email) VALUES (${name}, ${email}) RETURNING *', input); return newRow; }, };
通过传入数据,将 name 和 email 保存到 Postgresql 中,返回新创建的用户
API 调用方式为:
-- -------------------- ---- ------- -------- - ----------------- - ----- ------ ------ ----------------- -- - ---- ----- - -
更新用户
type Mutation { updateUser(id: ID! input: UpdateUserInput!): User } input UpdateUserInput { name: String email: String }
实现 Resolver 的代码为
-- -------------------- ---- ------- ----- ---- - - ----------- ----- -- --- ----- -- -- - ----- --------- - - --- -------- -- ----- ---- - --------------------------------------- ------- -- ----- -- ---- -- ----- --- -------------- ------- -- --- - ----- - --- - ----- ----- ----- - ------- ----- --- ----------------- ----- -------- --------- --- ----- ------- - ----- ------------- ----------- ------ -------- -- --
传入需要更新的 id 及其余部分的内容,将 name 和 email 保存到 Postgresql 中,返回更新后的结果
API 调用方式为:
-- -------------------- ---- ------- -------- - -------------- ---- ------ - ------ --------------------- -- - -- ---- ----- - -
删除用户
type Mutation { deleteUser(id: ID!): User }
实现 Resolver 的代码为
const root = { deleteUser: async ({ id }) => { const deleted = await db.one('DELETE FROM users WHERE id=$1 RETURNING *', id); return deleted; }, };
通过传入的 id 删除指定用户并返回删除后的结果
API 调用方式为:
mutation { deleteUser(id: "1") { id name email } }
结论
GraphQL 和 PostgreSQL 的结合使用,提供了一个非常灵活的后端查询接口,可以根据前端的需求,动态获取数据,同时有效减少了数据请求的冗余和延迟。本文详细介绍了使用 GraphQL 和 PostgreSQL 进行集成开发的完整流程,包括创建 Schema 和 Resolver,连接数据库,执行增删改查操作。读者可根据本文的指导,使用 GraphQL 和 PostgreSQL 实现自己的 Web 项目。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67761a186d66e0f9aa09ff2c