作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
马科斯·恩里克·达席尔瓦的头像

马科斯·恩里克·达席尔瓦

Marcos对REST架构、敏捷开发和JavaScript充满热情. 他有8年以上专注于web应用程序的经验.

工作经验

12

Share

在本文中,我们的目标是提供一个关于如何创建一个 secure Node.js GraphQL API.

你可能会想到以下问题:

  • 使用GraphQL API的目的是什么?
  • 什么是GraphQL API?
  • 什么是GraphQL查询?
  • GraphQL的好处是什么?
  • GraphQL比REST好吗?
  • 我们为什么使用Node.js?

这些都是有效的问题, 但在回答这些问题之前, 我们应该对当前的web开发状态进行简要的概述:

  • 现在您能找到的几乎所有解决方案都使用某种应用程序编程接口(API).
  • 即使你只是使用社交网络, 比如Facebook或Instagram, 您仍然连接到使用API的前端.
  • 如果你好奇的话, 你会发现几乎所有的在线娱乐服务都使用一种不同的API, 包括Netflix等服务, Spotify, and YouTube.

实际上,在每个场景中,您都会发现不需要详细了解的API,例如.g., 你不需要知道它们是如何建造的, 你不需要使用他们曾经使用的技术就可以将它集成到你自己的系统中. 所提供的API允许您提供一种以公共标准在服务之间进行通信的方法,服务和客户端都可以进行通信,而不必依赖于特定的技术堆栈.

使用结构良好的API, 有可能是固体, maintainable, 以及可扩展的API,可以为多种客户端和前端应用程序提供服务.

那又怎样? Is GraphQL API?

GraphQL是api的查询语言, 为Facebook内部使用而开发,并于2015年发布供公众使用. 它支持读、写和实时更新. 它也是开源的,通常与REST和其他架构进行比较. 简而言之,它是基于:

  • GraphQL查询 -这允许客户端读取和操作应该如何接收数据.
  • GraphQL突变 —向服务器写数据的方式. 这是关于如何将数据写入系统的GraphQL约定.

尽管本文的目的是演示一个简单的, 一个关于如何构建和使用GraphQL api的真实场景, 我们不会提供GraphQL的详细介绍. 原因很简单, GraphQL团队提供了全面的文档,并在他们的文档中列出了一些最佳实践 GraphQL简介.

什么是GraphQL查询?

如前所述,查询是客户机从API读取和操作数据的方式. 您可以传递对象的类型并选择希望接收回的字段类型. 一个简单的查询如下所示:

query{
  users{
    firstName,
    lastName
  }
}

在这个查询中,我们试图从用户的模式访问所有用户,但只接收 firstName and lastName. 这个查询的结果是这样的,例如:

{
  "data": {
    "users": [
      {
        “firstName”:“马科斯”,
        “姓”:“席尔瓦”
      },
      {
        “firstName”:“保罗”,
        “姓”:“席尔瓦”
      }
    ]
  }
}

对于客户机使用来说非常简单.

使用GraphQL API的目的是什么?

创建API的目的是使软件作为一种服务能够被其他外部服务集成. 即使您的应用程序由单个前端使用, 您可以将此前端视为外部服务, and for that, 当两者之间的通信通过API提供时,您将能够在不同的项目中工作.

如果你在一个大型团队中工作, 它可以被分割成前端和后端团队, 允许双方使用相同的技术,使他们的工作更容易. 在构建API时, 选择更适合项目的解决方案以及使您更接近所需解决方案是很重要的.

在本文中,我们将重点讨论构建使用GraphQL的API的框架.

GraphQL比REST更好吗?

这可能有点逃避,但我忍不住: That depends.

GraphQL是一种非常适合多种场景的方法. REST是一种架构方法,在几个场景中也得到了验证. Nowadays, 有很多文章解释了为什么一个比另一个更好,或者为什么你应该只使用REST而不是GraphQL. And also, 有很多方法可以在内部使用GraphQL,并且仍然将API的端点作为基于rest的体系结构来维护.

最好的指导是了解每种方法的好处, 分析你正在创建的解决方案, 评估您的团队对解决方案的适应程度, 在选择不同的方法之前,评估你是否能够引导你的团队快速学习和跟上进度.

本文更像是实用指南,而不是对GraphQL和REST进行主观比较. 如果你想阅读这两者的详细比较, 我建议你看看我们的另一篇文章, GraphQL vs. REST -一个GraphQL教程.

在今天的文章中,我们将重点讨论如何使用Node创建GraphQL API.js.

我们为什么要使用Node.js?

GraphQL有几个不同的库可供使用. 出于本文的目的,我们决定采用在Node中使用JavaScript的想法.由于它们的广泛使用和事实 Node.Js允许开发者 使用熟悉的前端语法进行服务器端开发.

将我们的方法与基于rest的API进行比较也很有用, 与Toptal Engineering Blog的另一篇文章中演示的类似: 在Node中创建安全REST API.js. 本文还展示了Node的使用.js with Express 来开发一个框架REST API,它将允许您比较这两种方法之间的一些差异. Node.Js还设计了可扩展的网络应用程序, 全球社区, 还有一些开源库,你可以在 npm website.

这一次,我们将展示如何使用GraphQL、Node构建一个框架API.js和Express!

Hands on GraphQL教程

如前所述, 我们将构建GraphQL API的框架思想, 您需要了解Node的基础知识.js和Express,然后继续. 这个GraphQL示例的项目源代码是可用的 here.

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

  • Users, 我们将为此处理一个基本的CRUD.
  • Products, 我们将详细介绍GraphQL的功能.

用户将包含以下结构:

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

产品将包含以下结构:

  • id
  • name
  • description
  • price

至于编码标准,我们将在这个项目中使用TypeScript. 在源文件中,你将能够配置一切,以开始用TypeScript编码.

Let’s Code!

首先,确保您拥有最新的Node.已安装的Js版本. 在发布时,当前版本是10.15.3, as per Nodejs.org.

初始化项目

让我们从一个可以命名的新文件夹开始 node-graphql. 在这里,我们可以打开终端或Git CLI控制台,并使用以下命令启动魔术: npm init.

配置我们的依赖和TypeScript

为了加快进程,更换你的 package.json 我们的Git存储库中应该包含所有必要的依赖项:

{
  “名称”:“node-graphql”,
  “版本”:“1.0.0",
  “描述”:“”,
  “主要”:“dist /索引.js",
  "scripts": {
    :“tsc tsc”,
    "start": "npm run TSC . exe " && node ./build/app.js"
  },
  “作者”:“”,
  “许可证”:“ISC”,
  “依赖”:{
    “@types /表达”:“^ 4.16.1",
    :“@types / express-graphql ^ 0.6.2",
    :“@types / graphql ^ 14.0.7",
    “表达”:“^ 4.16.4",
    :“express-graphql ^ 0.7.1",
    :“graphql ^ 14.1.1",
    :“graphql-tools ^ 4.0.4"
  },
  " devDependencies ": {
    :“tslint ^ 5.14.0",
    :“打印稿^ 3.3.4000"
  }
}

随着更新 package.json,只需再次点击终端并使用: npm install. 它将安装在Node中运行此GraphQL API所需的所有依赖项.js和Express.

下一部分是配置TypeScript模式. 我们需要一个文件 tsconfig.json 在我们的根文件夹中添加如下内容:

{
  " compilerOptions ": {
    “目标”:“ES2016”,
    “模块”:“commonjs”,
    "outDir": "./build",
    “严格”:没错,
    “esModuleInterop”:真的
  }
}

此配置的代码逻辑将出现在app文件夹中. 我们可以创建一个 app.ts 文件和基本测试添加以下代码:

console.log('Hello Graphql Node API教程');

通过我们的配置,我们现在可以运行了 npm start 等待构建并能够测试一切是否正常工作. 在终端控制台中,您应该看到我们的“Hello GraphQL Node API教程”.“在后面的场景, 配置基本上是将TypeScript代码编译成纯JavaScript,然后在 build folder.

现在让我们为GraphQL API配置一个基本框架. 为了启动我们的项目,我们将添加三个基本导入:

  • Express
  • Express-graphql
  • Graphql-tools

让我们开始把它们放在一起:

从“express”中输入express;
从'express-graphql'导入graphqlHTTP;
从'graphql-tools'中导入{makeExecutableSchema};

现在我们应该可以开始编写代码了. 下一步是在Express中处理我们的应用程序和基本的GraphQL配置,如:

从“express”中输入express;
从'express-graphql'导入graphqlHTTP;
从'graphql-tools'中导入{makeExecutableSchema};

Const app: express.Application = express();
Const port = 3000;


let typeDefs: any = ['
  type Query {
    你好:字符串
  }
     
  类型突变{
    hello(message: String):字符串
  }
`];

let helloMessage: String = '世界!';

让resolvers = {
    Query: {
        hello: () => helloMessage
    },
    Mutation: {
        hello: (_: any, helloData: any) => {
            helloMessage = helloData.message;
            返回helloMessage;
        }
    }
};


app.use(
    '/graphql',
    graphqlHTTP ({
        schema: makeexecutablesschema ({typeDefs, resolvers})
        graphiql:真
    })
);
app.listen(port, () => console.Node Graphql API监听端口${port}!`));

我们正在做的是:

  • 为Express服务器应用程序启用端口3000.
  • 定义我们想要使用的查询和突变作为一个快速示例.
  • 定义查询和突变将如何工作.

好的,但是typedef和解析器,以及与查询和突变的关系,发生了什么?

  • typeDefs -我们的模式的定义,我们可以期望从查询和突变.
  • Resolvers -而不是期望的字段或必需的参数, 在这里,我们定义了查询和更改如何工作的函数和行为.
  • Queries -我们想从服务器读取的“get”.
  • Mutations -我们的请求会影响我们自己服务器上的任何数据.

现在,让我们跑起来 npm start 再看看这里有什么. 我们期望应用程序将运行以下消息:Node Graphql API监听端口3000!

现在我们可以尝试在我们自己的服务器上查询和测试GraphQL API: http://localhost:3000/graphql

GraphQL教程:服务器测试

很好,现在我们可以编写我们自己的第一个查询,它被定义为“hello”.”

GraphQL教程:第一个查询

注意我们定义它的方式 typeDefs,该页面可以帮助我们构建查询.

这很好,但是我们如何改变这个值呢? Mutations!

现在,让我们看看当我们用一个突变来改变内存中的值时会发生什么:

GraphQL教程:突变的演示

现在我们可以对GraphQL节点执行基本的CRUD操作.js API. 现在让我们继续我们的代码.

Products

对于产品,我们将使用一个名为products的模块. 为了简化本文, 为了演示,我们将使用内存中的数据库. 我们将定义一个模型和一个服务来管理产品.

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

导出类Product {
  private id: Number = 0;
  private name: String = ";
  私有描述:String = ";
  private price: Number = 0;

  构造函数(productId:数量,
    productName:字符串,
    productDescription:字符串,
    价格:数量){
    this.id = productId;
    this.name = productName;
    this.description = productDescription;
    this.Price =价格;
  }

}

将与GraphQL通信的服务定义为:

导出类ProductsService {

    公共产品:any = [];

    configTypeDefs () {
        let typeDefs = '
          产品类型
            name: String,
            描述:字符串,
            id: Int,
            price: Int
          } `;
        typeDefs += ' 
          扩展类型查询{
          产品(产品):
        }
        `;

        typeDefs += '
          扩展型突变{
            product(name:String, id:Int, 描述:字符串, price: Int): product!
          }`;
        返回类型定义;
    }

    configResolvers(resolvers: any) {
        resolvers.Query.products = () => {
            return this.products;
        };
        resolvers.Mutation.product = (_: any, product: any) => {
            this.products.推动(产品);
            返回产品;
        };

    }

}

Users

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

导出类用户{
    private id: Number = 0;
    private firstName: String = ";
    private lastName: String = ";
    private 电子邮件:字符串 = ";
    私有密码:String = ";
    private permissionLevel: Number = 1;

    构造函数(id:数字,
                firstName:字符串,
                姓:字符串,
                电子邮件:字符串,
                密码:字符串,
                permissionLevel: Number) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.Email = Email;
        this.Password = Password;
        this.permissionLevel = permissionLevel;
    }

}

同时,我们的服务将是这样的:

Const crypto = require('crypto');

导出类UsersService {

    公共用户:any = [];

    configTypeDefs () {
        let typeDefs = '
          type User {
            firstName:字符串,
            姓:字符串,
            id: Int,
            密码:字符串,
            permissionLevel: Int,
            电子邮件:字符串
          } `;
        typeDefs += ' 
          扩展类型查询{
          用户(用户):
        }
        `;

        typeDefs += '
          扩展型突变{
            用户(firstName:字符串,
             姓:字符串,
             密码:字符串,
             permissionLevel: Int,
             电子邮件:字符串,
             id: Int):用户!
          }`;
        返回类型定义;
    }

    configResolvers(resolvers: any) {
        resolvers.Query.users = () => {
            return this.users;
        };
        resolvers.Mutation.user = (_: any, user: any) => {
            设salt = crypto.randomBytes (16).toString(“base64”);
            让hash = crypto.createHmac(“sha512”、盐).update(user.password).消化(“base64”);
            user.密码=哈希;
            this.users.push(user);
            return user;
        };

    }

}

提醒一下,源代码可以从这里使用 link.

现在我们可以播放和测试代码了. Let’s run npm start. 我们将让服务器在端口3000上运行. 我们现在可以访问GraphQL进行测试 http://localhost:3000/graphql.

让我们尝试一个突变,将一个项目添加到我们的欧博体育app下载:

Node.GraphQL突变演示

为了测试它是否有效,我们现在将使用产品查询,但仅接收 id, name, and price:

query{
  products{
    id,
    name,
    price
  }
}

回应将是:
{
  "data": {
    "products": [
          {
        "id": 100,
        “名字”:“我的神奇产品”,
        "price": 400
      }
    ]
  }
}

And that’s it; the product is working as expected. 现在我们可以玩了,如果我们想要切换场地. 你可以试着添加一个描述:

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

现在我们可以看一下产品说明了. 现在让我们试试用户.

mutation{
  user(id:200,
  名字:“马科斯”,
  姓:“席尔瓦”,
  密码:“amaz1ingP4ss”,
  permissionLevel: 9,
  电子邮件:“马科斯.henrique@vrps.net") {
    id
  }
}

查询将是这样的:

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

回复是这样的:

{
  "data": {
    "users": [
      {
        "id": 200,
        “firstName”:“马科斯”,
        “姓”:“席尔瓦”,
        “密码”:“kpj6Mq0tGChGbZ + BT9Nw6RMCLReZEPPyBCaUS3X23lZwCCp1Ogb94 / oqJlya0xOBdgEbUwqRSuZRjZGhCzLdeQ = = ",
        “电子邮件”:“马科斯.henrique@vrps.net"
      }
    ]
  }
}

现在我们的GraphQL骨架已经准备好了! 从这里到一个有用的, 全功能API, 但基本核心现在已经设置好了.

总结和最后的想法

连刀刃都要缩短, 这篇文章篇幅很大,包含了很多关于GraphQL Node开发的基本信息.js API.

让我们回顾一下到目前为止所涵盖的内容:

  • 节点使用情况.使用Express和GraphQL构建GraphQL API;
  • 基本的GraphQL使用;
  • 查询和突变的基本用法;
  • 为您的项目创建模块的基本方法;
  • 测试GraphQL API;

更多地关注事物的发展方面, 我们避免了几个重要的项目,可以简要总结如下:

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

请记住,我们在这个Git中有完整的源代码 link. 您可以自由地使用、分叉、打开issue、拉取请求和使用它! 请注意,本文中提出的所有标准和建议并不是一成不变的.

这只是可以用来开始设计自己的GraphQL API的众多方法之一. Also, 一定要更详细地阅读和探索GraphQL, 了解它提供了什么,以及它如何使您的api变得更好.

了解基本知识

  • GraphQL是一种语言吗?

    GraphQL被定义为客户端api和服务器端运行时执行这些查询的查询语言. That said, GraphQL并不完全是一种语言, 但它有自己的语法,可以在几种编程语言中开发, such as Node.js.

  • GraphQL的好处是什么?

    GraphQL简化了客户机的使用,以便发出请求并过滤客户机实际需要使用的内容, 避免额外的数据从服务器端传递到客户端. 它是REST的一个很好的替代方案,但也可以与REST一起使用.

  • Node到底是什么.js?

    Node.js是一个跨平台的JavaScript运行时环境,它允许我们使用JavaScript语法开发后端服务器. 当软件工程师能够使用JavaScript编写代码时,它可以提高开发速度, 后端(节点).js)和前端(如Angular或React).

  • Is Node.js fast?

    Node.在过去的几年里,Js已经被证明是非常稳定和快速的. 它适用于多任务处理,并适用于Chrome使用的V8引擎.

聘请Toptal这方面的专家.
Hire Now
马科斯·恩里克·达席尔瓦的头像
马科斯·恩里克·达席尔瓦

Located in 莱科,意大利莱科省

Member since 2017年2月25日

作者简介

Marcos对REST架构、敏捷开发和JavaScript充满热情. 他有8年以上专注于web应用程序的经验.

Toptal作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.

工作经验

12

世界级的文章,每周发一次.

订阅意味着同意我们的 隐私政策

世界级的文章,每周发一次.

订阅意味着同意我们的 隐私政策

Toptal开发者

加入总冠军® community.