本文概述
- 也就是说, 什么是GraphQL API?
- 什么是GraphQL查询?
- 使用GraphQL API的目的是什么?
- GraphQL是否比REST更好?
- 为什么我们使用Node.js?
- 动手GraphQL教程
- 让我们编码吧!
- 总结和最终想法
在本文中, 我们旨在提供有关如何创建安全的Node.js GraphQL API的快速指南。
可能想到的一些问题可能是:
- 使用GraphQL API的目的是什么?
- 什么是GraphQL API?
- 什么是GraphQL查询?
- GraphQL有什么好处?
- GraphQL是否比REST更好?
- 为什么我们使用Node.js?
所有这些都是有效的问题, 但是在回答问题之前, 我们应该深入了解Web开发的当前状态:
- 你今天发现的几乎每个解决方案都使用某种应用程序编程接口(API)。
- 即使仅使用Facebook或Instagram之类的社交网络, 你仍将连接到使用API的前端。
- 如果你感到好奇, 你会发现几乎所有的在线娱乐服务都使用不同类型的API, 包括Netflix, Spotify和YouTube等服务。
在几乎每种情况下, 你都可以找到不需要详细了解的API, 例如, 你不需要了解它们的构建方式, 也不需要使用以前使用的相同技术。能够将其集成到你自己的系统中。提供的API使你能够提供一种在服务之间进行通信的通用标准, 服务和客户端都可以在不依赖特定技术堆栈的情况下进行通信。
借助结构良好的API, 可以拥有可以为多种客户端和前端应用程序提供服务的可靠, 可维护和可扩展的API。
也就是说, 什么是GraphQL API?
GraphQL是一种API的查询语言, 专为在Facebook内部使用而开发, 并于2015年发布以供公众使用。它支持读取, 编写和实时更新。它也是开源的, 通常与REST和其他体系结构进行比较。概括地说, 它基于:
- GraphQL查询-这允许客户端读取和操纵应如何接收数据。
- GraphQL突变-这是如何在服务器上写入数据。这是关于如何将数据写入系统的GraphQL约定。
尽管本文旨在演示一个简单而真实的场景, 说明如何构建和使用GraphQL API, 但我们将不对GraphQL进行详细介绍。原因很简单, 因为GraphQL团队提供了全面的文档, 并在GraphQL简介中列出了一些最佳实践。
什么是GraphQL查询?
如前所述, 查询是客户端可以从API读取和操作数据的方式。你可以传递对象的类型, 然后选择要接收的字段类型。一个简单的查询如下所示:
query{
users{
firstName, lastName
}
}
在此查询中, 我们尝试从用户的架构访问所有用户, 但只接收firstName和lastName。该查询的结果如下所示:
{
"data": {
"users": [
{
"firstName": "Marcos", "lastName": "Silva"
}, {
"firstName": "Paulo", "lastName": "Silva"
}
]
}
}
客户端使用非常简单。
使用GraphQL API的目的是什么?
创建API的目的是具有将软件即服务与其他外部服务集成的能力。即使你的应用程序由单个前端使用, 你也可以将此前端视为外部服务, 为此, 当通过API提供两者之间的通信时, 你将能够在不同的项目中工作。
如果你在大型团队中工作, 则可以将其拆分成一个前端团队和一个后端团队, 从而允许他们使用相同的技术并简化他们的工作。在设计API时, 重要的是要选择最适合该项目的方案, 这将使你更接近所需的解决方案。
在本文中, 我们将重点介绍构建使用GraphQL的API的框架。
GraphQL是否比REST更好?
可能有点解决问题, 但我无能为力:要看情况。
GraphQL是一种非常适合多种方案的方法。 REST是一种架构方法, 也已在多种情况下得到证明。如今, 有成千上万的文章解释了为什么一个比另一个更好, 或者为什么只使用REST而不是GraphQL。而且, 你可以采用多种方式在内部使用GraphQL, 并且仍将API的端点维护为基于REST的体系结构。
最好的指导是了解每种方法的好处, 分析你正在创建的解决方案, 评估你的团队使用该解决方案的舒适度, 并评估你是否能够指导你的团队学习和起步。在选择方法之前要加快速度。
本文更多是实用指南, 而不是对GraphQL和REST的主观比较。如果你想阅读两者的详细比较, 建议你阅读我们的另一篇文章GraphQL与REST-GraphQL教程。
在今天的文章中, 我们将重点介绍使用Node.js创建GraphQL API。
为什么我们使用Node.js?
GraphQL有几个可以使用的不同库。就本文而言, 由于它们的广泛使用以及Node.js允许开发人员将熟悉的前端语法用于服务器端开发的事实, 我们决定将JavaScript与Node.js一起使用。
与我们的基于REST的API的方法进行比较也很有用, 类似于另一篇srcmini Engineering博客文章:在Node.js中创建安全REST API所演示的方法。本文还展示了如何将Node.js与Express一起使用来开发骨架REST API, 这将使你能够比较这两种方法之间的一些差异。 Node.js还设计为具有可扩展的网络应用程序, 全球社区以及可以在npm网站上找到的几个开源库。
这次, 我们将展示如何使用GraphQL, Node.js和Express构建骨架API!
动手GraphQL教程
如前所述, 我们将为GraphQL API建立一个基本概念, 并且你需要先了解Node.js和Express的基础知识。此处提供了针对此GraphQL示例创建的项目的源代码。
我们将处理两种类型的资源:
- 用户, 我们将为其处理基本的CRUD。
- 产品, 我们将对其进行详细介绍以展示GraphQL的更多功能。
用户将包含以下结构:
- id
- 名字
- 姓
- 电子邮件
- 密码
- PermissionLevel
产品将包含以下结构:
- id
- 名称
- 描述
- 价钱
至于编码标准, 我们将在该项目中使用TypeScript。在源文件中, 你将能够配置所有内容以使用TypeScript开始编码。
让我们编码吧!
首先, 请确保你安装了最新的Node.js版本。在发布之时, 根据Nodejs.org, 当前版本为10.15.3。
初始化项目
让我们从一个可以命名为node-graphql的新文件夹开始。在这里, 我们可以打开终端或Git CLI控制台, 并使用以下命令启动魔术:npm init。
配置我们的依赖项和TypeScript
为了加快这一过程, 在我们的Git存储库中将package.json替换为以下内容应包含所有必要的依赖项:
{
"name": "node-graphql", "version": "1.0.0", "description": "", "main": "dist/index.js", "scripts": {
"tsc": "tsc", "start": "npm run tsc && node ./build/app.js"
}, "author": "", "license": "ISC", "dependencies": {
"@types/express": "^4.16.1", "@types/express-graphql": "^0.6.2", "@types/graphql": "^14.0.7", "express": "^4.16.4", "express-graphql": "^0.7.1", "graphql": "^14.1.1", "graphql-tools": "^4.0.4"
}, "devDependencies": {
"tslint": "^5.14.0", "typescript": "^3.3.4000"
}
}
使用更新的package.json, 再次在终端上使用:npm install。它将在Node.js和Express中安装运行此GraphQL API所需的所有依赖项。
下一部分是配置我们的TypeScript模式。我们需要在根文件夹中包含以下名称的文件tsconfig.json:
{
"compilerOptions": {
"target": "ES2016", "module": "commonjs", "outDir": "./build", "strict": true, "esModuleInterop": true
}
}
此配置代码的逻辑将出现在app文件夹中。在这里我们可以创建一个app.ts文件, 并为进行基本测试在其中添加以下代码:
console.log('Hello Graphql Node API tutorial');
通过我们的配置, 我们现在可以运行npm start并等待构建, 并且能够测试一切正常。在终端控制台中, 你应该看到我们的” Hello GraphQL Node API教程”。在后台, 配置基本上将TypeScript代码编译为纯JavaScript, 然后在build文件夹中执行构建。
现在, 我们为GraphQL API配置一个基本框架。为了开始我们的项目, 我们将添加三个基本导入:
- 表现
- 表达图
- 图形工具
让我们开始将它们放在一起:
import express from 'express';
import graphqlHTTP from 'express-graphql';
import {makeExecutableSchema} from 'graphql-tools';
现在我们应该可以开始编写一些代码了。下一步是处理Express中的应用程序和基本的GraphQL配置, 例如:
import express from 'express';
import graphqlHTTP from 'express-graphql';
import {makeExecutableSchema} from 'graphql-tools';
const app: express.Application = express();
const port = 3000;
let typeDefs: any = [`
type Query {
hello: String
}
type Mutation {
hello(message: String) : String
}
`];
let helloMessage: String = 'World!';
let resolvers = {
Query: {
hello: () => helloMessage
}, Mutation: {
hello: (_: any, helloData: any) => {
helloMessage = helloData.message;
return helloMessage;
}
}
};
app.use(
'/graphql', graphqlHTTP({
schema: makeExecutableSchema({typeDefs, resolvers}), graphiql: true
})
);
app.listen(port, () => console.log(`Node Graphql API listening on port ${port}!`));
我们正在做的是:
- 为我们的Express服务器应用程序启用端口3000。
- 定义我们想用作快速示例的查询和变异。
- 定义查询和变异的工作方式。
好的, 但是typeDef和解析器又发生了什么, 以及与查询和变异的关系?
- typeDefs-关于查询和变异的期望的架构定义。
- 解析器-在这里, 我们定义查询和变异应如何工作的功能和行为, 而不是字段或所需参数的期望。
- 查询-我们要从服务器读取的”获取”。
- 突变-我们的请求将影响我们在自己服务器上拥有的任何数据。
现在, 让我们再次运行npm start来看看那里有什么。我们希望该应用程序运行时将显示以下消息:Node Graphql API正在侦听端口3000!
现在, 我们可以尝试通过以下方式在我们自己的服务器上查询和测试GraphQL API:http:// localhost:3000 / graphql
太好了, 现在我们可以编写第一个自己的查询, 定义为”你好”。
请注意, 我们在typeDefs上定义它的方式可以帮助我们构建查询。
很好, 但是我们如何改变价值呢?变异!
现在, 让我们看看通过突变更改内存值时会发生什么:
现在, 我们可以使用GraphQL Node.js API进行基本的CRUD操作。现在让我们继续进行代码。
产品展示
对于产品, 我们将使用称为产品的模块。为了简化本文, 我们将仅使用内存数据库进行演示。我们将定义模型和服务来管理产品。
我们的模型将基于以下内容:
export class Product {
private id: Number = 0;
private name: String = '';
private description: String = '';
private price: Number = 0;
constructor(productId: Number, productName: String, productDescription: String, price: Number) {
this.id = productId;
this.name = productName;
this.description = productDescription;
this.price = price;
}
}
将与GraphQL通信的服务将定义为:
export class ProductsService {
public products: any = [];
configTypeDefs() {
let typeDefs = `
type Product {
name: String, description: String, id: Int, price: Int
} `;
typeDefs += `
extend type Query {
products: [Product]
}
`;
typeDefs += `
extend type Mutation {
product(name:String, id:Int, description: String, price: Int): Product!
}`;
return typeDefs;
}
configResolvers(resolvers: any) {
resolvers.Query.products = () => {
return this.products;
};
resolvers.Mutation.product = (_: any, product: any) => {
this.products.push(product);
return product;
};
}
}
用户数
对于用户, 我们将遵循与产品模块相同的结构。我们将为用户提供模型和服务。该模型将定义为:
export class User {
private id: Number = 0;
private firstName: String = '';
private lastName: String = '';
private email: String = '';
private password: String = '';
private permissionLevel: Number = 1;
constructor(id: Number, firstName: String, lastName: String, email: String, password: String, permissionLevel: Number) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.password = password;
this.permissionLevel = permissionLevel;
}
}
同时, 我们的服务将像:
const crypto = require('crypto');
export class UsersService {
public users: any = [];
configTypeDefs() {
let typeDefs = `
type User {
firstName: String, lastName: String, id: Int, password: String, permissionLevel: Int, email: String
} `;
typeDefs += `
extend type Query {
users: [User]
}
`;
typeDefs += `
extend type Mutation {
user(firstName:String, lastName: String, password: String, permissionLevel: Int, email: String, id:Int): User!
}`;
return typeDefs;
}
configResolvers(resolvers: any) {
resolvers.Query.users = () => {
return this.users;
};
resolvers.Mutation.user = (_: any, user: any) => {
let salt = crypto.randomBytes(16).toString('base64');
let hash = crypto.createHmac('sha512', salt).update(user.password).digest("base64");
user.password = hash;
this.users.push(user);
return user;
};
}
}
提醒一下, 可以从此链接使用源代码。
现在我们可以播放和测试我们的代码了。让我们运行npm start。我们将在端口3000上运行服务器。我们现在可以在http:// localhost:3000 / graphql上访问GraphQL进行测试。
让我们尝试一种将商品添加到我们的产品列表的变体:
为了测试它是否有效, 我们现在将使用产品查询, 但只接收ID, 名称和价格:
query{
products{
id, name, price
}
}
The response will be:
{
"data": {
"products": [
{
"id": 100, "name": "My amazing product", "price": 400
}
]
}
}
就是这样;产品运行正常。现在, 我们可以根据需要播放和切换字段。你可以尝试添加描述:
query{
products{
id, name, description, price
}
}
现在, 我们可以对我们的产品进行描述。让我们现在尝试用户。
mutation{
user(id:200, firstName:"Marcos", lastName:"Silva", password:"amaz1ingP4ss", permissionLevel:9, email:"[email protected]") {
id
}
}
一个查询将类似于:
query{
users{
id, firstName, lastName, password, email
}
}
响应如下:
{
"data": {
"users": [
{
"id": 200, "firstName": "Marcos", "lastName": "Silva", "password": "kpj6Mq0tGChGbZ+BT9Nw6RMCLReZEPPyBCaUS3X23lZwCCp1Ogb94/oqJlya0xOBdgEbUwqRSuZRjZGhCzLdeQ==", "email": "[email protected]"
}
]
}
}
现在我们的GraphQL骨架已经准备好了!从这里到实用的功能齐全的API尚有许多步骤, 但现在已设置了基本核心。
总结和最终想法
即使缩短技巧, 这篇文章也相当丰富, 其中包含有关GraphQL Node.js API开发的许多基本信息。
让我们回顾一下到目前为止所涵盖的内容:
- 将Node.js与Express和GraphQL结合使用以构建GraphQL API;
- GraphQL的基本用法;
- 查询和变异的基本用法;
- 为你的项目创建模块的基本方法;
- 测试我们的GraphQL API;
为了更专注于事物的开发方面, 我们避免了几个重要的项目, 可以将其简要总结如下:
- 新项目验证;
- 使用通用错误服务正确处理错误;
- 验证用户可以在每个请求中使用通用服务的字段;
- 添加JWT拦截器以保护API;
- 使用更有效的方法处理密码哈希;
- 添加单元和集成测试;
请记住, 我们在此Git链接中具有完整的源代码。随意使用, 分叉, 打开问题, 发出拉动请求并进行操作!请注意, 本文提出的所有标准和建议并非一成不变。
这只是可用于开始设计自己的GraphQL API的众多方法之一。此外, 请确保更详细地阅读和探索GraphQL, 了解它所提供的功能以及如何使你的API更好。
评论前必须登录!
注册