使用 Azure Functions 和 SQLite 构建微型 Web API






4.88/5 (6投票s)
如何使用 Azure Functions 和 SQLite 构建一个精简、低资源、可扩展的 API 服务。
引言
在本文中,我们将使用 Azure Function 和 SQLite 作为后端来编写一个基础 API。
我们将创建一个 Web API,它根据您发送的邮政编码返回一个城市。这将是一个简单、小型服务,可用于表单和其他查找。
我们将使用一个预先填充的 SQLite 数据库,并构建一个 Azure Function 来与之交互并提供 Web API 接口。
SQLite 是一个小型、独立的 SQL 数据库引擎,非常适合处理小数据。它是一个设计精良、性能高且可靠的数据库,您可能每天都在使用它。由于其体积小和资源占用少,它在手机和其他便携式设备上无处不在。
您可以通过 Pluralsight 的 Android: SQLite Fundamentals 课程了解更多关于 SQLite 的信息。虽然它侧重于 Android 开发,但它很好地涵盖了 SQLite 的基础知识。
您可以在这里了解更多关于 Azure Functions 的信息。
数据库
此项目的数据库可在此处 下载。这将是我们正在处理的数据库。
它是一个包含城市及其对应邮政编码的数据库。数据库的架构如下所示:
该数据库包含美国大多数城市的信息,以邮政编码作为主键。
我们将本地连接到此数据库,并将其打包随我们的 Azure Function 一起部署。
设置我们的 Azure Function
我们将需要在 Azure 中设置一个 Azure Function 来部署我们的应用程序。以下是操作步骤。
登录到您的 Azure Portal。搜索“Function App”。
点击“创建”。您会看到一个类似下图的对话框。
选择您的资源组,然后指定项目的名称。这将是您服务的域名。
选择“代码”进行发布,并选择 **.NET** 作为运行时堆栈。
选择版本 **3.1**。
以及您希望 Azure Function 所在的区域。
然后点击 **Review + create**(审阅 + 创建)。
创建我们的 Azure Function
打开 Visual Studio 2019(或更高版本)并创建一个新项目。
搜索 **Azure Functions** 模板,然后点击“下一步”。
为您的项目命名,随意命名。我将其命名为“ZiptoCity”。
确保选择:
- .NET Core 3 (LTS)
- Http trigger(HTTP 触发器)
- Anonymous authorization level(匿名授权级别)
然后创建项目。
创建模型
创建一个名为 *Models* 的新文件夹,并创建一个名为 *City.cs* 的新类。这将是我们作为结果返回的模型。
向您的类添加以下属性,使其看起来像这样:
using Newtonsoft.Json;
namespace ZiptoCity.Models
{
public class City
{
[JsonProperty("zipcode")]
public int ZipCode { get; set; }
[JsonProperty("cityname")]
public string CityName { get; set; }
[JsonProperty("county")]
public string County { get; set; }
[JsonProperty("state")]
public string State { get; set; }
[JsonProperty("timezone")]
public string TimeZone { get; set; }
}
}
这些是我们希望在 API 中公开的数据库片段。我们使用 JsonProperty 来装饰属性,因为之后它将以 JSON 格式显示。
创建我们的主函数
接下来,我们将创建访问此数据的函数。
右键单击项目文件夹,选择“添加”->“新建 Azure Function”。
选择 **Http trigger**(HTTP 触发器)并选择 **anonymous**(匿名)身份验证。
并添加新文件。
您会看到一个新函数。我们来做一些更改。
在自动生成的方法的签名中,您会看到这个:
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, ILogger log)
将其更改为如下所示:
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "city/{id}")] HttpRequest req, ILogger log, int id)
我们将从可用的 API 方法中删除 **POST**,因为我们不使用它。
然后我们将添加一个新路由,该路由接受 {id} 作为参数。这里我们将添加邮政编码。
最后,我们将使用 **int id** 来捕获该 ID。
让我们更改日志消息。
log.LogInformation("Requested city for " + id);
现在我们将连接到数据库。
注意:对于较大的应用程序,最好抽象数据库连接信息。但由于我们只执行一个操作,所以我决定将所有连接处理放在方法内部。
连接到数据库
现在我们将连接到 SQLite 数据库。确保将此数据库复制到名为 Data 的文件夹中,并将数据库设置为 **Copy always**(始终复制)。
然后我们需要安装 SQLite Nuget 包。
Install-Package System.Data.SQLite -Version 1.0.115
在我们的 Run 方法中,添加以下内容:
var sqlite_conn = new SQLiteConnection(@"Data Source=Data\zipcode.db; Version = 3; New = True; Compress = True; ");
try
{
sqlite_conn.Open();
}
catch (Exception ex)
{
log.LogInformation("Error: " + ex.Message);
}
此代码连接到位于 Data 文件夹的 SQLite 数据库。如果连接出现问题,将会被记录下来。
查询数据
接下来,我们将添加一些行来创建一个 SQLiteDataReader 和一个 SQLiteCommand 来填充数据。
SQLiteDataReader sqlite_datareader;
SQLiteCommand sqlite_cmd;
sqlite_cmd = sqlite_conn.CreateCommand();
现在,我们将创建一个查询来从数据库中获取我们想要返回的数据。我们将把 id
作为参数传递给查询。
sqlite_cmd.CommandText = "SELECT zip, primaryCity, state, county, timezone FROM zip_code_database WHERE zip = '" + id + "'";
然后我们可以执行读取器。
sqlite_datareader = sqlite_cmd.ExecuteReader();
检索和分配数据
现在我们想使用读取器来填充我们要返回的 City
对象。我们将创建一个要填充的对象。
var resultCity = new City { };
我们还将创建一个布尔值,可以在发送最终结果之前进行检查。
var goodResult = false;
然后,我们将创建一个循环,如果我们的查询结果成功,该循环将运行。
if (sqlite_datareader.HasRows)
{
goodResult = true;
while (sqlite_datareader.Read())
{
resultCity.ZipCode = sqlite_datareader.GetInt32(0);
resultCity.CityName = sqlite_datareader.GetString(1);
resultCity.State = sqlite_datareader.GetString(2);
resultCity.County = sqlite_datareader.GetString(3);
resultCity.TimeZone = sqlite_datareader.GetString(4);
}
}
在此循环中,我们将 goodResult 设置为 true。然后循环遍历 datareader,并将值从 datareader 分配给我们的 resultCity
对象。
现在我们可以关闭连接。
sqlite_conn.Close();
发送结果
现在我们已准备好根据查询发送结果。如果我们未从数据库收到城市,goodResult
将保持 false。
如果查询成功,我们将发送 City 对象的 JSON 表示形式。
if (goodResult)
{
return new OkObjectResult(resultCity);
}
else
{
return new NotFoundResult();
}
完成!现在我们的 Azure Function 已准备好进行测试。
完整的函数
完整的函数应如下所示:
[FunctionName("ZipCodeLookup")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "city/{id}")] HttpRequest req,
ILogger log, int id)
{
log.LogInformation("Requested city for " + id);
var sqlite_conn = new SQLiteConnection(@"Data Source=Data\zipcode.db; Version = 3; New = True; Compress = True; ");
try
{
sqlite_conn.Open();
}
catch (Exception ex)
{
log.LogInformation("Error: " + ex.Message);
}
SQLiteDataReader sqlite_datareader;
SQLiteCommand sqlite_cmd;
sqlite_cmd = sqlite_conn.CreateCommand();
sqlite_cmd.CommandText = "SELECT zip, primaryCity, state, county, timezone FROM zip_code_database WHERE zip = '" + id + "'";
sqlite_datareader = sqlite_cmd.ExecuteReader();
var resultCity = new City { };
var goodResult = false;
if (sqlite_datareader.HasRows)
{
goodResult = true;
while (sqlite_datareader.Read())
{
resultCity.ZipCode = sqlite_datareader.GetInt32(0);
resultCity.CityName = sqlite_datareader.GetString(1);
resultCity.State = sqlite_datareader.GetString(2);
resultCity.County = sqlite_datareader.GetString(3);
resultCity.TimeZone = sqlite_datareader.GetString(4);
}
}
sqlite_conn.Close();
if (goodResult)
{
return new OkObjectResult(resultCity);
}
else
{
return new NotFoundResult();
}
}
}
让我们来测试一下!
测试 Azure Function
我们现在可以通过按 5 来测试我们的 Azure Function。您会看到一个控制台窗口,显示如何连接它。
您可以本地连接到您的函数,但使用 URL + 示例邮政编码。
既然我们知道它没问题,就可以部署它了。
部署 Azure Function
转到 Build -> Publish(生成 -> 发布),然后选择 Azure。
选择 Azure Function App (Windows)。
选择您的订阅、资源组,然后选择函数应用。确保 Run from package file (recommended)(从包文件中运行(推荐))未被选中。
按 Finish(完成),然后 Publish(发布)以部署到 Azure。
在 Azure 中运行您的应用程序
应用程序已发布到 Azure 后,您需要进行一些快速更改,它就可以准备就绪了。
在 Azure 门户中,选择您的函数。然后向下滚动到 **CORS**。
在允许的来源中,添加通配符(**\***)字符。
注意:对于生产环境,您将需要输入允许访问此应用程序的域名。
保存配置,您就可以开始了。
您现在可以使用浏览器或 Postman 向您的新 API 发送查询。
就是这样!
结论
在此项目中,我们构建了一个小型 Web API,它接受邮政编码并返回城市信息。这是“微型 API”的一个很好的例子,您可以在组织中使用它。小型、精简的应用程序始终很受欢迎,通过使用 Azure Functions 和 SQLite,您可以创建性能良好且可扩展的微型应用程序。
微服务架构日益普及。构建小型、松耦合的服务和 API 可以帮助您的组织构建高性能且易于维护的应用程序。Azure Functions 通过提供小型按使用量付费的空间来构建应用程序,使这一切成为可能。
您可以在这里了解更多关于 Azure Functions 的信息。