【AICon】AI 基础设施、LLM运维、大模型训练与推理,一场会议,全方位涵盖! >>> 了解详情
写点什么

借助 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:336296
用户头像

发布了 693 篇内容, 共 401.6 次阅读, 收获喜欢 1502 次。

关注

评论

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

上线半天下载量破100W!美团大佬的Java性能调优实战手册,超详细

Java 程序员 后端

不错,这么好的东西不白嫖也太可惜了!阿里内部首发

Java 程序员 后端

两年JAVA程序员的面试总结,mysql索引原理

Java 程序员 后端

云服务器下centos7,nginx面试题

Java 程序员 后端

三、Spring Cloud之软负载均衡 Ribbon,mysql架构

Java 程序员 后端

不是吧阿sir,你这多线程并发也太熟了吧,震惊面试官第四年

Java 程序员 后端

不是吧,就因为他和面试官多聊了半个小时红黑树,进了腾讯

Java 程序员 后端

三面遭阿里新微服务框架暴锤,含恨吃透这份手抄本笔记,终入阿里

Java 程序员 后端

为了面试阿里巴巴、腾讯、字节跳动,linux内核架构

Java 程序员 后端

为什么不想做Java了, 现在Java面试怎么这么难,从自身找原因

Java 程序员 后端

不要再本地启动项目调试了,试SpringBoot远程调试你会发现新大陆!

Java 程序员 后端

万字长文,字节大牛百万调优经验之作:JVM调优实战笔记

Java 程序员 后端

三面阿里云斩获offer:微服务+Redis,积累总结

Java 程序员 后端

主动学习微服务架构深度解析:微服务的采用前提,微服务使用场景

Java 程序员 后端

二、docker 镜像容器常用操作(让我们用docker 溜得飞起)

Java 程序员 后端

一篇文章让你了解基于Spring的测试,java自学百度网盘

Java 程序员 后端

一篇送给临近35岁程序员的文章,mysql数据库sql语句面试题

Java 程序员 后端

一行Java代码实现两玩家交换装备【并发编程】

Java 程序员 后端

上线半天下载量破100W!阿里内部微服务进阶笔记,超详细

Java 程序员 后端

不会吧不会吧?字节“百万级,nginx视频教程吾爱破解

Java 程序员 后端

世界顶级SQL技术专家呕心沥血半年才整理出这份:SQL优化核心思想笔记,手慢无

Java 程序员 后端

为什么不想做Java了,6年经验去面试10分钟结束,现在Java面试怎么这么难

Java 程序员 后端

一篇文章带你快速理解JVM运行时数据区 、程序计数器详解 (手画详图

Java 程序员 后端

为什么一个还没毕业的大学生能够把 IO 讲的这么好?

Java 程序员 后端

为什么我不建议你用阿里巴巴Java规范,而使用 Google Guava 编程?

Java 程序员 后端

三面腾讯,已拿offer!分享复习经验和后台开发面经

Java 程序员 后端

不是吧阿sir,你这Redis太熟了吧,震惊面试官第六年

Java 程序员 后端

架构实战营模块二作业

孙志强

架构实战营

三面蚂蚁金服终获 java高岗 offer,却直言再也不想体验第二次了

Java 程序员 后端

不到30岁开上兰博基尼的程序员,为什么这么强,他告诉我只需要把多线程搞好你也行

Java 程序员 后端

三面遭阿里新微服务框架暴锤,含恨吃透这份手抄本笔记,终入阿里(1)

Java 程序员 后端

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