写点什么

借助 Serverless 框架构建 RESTful API

  • 2019-07-03
  • 本文字数:5865 字

    阅读完需:约 19 分钟

借助Serverless框架构建RESTful API

Serverless 应用程序已经存在了许多年,但是在过去的两年里,它的受欢迎程度直线上升。在本文中,你将了解如何从头构建 RESTful API 并将其部署到 AWS(Amazon Web Services)上。

什么是 Serverless 应用程序?

尽管名为“Serverless”,但它确实需要服务器来运行代码。关键的区别在于,你不需要管理运行代码的服务器,这消除了管理服务器、负载平衡器、应用补丁和扩展服务器的负担。


Serverless 应用程序可以在大多数云(AWS、Azure、GCP 和 IBM Cloud)上运行,但在本文中,我们将重点讨论 AWS,因为它是目前应用最广泛的云计算平台,尽管你学到的知识可以迁移到其他提供商。


Serverless 应用程序主要有四个部分组成:


  • 零管理

  • 自动扩展

  • 按使用付费

  • 提升速度

Serverless 框架

人们经常犯的一个错误是混淆了 Serverless 架构和框架的概念。Serverless 框架是一个开源 CLI 工具,它使代码部署变得更加容易且更可维护。它允许你将基础设施定义为代码(数据库、队列、文件存储、API 等),而不是手动登录并通过 Web 接口创建它们。


框架与云无关,被广泛采用,有良好的学习文档,并有一个大型的社区来支持它。

Serverless 框架的核心概念

使用 Serverless 框架开发 Serverless 应用程序有四个关键组件。


函数


函数是 AWS Lambda 函数,它是你编写业务逻辑的地方,它由事件调用。


常见函数举例:


  • 将数据保存到数据库中

  • 发送电子邮件

  • 处理文件


事件


任何触发函数运行的操作都被认为是一个事件。


常见事件举例:


  • AWS API 网关 HTTP 端点请求

  • AWS S3 桶上传

  • AWS SQS(简单队列服务)操作


资源


资源是你的函数所依赖的 AWS 基础设施。


常见的资源:


  • S3(处理文件)

  • 数据库(为了存储我们的数据,AWS 支持各种数据库技术)

  • SQS(队列)


服务


服务是框架的组织单元。你可以将它看作一个项目文件,尽管你可以为一个应用程序提供多个服务。它是定义函数、触发函数的事件和函数使用资源的地方,所有这些都在一个名为 serverless.yml 的文件中。

构建 API

在本教程中,你将构建一个图书 API,该 API 将图书保存到一个 NoSQL 数据存储(DynamoDB)中,并将用于管理图书的 CRUD(创建、读取、更新和删除)。


点击这里查看整个项目。

前提

  • 你的机器上已经安装了 Node.js

  • AWS 账号

项目设置

1)首先,你需要安装全局 Serverless 框架。


npm install -g serverless
复制代码


2)创建一个新目录“book-api”,并用你最喜欢的代码编辑器打开。


3)在项目根目录下运行如下命令生成新项目的框架。


serverless create --template aws-nodejs
复制代码


4)在项目根目录下新建一个文件“package.json”,并将下面的内容粘贴到这个文件中。


{  "name": "book-app",  "version": "1.0.0",  "description": "Serverless book management API",  "dependencies": {    "@hapi/joi": "^15.0.3",    "aws-sdk": "^2.466.0",    "uuid": "^3.3.2"  }}
复制代码


5)在项目的根目录下运行如下命令安装项目依赖。


npm install
复制代码


你的项目现在应该是下面这个样子:


book-api- node_modules- serverles.yml- handler.js- .gitignore- .package.json
复制代码

基础设施设置

Serverless 框架简化了在代码中定义基础设施的过程,你可以在“serverless.yml”中配置应用程序基础设施。当你部署代码时,配置将转换为 AWS 提供的 CloudFormation 模板,它允许你在代码中创建和管理基础设施。


要构建 API,你需要以下基础设施:


  • 数据库(在本指南中,你将使用由 AWS 开发的 NoSQL 数据库 DynamoDB)。

  • 安全策略(身份和访问管理是 AWS 提供的服务,允许你创建安全策略并将其分配给服务。你需要创建一个允许函数访问数据库的策略,因为默认情况下,服务是沙箱化的,这有助于减少漏洞和防止错误,比如删除生产数据库)。

  • 函数(处理 HTTP 请求并执行操作,如将数据项插入数据库并返回适当的 HTTP 响应)。

  • 事件(当接收到 HTTP 请求时调用函数)。


打开项目根目录下的文件“serverless.yml”,并用下面的内容替换。


service: book-api
provider: name: aws runtime: nodejs10.x stage: development region: eu-west-1 environment: BOOKS_TABLE: "books" iamRoleStatements: - Effect: Allow Action: - dynamodb:DescribeTable - dynamodb:Query - dynamodb:Scan - dynamodb:GetItem - dynamodb:PutItem - dynamodb:UpdateItem - dynamodb:DeleteItem Resource: Fn::Join: - "" - - "arn:aws:dynamodb:*:*:table/" - Ref: BooksTable
functions: create: handler: books/create.handler events: - http: path: books method: post cors: true
update: handler: books/update.handler events: - http: path: books/{id} method: put cors: true
list: handler: books/list.handler events: - http: path: books method: get cors: true
get: handler: books/get.handler events: - http: path: books/{id} method: get cors: true
delete: handler: books/delete.handler events: - http: path: books/{id} method: delete cors: true
resources: Resources: BooksTable: Type: AWS::DynamoDB::Table Properties: TableName: ${self:provider.environment.BOOKS_TABLE} AttributeDefinitions: - AttributeName: id AttributeType: S KeySchema: - AttributeName: id KeyType: HASH ProvisionedThroughput: ReadCapacityUnits: 1 WriteCapacityUnits: 1
复制代码


这个文件乍一看可能有点令人生畏,但让我们花点时间来消化代码,进一步了解每个部分在做什么。


Service


你的服务的名称,最好将其命名为描述性的名称,因为它在 AWS 的日志和各种其他位置中使用。


Provider


Provider 块是指定希望部署到的云平台和特定于给定云提供者的配置的地方。


  • name ——你希望的部署 API 的云提供商(AWS、Azure 等)。

  • runtime——运行时和版本(Node、GO、Python、.NET Core 等)。

  • stage ——部署阶段(开发、过渡、生产等)。

  • region——你希望的应用程序托管地区。

  • environment——全局环境变量,可以从函数里访问或者在配置文件中自引用。

  • iamRoleStatements——为 Lambda 函数指定安全策略,授予访问其他服务的权限。


Functions


这是指定函数和调用函数的事件的地方。正如你在上面的配置中所看到的,它指定了五个供各种请求类型的特定端点的 HTTP 事件调用的函数。


让我们看看其中一个函数,并试着理解它是如何工作的。


functions:  create:    handler: books/create.handler    events:      - http:          path: books          method: post          cors: true
复制代码


我们可以设想一下,我们的代码将被做处理如下:


  • 创建一个新的 AWS Lambda 函数,其标识符为“create”。

  • Lambda 函数的代码的位置为“books-api/books/create”。当事件触发时要调用的函数称为 handler。

  • 创建一个新事件,当你接收到路径为“/books”的 HTTP POST 请求时,该事件将运行 handler (AWS 使用 API 网关处理 HTTP 事件)。


Resources


这是指定应用程序所依赖的 AWS 基础设施的地方。正如你在配置中看到的,它告诉 AWS 新建一个名为“books”的 DynamoDB 表(通过自引用环境变量)。

创建图书模式

在将数据插入数据库之前验证数据始终是一种很好的实践,为了处理这个问题,你将使用一个名为“Joi”的开源模式验证器。


1)在项目根目录下创建一个新目录“books”。


2)在 books 目录下创建一个文件“schema.js”,并将如下内容粘贴到这个文件中。


const Joi = require("@hapi/joi");
const bookSchema = Joi.object().keys({ title: Joi.string() .min(1) .required(), author: Joi.string() .min(1) .required(), pages: Joi.number().required()});
function validateModel(model) { return Joi.validate(model, bookSchema, { abortEarly: false });};
module.exports = { validateModel};
复制代码


如你所见,我们定义了图书模式及其属性,并输出了一个函数“validateModel”,你将使用它来验证 handler 函数中的请求。

创建 handler 函数

现在是绑定 handler 函数的时候了,这些函数是在“serverless.yml”文件中指定的。你可能已经注意到,当你搭建项目时,它创建了一个名为“handler.js”的文件。我们不会使用这个,因为把所有的代码放在一个文件中是不好的做法,因为它变得非常复杂,打破了单一职责原则,你可以删除这个文件。

Create

在 books 目录下新建一个文件“create.js”,并将如下内容粘贴到这个文件中。


"use strict";const AWS = require("aws-sdk");const client = new AWS.DynamoDB.DocumentClient();const uuid = require("uuid");const { validateModel } = require("./schema");
module.exports.handler = async function createBook(event, context, callback) { const timestamp = new Date().getTime(); const data = JSON.parse(event.body);
const validation = validateModel(data);
if (validation.error) { const response = { statusCode: 400, body: JSON.stringify(validation.error.details) };
return callback(null, response); }
const params = { TableName: process.env.BOOKS_TABLE, Item: { id: uuid.v1(), created_at: timestamp, updated_at: timestamp, title: data.title, author: data.author, pages: data.pages } };
await client.put(params).promise();
const response = { statusCode: 201, body: JSON.stringify(params.Item) };
return callback(null, response);};
复制代码


上面的函数负责将图书保存到数据库中并以新创建的图书作为响应。


它可以分为以下几个步骤:


  1. 输出你在“serverless.yml”文件中 functions 块里引用的函数“handler”。

  2. 当接收到对“/books”的 HTTP Post 请求(到 API 网关)时,它将触发一个事件来运行 Lambda 函数并传递请求对象(事件参数的一部分)。

  3. 反序列化请求体并将其保存在“data”变量声明中。

  4. 验证模式,如果它无效,返回一个带有验证错误的错误请求。

  5. 创建一个参数对象,表名来自“serverless.yml”文件中声明的环境变量,Item 即数据库中的数据存储。

  6. 使用 AWS SDK 利用 params 对象将数据项“put”到 DynamoDB。

  7. 返回 201 HTTP 状态码(已创建),并将新创建的图书作为响应体发送。

Update

在 books 目录下新建一个文件“update.js”,并将如下内容粘贴到这个文件中。


"use strict";const AWS = require("aws-sdk");const client = new AWS.DynamoDB.DocumentClient();const { validateModel } = require("./schema");
module.exports.handler = async function updateBook(event, context, callback) { const timestamp = new Date().getTime(); const data = JSON.parse(event.body);
const validation = validateModel(data);
if (validation.error) { const response = { statusCode: 400, body: JSON.stringify(validation.error.details) };
return callback(null, response); }
const params = { TableName: process.env.BOOKS_TABLE, Key: { id: event.pathParameters.id }, ExpressionAttributeValues: { ":updated_at": timestamp, ":title": data.title, ":author": data.author, ":pages": data.pages }, UpdateExpression: "SET updated_at = :updated_at, title = :title, author = :author, pages = :pages", ReturnValues: "ALL_NEW" };
const result = await client.update(params).promise();
const response = { statusCode: 200, body: JSON.stringify(result.Attributes) };
return callback(null, response);};
复制代码

List

在 books 目录下新建一个文件“list.js”,并将如下内容粘贴到这个文件中。


"use strict";const AWS = require("aws-sdk");const client = new AWS.DynamoDB.DocumentClient();
module.exports.handler = async function listBooks(event, context, callback) { const params = { TableName: process.env.BOOKS_TABLE };
const { Items = [] } = await client.scan(params).promise();
callback(null, { statusCode: 200, body: JSON.stringify(Items) });};
复制代码

Get

在 books 目录下新建一个文件“get.js”,并将如下内容粘贴到这个文件中。


"use strict";const AWS = require("aws-sdk");const client = new AWS.DynamoDB.DocumentClient();
module.exports.handler = async function getBook(event, context, callback) { const params = { TableName: process.env.BOOKS_TABLE, Key: { id: event.pathParameters.id } };
const { Item } = await client.get(params).promise();
const response = { statusCode: Item ? 200 : 404, body: JSON.stringify(Item ? Item : { message: "Book not found!" }) };
callback(null, response);};
复制代码

Delete

在 books 目录下新建一个文件“delete.js”,并将如下内容粘贴到这个文件中。


"use strict";const AWS = require("aws-sdk");const client = new AWS.DynamoDB.DocumentClient();
module.exports.handler = async function deleteBook(event, context, callback) { const params = { TableName: process.env.BOOKS_TABLE, Key: { id: event.pathParameters.id } };
await client.delete(params).promise();
const response = { statusCode: 200 };
return callback(null, response);};
复制代码

部署

使用 Serverless 框架部署应用程序非常简单!这就是将基础设施作为代码的好处所在。


  1. 你需要将你的 AWS 帐户连接到你机器上的 Serverless 框架 CLI(这是一个一次性的过程)。

  2. 从应用程序的根目录运行以下命令:


serverless deplo
复制代码


3.你现在应该看到类似下面的屏幕截图:



4.现在,你可以将 HTTP 请求发送到终端中显示的端点(还可以从 AWS 控制台的“API 网关”选项卡下获取 URL)。


恭喜!你已经完成 Serverless 应用程序的部署!


英文原文:https://jamielivingstone.dev/build-a-rest-api-with-the-serverless-framework-and-deploy-to-aws


2019-07-03 19:336656
用户头像

发布了 781 篇内容, 共 536.1 次阅读, 收获喜欢 1578 次。

关注

评论

发布
暂无评论
发现更多内容

AI技术实践 | 人脸核身在未成年人保护领域的实践应用

牵着蜗牛去散步

人工智能 腾讯云 腾讯 人脸识别 未成年保护

重磅 | 九科信息受邀参加2022中国互联网大会“数字政府论坛”

九科Ninetech

如何轻松做数据治理?开源技术栈告诉你答案

NebulaGraph

数据治理 图数据库 全链路数据血缘 数据血缘

论文复现丨基于ModelArts实现Text2SQL

华为云开发者联盟

人工智能 华为云 12 月 PK 榜

玩转OpenHarmony智能家居:如何实现树莓派“碰一碰”设备控制

OpenHarmony开发者

OpenHarmony

华为应用市场公布2022年度榜单 原子化服务、车载应用首次上榜

最新动态

web前端培训班怎么学习?

小谷哥

贯穿汽车用户全生命周期,火山引擎数智平台能帮车企做这些事!

字节跳动数据平台

大数据 数据产品 12 月 PK 榜

【年度评选】让我们为即将过去的 2022 划上圆满的句号

InfoQ写作社区官方

热门活动

云成本优化方案-采购云管平台!

行云管家

云计算 云资源 云成本、

融云 x OHLA:「社交+游戏」双轮驱动,逐鹿中东陌生人社交

融云 RongCloud

社交 融云

跨越速运运单分析系统入选2022中国数据智能最佳实践案例

StarRocks

数据分析 物流

美团餐饮SaaS基于StarRocks构建商家数据中台的探索

StarRocks

数据分析 零售

某车企用户数据泄露,新能源汽车信息安全问题不容忽视

行云管家

信息安全 企业 堡垒机

端到端流程打通企业经脉

元年技术洞察

数字化转型 流程 趋势研究 PaaS平台 方舟平台

选择大数据培训学习技术之前有哪些准备

小谷哥

火山引擎工具技术分享:用AI完成数据挖掘,零门槛完成SQL撰写

字节跳动数据平台

大数据 BI BI 分析工具 12 月 PK 榜

GitHub标星120K+!最新23版Java岗面试攻略,涵盖28个技术栈!

程序知音

Java java面试 java编程 后端技术 Java面试八股文

中美顶级AI首次对话 送给人类的忠告引发关注

硬科技星球

自学web前端开发能找到好工作吗?

小谷哥

大数据培训机构怎么选择

小谷哥

隐私集合求交(PSI)协议研究综述

京东科技开发者

安全 密码学 安全多方计算 隐私集合求交 不经意传输

java培训学习后找不到工作的原因有哪些

小谷哥

海量请求下的接口并发解决方案

Java全栈架构师

Java 数据库 面试 后端 架构师

技术分享| anyRTC复盘一起看球场景

anyRTC开发者

CDN RTC 实时音视频 直播连麦 AI降噪

分布式系统关键路径延迟分析实践

百度Geek说

12 月 PK 榜 延时分析 关键路径 大型分布式系统延时优化

破解加密的LastPass数据库

神锁离线版

数据安全 密码 密码管理器 Lastpass 密码安全

【干货分享】PCB 板变形原因!不看不知道

华秋PCB

生产 工艺 PCB PCB设计

MySQL进阶:Innodb的RR到底有没有解决幻读?

程序员小毕

MySQL 数据库 程序员 后端 java面试

YonBuilder开发之后端函数

YonBuilder低代码开发平台

后端 数据 开发 扩展 软件研发

InfoQ 写作社区 2022 年度优质企业号评选正式开启!

InfoQ写作社区官方

热门活动

借助Serverless框架构建RESTful API_大前端_Jamie Livingstone_InfoQ精选文章