搜索
首页web前端js教程创建安全Node.js GraphQL API的快速指南

创建安全Node.js GraphQL API的快速指南

本文的目标是提供关于如何创建安全的 Node.js GraphQL API 的快速指南。【视频教程推荐:node js教程 】

你可能会想到一些问题:

  • 使用 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团队提供了全面的文档,并在Introduction to GraphQL中列出了几个最佳实践。

什么是GraphQL查询?

如上所述,查询是客户端从API读取和操作数据的一种方式。你可以传递对象的类型,并选择要接收的字段类型。下面是一个简单的查询:

query{
  users{
    firstName,
    lastName
  }
}

我们尝试从用户库中查询所有用户,但只接收firstNamelastName。此查询的结果将类似于:

{
  "data": {
    "users": [
      {
        "firstName": "Marcos",
        "lastName": "Silva"
      },
      {
        "firstName": "Paulo",
        "lastName": "Silva"
      }
    ]
  }
}

客户端的使用非常简单。

使用GraphQL API的目的是什么?

创建API的目的是使自己的软件具有可以被其他外部服务集成的能力。即使你的程序被单个前端程序所使用,也可以将此前端视为外部服务,为此,当通过API为两者之间提供通信时,你能够在不同的项目中工作。

如果你在一个大型团队中工作,可以将其拆分为创建前端和后端团队,从而允许他们使用相同的技术,并使他们的工作更轻松。

在本文中,我们将重点介绍怎样构建使用GraphQL API的框架。

GraphQL比REST更好吗?

GraphQL是一种适合多种情况的方法。 REST是一种体系结构方法。如今,有大量的文章可以解释为什么一个比另一个好,或者为什么你应该只使用REST而不是GraphQL。另外你可以通过多种方式在内部使用GraphQL,并将API的端点维护为基于REST的架构。

你应该做的是了解每种方法的好处,分析自己正在创建的解决方案,评估你的团队使用解决方案的舒适程度,并评估你是否能够指导你的团队快速掌握这些技术。

本文更偏重于实用指南,而不是GraphQL和REST的主观比较。如果你想查看这两者的详细比较,我建议你查看我们的另一篇文章,为什么GraphQL是API的未来

在今天的文章中,我们将专注于怎样用Node.js创建GraphQL API。

为什么要使用Node.js?

GraphQL有好几个不同的支持库可供使用。出于本文的目的,我们决定使用Node.js环境下的库,因为它的应用非常广泛,并且Node.js允许开发人员使用他们熟悉的前端语法进行服务器端开发。

掌握GraphQL

我们将为自己的 GraphQL API 设计一个构思的框架,在开始之前,你需要了解Node.js和Express的基础知识。这个GraphQL示例项目的源代码可以在这里找到(https://github.com/makinhs/no...)。

我们将会处理两种类型的资源:

  • Users ,处理基本的CRUD。
  • Products, 我们对它的介绍会详细一点,以展示GraphQL更多的功能。

Users 包含以下字段:

  • id
  • firstname
  • lastname
  • email
  • password
  • permissionLevel

Products 包含以下字段:

  • id
  • name
  • description
  • price

至于编码标准,我们将在这个项目中使用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

接着是配置我们的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 tutorial”。在后台场景中,我们的配置会将 TypeScript 代码编译为纯 JavaScript,然后在build文件夹中执行构建。

现在为GraphQL API配置一个基本框架。为了开始我们的项目,将添加三个基本的导入:

  • Express
  • Express-graphql
  • Graphql-tools

把它们放在一起:

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。
  • 定义我们想要用作快速示例的查询和修改。
  • 定义查询和修改的工作方式。

好的,但是typeDefs和resolvers中发生了什么,它们与查询和修改的关系又是怎样的呢?

  • typeDefs - 我们可以从查询和修改中获得的模式的定义。
  • Resolvers - 在这里我们定义了查询和修改的功能和行为,而不是想要的字段或参数。
  • Queries - 我们想要从服务器读取的“获取方式”。
  • Mutations - 我们的请求将会影响在自己的服务器上的数据。

现在让我们再次运行npm start,看看我们能得到些什么。我们希望该程序运行后产生这种效果:Graphql API 侦听3000端口。

我们现在可以试着通过访问 http://localhost:3000/graphql 查询和测试GraphQL API:

1.png

好了,现在可以编写第一个自己的查询了,先定义为“hello”。

2.png

请注意,我们在typeDefs中定义它的方式,页面可以帮助我们构建查询。

这很好,但我们怎样才能改变值呢?当然是mutation!

现在,让我们看看当我们用mutation对值进行改变时会发生什么:

3.png

现在我们可以用GraphQL Node.js API进行基本的CRUD操作了。接下来开始使用这些代码。

Products

对于Products,我们将使用名为products的模块。为了是本文不那么啰嗦,我们将用内存数据库进行演示。先定义一个模型和服务来管理Products。

我们的模型将基于以下内容:

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;
        };

    }

}

Users

对于users,我们将遵循与products模块相同的结构。我们将为用户提供模型和服务。该模型将定义为:

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;
        };

    }

}

提醒一下,源代码可以在 https://github.com/makinhs/no... 找到。

现在运行并测试我们的代码。运行npm start,将在端口3000上运行服务器。我们现在可以通过访问http://localhost:3000/graphql来测试自己的GraphQL

尝试一个mutation,将一个项目添加到我们的product列表中:

4.png

为了测试它是否有效,我们现在使用查询,但只接收idnameprice

query{
  products{
    id,
    name,
    price
  }
}

将会返回:
{
  "data": {
    "products": [
          {
        "id": 100,
        "name": "My amazing product",
        "price": 400
      }
    ]
  }
}

很好,按照预期工作了。现在可以根据需要获取字段了。你可以试着添加一些描述:

query{
  products{
    id,
    name,
    description,
    price
  }
}

现在我们可以对product进行描述。接下来试试user吧。

mutation{
  user(id:200,
  firstName:"Marcos",
  lastName:"Silva",
  password:"amaz1ingP4ss",
  permissionLevel:9,
  email:"marcos.henrique@toptal.com") {
    id
  }
}

查询如下:

query{
  users{
    id,
    firstName,
    lastName,
    password,
    email
  }
}

返回内容如下:

{
"data": {
  "users": [
    {
     "id": 200,
     "firstName": "Marcos",
     "lastName": "Silva",
     "password": "kpj6Mq0tGChGbZ+BT9Nw6RMCLReZEPPyBCaUS3X23lZwCCp1Ogb94/
                           oqJlya0xOBdgEbUwqRSuZRjZGhCzLdeQ==",
     "email": "marcos.henrique@toptal.com"
     }
   ]
}
}

到此为止,我们的GraphQL骨架完成!虽然离实现一个有用的、功能齐全的API还需要很多步骤,但现在已经设置好了基本的核心功能。

总结和最后的想法

让我们回顾一下本文的内容:

  • 在Node.js下可以通过Express和GraphQL库来构建GraphQL API;
  • 基本的GraphQL使用;
  • 查询和修改的基本用法;
  • 为项目创建模块的基本方法;
  • 测试我们的GraphQL API;

为了集中精力关注GraphQL API本身,我们忽略了几个重要的步骤,可简要总结如下:

  • 新项目的验证;
  • 使用通用的错误服务正确处理异常;
  • 验证用户可以在每个请求中使用的字段;
  • 添加JWT拦截器以保护API;
  • 使用更有效的方法处理密码哈希;
  • 添加单元和集成测试;

请记住,我们在Git (https://github.com/makinhs/node-graphql-tutorial)上有完整的源代码。可以随意使用、fork、提问、pull 并运行它!请注意,本文中提出的所有标准和建议并不是一成不变的。

这只是设计GraphQL API的众多方法之一。此外,请务必更详细地阅读和探索GraphQL文档,以了解它提供的内容以及怎样使你的API更好。

英文地址原文:https://www.toptal.com/graphql/graphql-nodejs-api

更多编程相关知识,可访问:编程教学!!

以上是创建安全Node.js GraphQL API的快速指南的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:segmentfault。如有侵权,请联系admin@php.cn删除
node.js流带打字稿node.js流带打字稿Apr 30, 2025 am 08:22 AM

Node.js擅长于高效I/O,这在很大程度上要归功于流。 流媒体汇总处理数据,避免内存过载 - 大型文件,网络任务和实时应用程序的理想。将流与打字稿的类型安全结合起来创建POWE

Python vs. JavaScript:性能和效率注意事项Python vs. JavaScript:性能和效率注意事项Apr 30, 2025 am 12:08 AM

Python和JavaScript在性能和效率方面的差异主要体现在:1)Python作为解释型语言,运行速度较慢,但开发效率高,适合快速原型开发;2)JavaScript在浏览器中受限于单线程,但在Node.js中可利用多线程和异步I/O提升性能,两者在实际项目中各有优势。

JavaScript的起源:探索其实施语言JavaScript的起源:探索其实施语言Apr 29, 2025 am 12:51 AM

JavaScript起源于1995年,由布兰登·艾克创造,实现语言为C语言。1.C语言为JavaScript提供了高性能和系统级编程能力。2.JavaScript的内存管理和性能优化依赖于C语言。3.C语言的跨平台特性帮助JavaScript在不同操作系统上高效运行。

幕后:什么语言能力JavaScript?幕后:什么语言能力JavaScript?Apr 28, 2025 am 12:01 AM

JavaScript在浏览器和Node.js环境中运行,依赖JavaScript引擎解析和执行代码。1)解析阶段生成抽象语法树(AST);2)编译阶段将AST转换为字节码或机器码;3)执行阶段执行编译后的代码。

Python和JavaScript的未来:趋势和预测Python和JavaScript的未来:趋势和预测Apr 27, 2025 am 12:21 AM

Python和JavaScript的未来趋势包括:1.Python将巩固在科学计算和AI领域的地位,2.JavaScript将推动Web技术发展,3.跨平台开发将成为热门,4.性能优化将是重点。两者都将继续在各自领域扩展应用场景,并在性能上有更多突破。

Python vs. JavaScript:开发环境和工具Python vs. JavaScript:开发环境和工具Apr 26, 2025 am 12:09 AM

Python和JavaScript在开发环境上的选择都很重要。1)Python的开发环境包括PyCharm、JupyterNotebook和Anaconda,适合数据科学和快速原型开发。2)JavaScript的开发环境包括Node.js、VSCode和Webpack,适用于前端和后端开发。根据项目需求选择合适的工具可以提高开发效率和项目成功率。

JavaScript是用C编写的吗?检查证据JavaScript是用C编写的吗?检查证据Apr 25, 2025 am 12:15 AM

是的,JavaScript的引擎核心是用C语言编写的。1)C语言提供了高效性能和底层控制,适合JavaScript引擎的开发。2)以V8引擎为例,其核心用C 编写,结合了C的效率和面向对象特性。3)JavaScript引擎的工作原理包括解析、编译和执行,C语言在这些过程中发挥关键作用。

JavaScript的角色:使网络交互和动态JavaScript的角色:使网络交互和动态Apr 24, 2025 am 12:12 AM

JavaScript是现代网站的核心,因为它增强了网页的交互性和动态性。1)它允许在不刷新页面的情况下改变内容,2)通过DOMAPI操作网页,3)支持复杂的交互效果如动画和拖放,4)优化性能和最佳实践提高用户体验。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

Dreamweaver Mac版

Dreamweaver Mac版

视觉化网页开发工具

SublimeText3 英文版

SublimeText3 英文版

推荐:为Win版本,支持代码提示!

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境