前言
随着现代web应用程序的不断发展,单一页面应用程序(SPA)的流行与日俱增。随之而来的是越来越多的客户端的请求和服务端的响应。GraphQL使得(在客户端和服务器之间)请求和响应的交互更加顺畅。GraphQL是一种API查询语言和运行时,旨在优化API的性能和灵活性。
Fastify是Node.js的快速和低开销的Web框架。Fastify和它的生态系统中的插件可以帮助我们快速构建GraphQL服务端。
在本文中,我们将了解如何在Fastify中使用GraphQL,从GraphQL API的基础知识开始,了解现代,设置开发环境,最后是MySQL数据库使用GraphQL的示例。
GraphQL基础知识
GraphQL使用新的查询语言来定义API的查询能力,并使用类型系统来定义数据的结构。查询语言称为GraphQL查询语言(GQL)。查询语言可用于以下多种类型的操作:
- 获取某些数据
- 更改现有数据
- 订阅发生的事件
查询是由服务器解决的操作。数据本质上是一组关联对象,这些对象由字段组成。查询图是字段关系的图形表示。查询图同时决定了查询方法。每个字段可以是标量或由再次嵌套查询图形以形成复杂查询。这是在GraphQL中定义一个查询:
---- ----- - --------- --------- ----- - ---- ----- - --- --- ----- ------ ---- --- -
在这个示例中,查询字段的名称是人(human),并包含一个参数id,该参数用于指定对哪些人进行查询。将返回名称,年龄和标识符(id)作为输出。
使用GraphQL语言的极度灵活性,可以更轻松地进行改进和扩展。在GraphQL中,使用批处理技术,可以缩短取回时间并最小化网络连接。
但是,在许多情况下,浏览器不会直接执行查询,而是使用某种具体执行器(例如,Apollo Client)代表用户与服务器交互。
准备工作
在开始使用GraphQL之前,需要安装和启动环境。请查看以下内容:
- Node.js
- NPM 包管理器
- MySQL 数据库
要了解更多信息,请访问官方网站。
创建项目
首先,我们需要创建一个新的Node.js项目。在命令行中打开新的项目目录并运行:
----- --------------- -- -- --------------- -- --- ----
进入项目根目录后,我们将安装Fastify和Fastify插件,以及GraphQL和相关插件:
--- ------- ------- ---------------- ------------ -------------- -------------- ----------- --------------------- ------- ------
Fastify插件
- fastify-autoload:自动加载路由和hooks.
- fastify-cors:跨域资源共享
- fastify-helmet:安全中间件
- fastify-static:静态文件服务
- fastify-gql:把GraphQL集成到Fastify中去
- apollo-server-fastify:GraphQL服务的路由插件,精简的GraphQL HTTP服务器
GraphQL相关插件
- graphql:graphql JavaScript库
- apollo-server-fastify和fastify-gql:将GraphQL和Fastify集成
使用Fastify和GraphQL的复杂示例
接下来,我们将创建一个从MySQL数据库检索数据并使用GraphQL API公开的示例。
数据库配置
应用程序将使用MySQL作为其数据库。安装并运行MySQL,然后使用以下命令来创建数据库,并为其添加一些数据。
------ ------ ----------------- ------- --------- --- ---- ------- --------------- - --- ---------------- ------ ----- ------- - ---- ------- --- ---- --------------- ------- ------------ --- ----- ------------- ------------ --- ---- ------- --- ------------ --------- --- ---- ------- ------------------ -------------- ---------- --- ---- ------- ---- ------- --- ------ - ------------- ----------------- ------- ------------- ------ ---- ----- ------- ------------ ------------- ------ ------- --------- ------ ------- -- ------ --- ------ -- --- ------------ --- ------- --------- -------- -- -- ---------- ---- --- ------------ --- ----------- --- ------- ------- ----- -------- ------- --- -- - ------- -------- --- ---------- ------- --- ---- --- ------- ---
设置fastify
我们将创建一个名为index.js的新文件,其中将启动Fastify:
---- ------- ----- ------- - -------------------- ------- ---- -- ----------------------------------------- ------------------------------------------- ------------------------------------------- - ----- ---------- ------- ----------- -- --------------------------------------------- - ---- ----------- -- -------------------- ---------- ----- -- - -- ----- - ------------------ --------------- - --
在这个示例中,我们将Fastify与中间件、静态文件服务和自动加载路由的开箱即用支持集成。请注意,我们使用3000端口运行Fastify并暴露公共IP地址。
集成的GraphQL和MySQL
要集成GraphQL和MySQL,我们将创建一个名为schema.js的新文件,这样它就可以捆绑到我们的Fastify应用程序中。schema.js将定义我们的GraphQL数据类型和相应的解析器:
------------- ----- - --- - - --------------------------------- ----- -------- - ---- ---- ----- - ------ ------ -------- ------ ---- - ---- ---- - --- --- ------ ------ ------------ ------ ------------- --- ----------- ------ - ----- --------- - ------ ------- ------------ ------- ------------- ---- - ---- -------- - ----------------- ------------ ---- -------------- ----- ------ ------------ ---- -------------- ------ ---- - -- ----- ----- - - - --- -- ------ ------ --------- ------------ ------ ------- -- ------ --- ------ -- --- ------------ ------------- -- ----------- --- ----------------- -- - --- -- ------ ------ --------- ------------ -------- -- -- ---------- ---- --- ------------ --- ------------ ------------- -- ----------- --- ----------------- -- - --- -- ------ ------ ------- ----- ------------ -------- ------- --- -- - ------- --------- ------------- -- ----------- --- ----------------- -- - --- -- ------ --------- ------------ ------- --- ---- --- ------- ------------- -- ----------- --- ----------------- - - ----- --------- - - ------ - ------ -- -- - ------ ----- -- ----- -------- ----- -- - ----- - -- - - ----- ------ --------------- -- ------- --- ---- -- -- --------- - ----------- -------- ----- -- - ----- - ----- - - ----- ----- ---- - - --- ------------ - -- --------- ----------- --- ----------------- -- ----------------- ------ ----- -- ----------- -------- ----- -- - ----- - --- ----- - - ----- ----- --------- - ----------------- -- ---- --- ---- -- ---------- -- --- - ----- --- -------- ---- ---- -- ----- ---- --- ------- - ----- ----------- - - -------------------- -------- -- ---------------- - ------------ ------ ------------ -- ----------- -------- ----- -- - ----- - -- - - ----- ----- --------- - ----------------- -- ---- --- ---- -- ---------- -- --- - ----- --- -------- ---- ---- -- ----- ---- --- ------- - ----- - ----------- - - ----------------------- --- ------ ------------ - - - -------------- - - --------- --------- -
在这个示例中,我们定义了GraphQL查询体的各个类型。并从我们的MySQL承载主机访问数据(实际示例的查询 -
----- ----- - -- ------ - --- - ------ - ------------ - ------------- - ---------- - ---- - ------ -- ----- - ----- ------------------------ ---- ----- -------------------------------
'use strict';
const { ApolloServer } = require('apollo-server-fastify'); const { taskDefs, resolvers } = require('./schema'); const mysql = require('mysql2/promise');
module.exports = async (fastify) => {
// Initialize our database client
const db = await mysql.createConnection({
host: "localhost",
user: "root",
password: "password",
database: "fastify_graphql"
});
// Attach our connection to fastify
too
fastify.decorate('db', db);
// Install GraphQL interface const server = new ApolloServer({ typeDefs: taskDefs, resolvers, });
// Decorate Fastify with GraphQL facilities fastify.register(server.createHandler()); }
------------------------------------------------------------------------------------------------------------- ---- ----------- ----------------------------------------------------------------------------
'use strict';
module.exports = async function (fastify, opts) {
fastify.get('/api/tasks', async function (req, res) {
const query = "
SELECT
id,
title,
description,
is_completed,
created_at
FROM
tasks
";
----- - ----- - - ----- ------------------------ ----------------
})
fastify.get('/api/toggle', async function (req, res) { const { id } = req.query;
----- ----- - -- ------ - ----- - --- - ------------ - -- --- ------------ - ---- - ---- - - ---- - ---- - - ---- - ----- - -- - -- -- ----- ------------------------- ------ ------------------
}) }
----------------------
'use strict';
const graphqlSchema = require('../graphql/schema');
module.exports = async function (fastify, opts) { // GraphQL related routes fastify.register(async function (app) { app.register(require("fastify-gql"), { schema: graphqlSchema.taskDefs, resolvers: graphqlSchema.resolvers, graphiql: true }); }, { prefix: '/graphql' }) }
---------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------- ---------- --------------
'use strict';
const fastify = require('fastify')({ logger: true })
fastify.register(require('fastify-cors')) fastify.register(require('fastify-helmet')) fastify.register(require('fastify-static'), { root: __dirname, prefix: '/public/', }) fastify.register(require('fastify-autoload'), { dir: './routes', })
fastify.register(require('./graphql'), { prefix: '/v1' })
fastify.listen(3000, '0.0.0.0', (err) => { if (err) { console.error(err) process.exit(1) } })
---------------------------------------------------- ----------------------------------------------------------------------- --------------------------------
query { task(id:1) { title description is_completed created_at } }
---------
{ "data": { "task": { "title": "Learn GraphQL", "description": "Study GraphQL in depth, the future of API management", "is_completed": 1, "created_at": "Sun May 23 2021 22:05:06 GMT+0800 (China Standard Time)" } } }
-- -- ---------------------------------------------------------------------------------------------------------------- ------------------ --------------------------------------------------------------------------- - ------------------------------------------------------------------------------ -------- -----------------------------------------------------------------------------------------------------------------------------