为了在Python中快速构建API,我主要依赖Flask。最近我遇到了一个新的基于Python3的API框架,叫做“APIStar”。我对它感兴趣有几个原因。首先,该框架包括新的Python特性,例如类型提示和异步。它更进一步为开发人员提供了良好的开发体验。我们很快就会了解这些功能,但在开始之前,我想首先感谢TomChristie在DjangoRESTFramework和APIStar方面所做的所有工作。现在回到APIStar——我觉得这个框架非常有成效。我可以选择基于asyncio写异步代码,也可以选择WSGI这种传统的后端方式。它附带了一个命令行工具——apistar来帮助我们更快地完成工作。它支持可选的DjangoORM和SQLAlchemy。它有一个优秀的类型系统,允许我们定义输入和输出的约束,APIStar可以自动生成API的模式(包括文档),提供验证和序列化功能等等。虽然APIStar专注于构建API,但您也可以非常轻松地在其之上构建Web应用程序。在我们自己构建一些东西之前,所有这些可能都没有意义。入门我们将从安装APIStar开始。为这个实验创建一个虚拟环境是个好主意。如果您不知道如何创建虚拟环境,请不要担心,请继续阅读。pipinstallapistar如果您没有使用虚拟环境或您的Python3pip称为pip3,请改用pip3installapistar。一旦我们安装了这个包,我们应该能够使用apistar命令行工具。我们可以用它创建一个新项目,我们在当前目录下创建一个新项目。apistar新的。现在我们应该创建两个文件:包含主应用程序的app.py和用于测试的test.py。我们来看看app.py文件:fromapistarimportInclude,Routefromapistar.frameworks.wsgiimportWSGIAppasAppfromapistar.handlersimportdocs_urls,static_urlsdefwelcome(name=None):ifnameisNone:return{'message':'欢迎使用API之星!'}return{'message':'欢迎使用API之星,%s!'%name}routes=[Route('/','GET',welcome),Include('/docs',docs_urls),Include('/static',static_urls)]app=App(routes=routes)if__name__=='__main__':app.main()在我们深入研究代码之前,让我们运行应用程序看看它是否正常工作。我们在浏览器中输入http://127.0.0.1:8080/,我们会得到如下响应:{"message":"WelcometoAPIStar!"}如果我们输入:http://127.0.0.1:8080/?name=masnun{"message":"欢迎来到API之星,masnun!"}同样,输入http://127.0.0.1:8080/docs/,我们会看到自动生成的API文档。现在让我们看一下代码。我们有一个欢迎函数,它接受一个名为name的参数,其默认值为None。APIStar是一个智能API框架。它将尝试在url路径或查询字符串中找到名称键并将其传递给我们的函数,它还会基于它生成API文档。太好了,不是吗?然后我们创建一个Route和Include实例列表,并将该列表传递给App实例。Route对象用于定义用户定义的路由。顾名思义,Include包含给定路径下的其他url路径。路由路由很简单。在构建App实例时,我们需要传递一个列表作为routes参数,该列表应该由我们刚才看到的Route或Include对象组成。对于路由,我们传递一个url路径、http方法和可调用的请求处理程序(函数或其他)。对于Include实例,我们传递一个url路径和一个Routes实例列表。路径参数我们可以通过在花括号内添加名称来声明url路径参数。例如/user/{user_id}定义了一个url,其中user_id是一个路径参数,或者更确切地说是一个将被注入处理函数(实际上是可调用函数)的变量。这是一个简单的例子:fromapistarimportRoutefromapistar.frameworks.wsgiimportWSGIAppasAppdefuser_profile(user_id:int):return{'message':'Yourprofileidis:{}'.format(user_id)}routes=[Route('/user/{user_id}','GET',user_profile),]app=App(routes=routes)if__name__=='__main__':app.main()如果我们访问http://127.0.0.1:8080/user/23,我们会得到以下响应:{"message":"Yourprofileidis:23"}但如果我们尝试访问http://127.0.0.1:8080/user/some_string,它将失败匹配。因为我们定义了user_profile函数,并为user_id参数添加了类型提示。如果它不是整数,则路径不匹配。但是如果我们继续并删除类型提示并只使用user_profile(user_id)它将匹配这个url。这也展示了APIStar的智能以及漏洞利用和好处的类型。包含/分组路由有时将某些url分组在一起是有意义的。假设我们有一个处理用户相关功能的用户模块,最好将所有用户相关的url分组在/user路径下。例如/user/new、/user/1、/user/1/update等。我们可以轻松地在单独的模块或包中创建我们的处理程序和路由,然后将它们包含在我们自己的路由中。让我们创建一个名为user的新模块,文件名为user.py。我们将以下代码放入此文件中:fromapistarimportRoutedefuser_new():return{"message":"Createanewuser"}defuser_update(user_id:int):return{"message":"Updateuser#{}".format(user_id)}defuser_profile(user_id:int):return{"message":"UserProfilefor:{}".format(user_id)}user_routes=[Route("/new","GET",user_new),Route("/{user_id}/update","GET",user_update),Route("/{user_id}/profile","GET",user_profile),]现在我们可以从应用程序主文件中导入user_routes,并且像这样使用它:fromapistarimportIncludefromapistar.frameworks.wsgiimportWSGIAppasAppfromuserimportuser_routesroutes=[Include("/user",user_routes)]app=App(routes=routes)if__name__=='__main__':app.main()现在会将/user/new委托给user_new函数。访问查询字符串/查询参数查询参数中传递的任何参数都可以直接注入处理程序函数。例如url/call?phone=1234,处理函数可以定义一个电话参数,该参数将从查询字符串/查询参数中接收值。如果url查询字符串不包含电话值,那么它将得到None。我们也可以为参数设置一个默认值,像这样:defwelcome(name=None):ifnameisNone:return{'message':'WelcometoAPIStar!'}return{'message':'WelcometoAPI之星,%s!%name}在上面的示例中,我们为name设置了默认值None。注入对象通过向请求者添加类型提示,我们可以将不同的对象注入到视图中。注入与请求相关的对象有助于处理程序直接从内部访问它们。APIStar内置的http包中有几个内置对象。我们还可以使用它的类型系统来创建我们自己的自定义对象并将它们注入到我们的函数中。APIStar还针对指定的约束执行数据验证。让我们定义我们自己的用户类型并将其注入到我们的请求处理程序中:max_length=100),'email':typesystem.string(max_length=100),'age':typesystem.integer(maximum=100,minimum=18)}required=["name","age","email"]defnew_user(user:User):returnuserroutes=[Route('/','POST',new_user),]app=App(routes=routes)if__name__=='__main__':app.main()现在,如果我们发送这样的请求:curl-XPOST\http://127.0.0.1:8080/\-H'Cache-Control:no-cache'\-H'Content-Type:application/json'\-d'{"name":"masnun","email":"masnun@gmail.com","age":12}'猜猜发生了什么?我们收到一条错误消息,提示年龄必须为18岁或以上。类型系统允许我们进行智能数据验证。如果我们启用了docsurl,我们也会自动记录这些参数。发送响应如果你注意到了,到目前为止我们只能传递一个字典,它将被转换为JSON并作为默认值返回。但是,我们可以使用apistar中的Response类来设置状态码和其他任意响应头。这是一个简单的例子:fromapistarimportRoute,Responsefromapistar.frameworks.wsgiimportWSGIAppasAppdefhello():returnResponse(content="Hello".encode("utf-8"),status=200,headers={"X-API-Framework":"APIStar"},content_type="text/plain")routes=[Route('/','GET',hello),]app=App(routes=routes)if__name__=='__main__':app.main()应返回纯文本响应和自定义标头。请注意,内容应该是字节,而不是字符串。这就是我编码的原因。继续我刚刚介绍的APIStar的一些功能,APIStar中有很多非常酷的东西,我建议您阅读Github自述文件以了解有关这个伟大框架必须提供的不同功能的更多信息。在接下来的几天里,我还将尝试在APIStar上提供更多简短、重点突出的教程。
