Hug的目标是使开发Python驱动的API尽可能简单,但并不简单。因此,它极大地简化了Python API开发
Hug的设计目标:
- 使开发Python驱动的API与书面定义一样简洁
- 框架应该鼓励编写自我文档代码
- 它应该是快的。出于性能原因,开发人员永远不会觉得有必要寻找其他地方。
- 为在Hug之上编写的API编写测试应该是简单而直观的
- 在API框架中只做一次比将问题集推给API框架的用户要好
- 成为下一代Python API的基础,采用最新技术
作为这些目标的结果,Hug仅支持Python3+,并且是在此基础上构建的Falcon’s高性能HTTP库
支持拥抱发展
Get professionally supported hug with the Tidelift Subscription
拥抱的专业支持是作为Tidelift
SubscriptionTidelift为软件开发团队提供了购买和维护软件的单一来源,并由最了解该技术的专家提供专业级别保证,同时与现有工具无缝集成
安装拥抱
安装Hug非常简单,只需:
pip3 install hug --upgrade
理想情况下,在virtual environment
快速入门
只需几行代码即可使用简单端点构建示例API
# filename: happy_birthday.py """A basic (single function) API written using hug""" import hug @hug.get('/happy_birthday') def happy_birthday(name, age:hug.types.number=1):
"""Says happy birthday to a user""" return "Happy {age} Birthday {name}!".format(**locals())
要运行,请在命令行中键入:
hug -f happy_birthday.py
您可以在浏览器中访问该示例,网址为:localhost:8000/happy_birthday?name=hug&age=1
然后在以下位置查看您的API的文档localhost:8000/documentation
参数也可以在URL中编码(签出happy_birthday.py
对于整个示例)
@hug.get('/greet/{event}') def greet(event: str):
"""Greets appropriately (from http://blog.ketchum.com/how-to-write-10-common-holiday-greetings/) """ greetings = "Happy" if event == "Christmas":
greetings = "Merry" if event == "Kwanzaa":
greetings = "Joyous" if event == "wishes":
greetings = "Warm" return "{greetings} {event}!".format(**locals())
一旦您按照上述方式运行服务器,您就可以通过以下方式使用它:
curl http://localhost:8000/greet/wishes
"Warm wishes!"
拥抱着版本化
# filename: versioning_example.py """A simple example of a hug API call with versioning""" import hug @hug.get('/echo', versions=1) def echo(text):
return text @hug.get('/echo', versions=range(2, 5)) def echo(text):
return "Echo: {text}".format(**locals())
要运行示例,请执行以下操作:
hug -f versioning_example.py
然后,您可以从以下位置访问该示例localhost:8000/v1/echo?text=Hi
/localhost:8000/v2/echo?text=Hi
或从以下地址访问您的API的文档localhost:8000
注意:Hug中的版本控制自动支持版本头和直接基于URL的规范
Hug接口测试
拥抱的http
方法装饰器不会修改您的原始函数。这使得测试Hug API与测试任何其他Python函数一样简单。此外,这意味着与其他Python代码中的API函数交互与仅调用Python API函数一样简单。Hug使测试API的完整Python堆栈变得容易,方法是使用hug.test
模块:
import hug import happy_birthday hug.test.get(happy_birthday, 'happy_birthday', {'name': 'Timothy', 'age': 25}) # Returns a Response object
你可以用这个Response
测试断言的对象(签出test_happy_birthday.py
):
def tests_happy_birthday():
response = hug.test.get(happy_birthday, 'happy_birthday', {'name': 'Timothy', 'age': 25})
assert response.status == HTTP_200 assert response.data is not None
与其他基于WSGI的服务器运行Hug
拥抱暴露出一种__hug_wsgi__
自动在每个API模块上使用魔法方法。在任何标准的WSGI服务器上运行基于Hug的API都应该很简单,只需将其指向module_name
:__hug_wsgi__
例如:
uwsgi --http 0.0.0.0:8000 --wsgi-file examples/hello_world.py --callable __hug_wsgi__
要运行hello world hug示例API,请执行以下操作
Hug API的构建块
在使用Hug框架构建API时,您将使用以下概念:
方法装饰器get
,post
,update
等HTTP方法修饰器,在保持Python方法不变的同时将Python函数公开为API
@hug.get() # <- Is the hug METHOD decorator def hello_world():
return "Hello"
Hug使用您修饰的函数结构自动为API用户生成文档。Hug始终将请求、响应和API_VERSION变量传递给函数(如果它们是在函数定义中定义的参数
类型批注可选地附加到方法参数的函数,用于指定如何验证参数并将其转换为Python类型
@hug.get() def math(number_1:int, number_2:int): #The :int after both arguments is the Type Annotation return number_1 + number_2
类型批注还会馈送到hug
的自动文档生成,让API用户知道要提供什么数据
指令与请求/响应数据一起执行的函数,这些函数基于在API_Function中作为参数被请求。这些仅作为输入参数应用,当前不能作为输出格式或转换应用
@hug.get() def test_time(hug_timer):
return {'time_taken': float(hug_timer)}
指令可以通过带有hug_
前缀,或使用Python3类型批注。后者是更现代的方法,建议使用。模块中声明的指令可以通过使用它们的完全限定名作为类型注释来访问(例如:module.directive_name
)
除了明显的输入转换用例之外,还可以使用指令将数据输送到API函数中,即使它们没有出现在请求查询字符串、POST正文等中。有关如何以这种方式使用指令的示例,请参阅Examples文件夹中的身份验证示例
添加您自己的指令非常简单:
@hug.directive() def square(value=1, **kwargs):
'''Returns passed in parameter multiplied by itself''' return value * value @hug.get() @hug.local() def tester(value: square=10):
return value tester() == 100
为完整起见,下面是通过魔术名称方法访问指令的示例:
@hug.directive() def multiply(value=1, **kwargs):
'''Returns passed in parameter multiplied by itself''' return value * value @hug.get() @hug.local() def tester(hug_multiply=10):
return hug_multiply tester() == 100
输出表单事项获取API函数的输出并对其进行格式化以便传输给API用户的函数
@hug.default_output_format() def my_output_formatter(data):
return "STRING:{0}".format(data)
@hug.get(output=hug.output_format.json) def hello():
return {'hello': 'world'}
如图所示,您可以轻松地更改整个API和单个API调用的输出格式
输入表事项一个函数,它从API的用户处获取数据体,并对其进行格式化以进行处理
@hug.default_input_format("application/json") def my_input_formatter(data):
return ('Results', hug.input_format.json(data))
输入格式化程序基于content_type
请求数据,并且仅执行基本解析。更详细的解析应该由您的api_function
中间件Hug API处理的每个请求都会调用的函数
@hug.request_middleware() def process_data(request, response):
request.env['SERVER_NAME'] = 'changed' @hug.response_middleware() def process_data(request, response, resource):
response.set_header('MyHeader', 'Value')
您还可以使用以下工具轻松添加任何Falcon样式的中间件:
__hug__.http.add_middleware(MiddlewareObject())
参数映射可用于覆盖推断的参数名称,例如。对于保留关键字:
import marshmallow.fields as fields
...
@hug.get('/foo', map_params={'from': 'from_date'}) # API call uses 'from' def get_foo_by_date(from_date: fields.DateTime()):
return find_foo(from_date)
输入格式化程序基于content_type
请求数据,并且仅执行基本解析。更详细的解析应该由您的api_function
多文件拆分API
Hug使您能够以任何您认为合适的方式组织大型项目。您可以导入任何包含Hug修饰函数(请求处理、指令、类型处理程序等)的模块,并使用该模块扩展您的基础API
例如:
something.py
import hug @hug.get('/') def say_hi():
return 'hello from something'
可以导入到主API文件中:
__init__.py
import hug from . import something @hug.get('/') def say_hi():
return "Hi from root" @hug.extend_api('/something') def something_api():
return [something]
或者,对于这样的情况,每个URL路由只包含一个模块:
#alternatively hug.API(__name__).extend(something, '/something')
配置拥抱404
默认情况下,当用户尝试访问未定义的端点时,Hug返回自动生成的API规范。如果您不想退还此规范,可以关闭404文档:
从命令行应用程序执行以下操作:
hug -nd -f {file} #nd flag tells hug not to generate documentation on 404
此外,您还可以轻松创建自定义404处理程序,方法是使用hug.not_found
装饰师:
@hug.not_found() def not_found_handler():
return "Not Found"
此修饰器的工作方式与Hug HTTP方法修饰器相同,甚至可以识别版本:
@hug.not_found(versions=1) def not_found_handler():
return "" @hug.not_found(versions=2) def not_found_handler():
return "Not Found"
Asyncio支持
在使用get
和cli
协程上的方法修饰器,Hug将调度协程的执行
使用异步协同程序装饰器
@hug.get() @asyncio.coroutine def hello_world():
return "Hello"
使用Python 3.5异步关键字
@hug.get() async def hello_world():
return "Hello"
注意:Hug在顶部的Falcon上运行,它不是异步服务器。即使使用Asyncio,仍将同步处理请求
使用Docker
如果您希望在Docker中进行开发并保持系统整洁,您可以这样做,但您需要首先安装Docker Compose
一旦你这样做了,你就需要cd
进入到docker
目录并运行中指定的Web服务器(Gunicorn./docker/gunicorn/Dockerfile
之后,您可以在主机上的浏览器中预览API的输出
$ cd ./docker
# This will run Gunicorn on port 8000 of the Docker container.
$ docker-compose up gunicorn
# From the host machine, find your Dockers IP address. # For Windows & Mac:
$ docker-machine ip default
# For Linux:
$ ifconfig docker0 | grep 'inet' | cut -d: -f2 | awk '{ print $1}' | head -n1
默认情况下,IP为172.17.0.1。假设这也是您看到的IP,那么您将转到http://172.17.0.1:8000/
在您的浏览器中查看您的API
您还可以登录到可以考虑您的工作空间的Docker容器。此工作区安装了Python和Pip,因此您可以在Docker中使用这些工具。例如,如果您需要测试CLI接口,您可以使用以下代码
$ docker-compose run workspace bash
在你的码头上workspace
容器中的./docker/templates
主计算机上的目录挂载到/src
在码头集装箱里。这是在下指定的services
>app
的./docker/docker-compose.yml
bash-4.3# cd /src
bash-4.3# tree
.
├── __init__.py
└── handlers
├── birthday.py
└── hello.py
1 directory, 3 files
安全联系信息
Hug认真对待安全和质量。这就是为什么我们只依赖经过彻底测试的组件并利用静电分析工具(如Banddit和SAFE)来验证我们代码库的安全性的原因。如果您发现或遇到任何潜在的安全问题,请立即通知我们,以便我们解决
若要报告安全漏洞,请使用Tidelift security contactTidelift将协调修复和披露
为什么要拥抱?
拥抱只是希望有用的向导的意思。这代表了该项目的目标,即帮助指导开发人员创建编写良好且直观的API
谢谢,我希望你能找到这拥抱对您开发下一个Python API很有帮助!
~蒂莫西·克罗斯利