跳转到主要内容

一个尽可能简单(但不会更简单)地开发API的Python框架。

项目描述

HUG

PyPI version Build Status Windows Build Status Coverage Status License Join the chat at https://gitter.im/timothycrosley/hug


阅读最新文档 - 浏览GitHub代码库


hug旨在使开发由Python驱动的API尽可能简单,但不会更简单。因此,它极大地简化了Python API的开发。

hug的设计目标

  • 使开发由Python驱动的API尽可能简洁,就像书面定义一样。
  • 框架应鼓励自文档化的代码。
  • 它应该是快速的。开发者永远不需要因为性能原因而寻找其他地方。
  • 为hug之上的API编写测试应该是简单直观的。
  • 在API框架中一次完成的魔法比将问题集推给API框架的用户更好。
  • 成为下一代Python API的基础,拥抱最新技术。

由于这些目标,hug仅支持Python 3+,并建立在Falcon高性能HTTP库之上

HUG Hello World Example

支持hug开发

通过Tidelift订阅获得专业支持的hug

hug 提供了专业的支持,作为 Tidelift 订阅 的一部分。Tidelift 为软件开发团队提供了一个购买和维护软件的单个来源,由最了解该软件的专家提供专业级别的保障,同时与现有工具无缝集成。

安装 hug

安装 hug 简单到只需要

pip3 install hug --upgrade

理想情况下,在一个 虚拟环境 中。

入门指南

只需几行代码即可构建一个简单的端点示例 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!"

使用 hug 进行版本控制

# 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=Hilocalhost:8000/v2/echo?text=Hi 访问示例。或者通过 localhost:8000 访问您的 API 文档

注意:hug 的版本控制自动支持版本头以及基于 URL 的直接指定。

测试 hug API

hug 的 http 方法装饰器不会修改您的原始函数。这使得测试 hug API 简单到就像测试任何其他 Python 函数一样。此外,这意味着在其他 Python 代码中与您的 API 函数交互与调用纯 Python API 函数一样直接。hug 通过使用 hug.test 模块使测试您的 API 的完整 Python 栈变得简单。

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 在每个 API 模块上自动公开一个 __hug_wsgi__ 魔法方法。在任何标准 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 时,您将使用以下概念

方法装饰器 getpostupdate 等 HTTP 方法装饰器,它们将您的 Python 函数公开为 API,同时保持您的 Python 方法不变

@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_ 前缀的参数访问,或使用 Python 3 类型注解。后者是更现代的方法,也是推荐的。模块中声明的指令可以通过使用它们的完全限定名称作为类型注解来访问(例如:module.directive_name)。

除了明显的输入转换用例之外,指令还可以用于将数据管道输入到您的 API 函数中,即使它们不在请求查询字符串、POST 体中,等等。有关如何以这种方式使用指令的示例,请参阅示例文件夹中的身份验证示例。

添加自己的指令很简单

@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')

配置hug 404

默认情况下,当用户尝试访问未定义的端点时,hug会返回一个自动生成的API规范。如果您不希望返回此规范,可以关闭404文档

从命令行应用程序

hug -nd -f {file} #nd flag tells hug not to generate documentation on 404

此外,您还可以轻松地使用hug.not_found装饰器创建自定义的404处理程序

@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"

异步支持

当在协程上使用getcli方法装饰器时,hug会安排协程的执行。

使用异步协程装饰器

@hug.get()
@asyncio.coroutine
def hello_world():
    return "Hello"

使用Python 3.5的async关键字。

@hug.get()
async def hello_world():
    return "Hello"

注意:Hug运行在Falcon之上,而Falcon不是一个异步服务器。即使使用asyncio,请求仍然会以同步方式处理。

使用Docker

如果您喜欢在Docker中开发并保持系统清洁,您可以这样做,但您首先需要安装Docker Compose

完成之后,您需要进入docker目录并运行在./docker/gunicorn/Dockerfile中指定的web服务器(Gunicorn),然后您可以在主机机器上的浏览器中预览您的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

在您的Docker workspace容器上,您的宿主机的./docker/templates目录已挂载到Docker容器的/src。这已在./docker/docker-compose.ymlservices > app中指定。

bash-4.3# cd /src
bash-4.3# tree
.
├── __init__.py
└── handlers
    ├── birthday.py
    └── hello.py

1 directory, 3 files

安全联系信息

hug非常重视安全和质量。这种关注是我们只依赖经过彻底测试的组件并利用静态分析工具(如bandit和safety)来验证我们的代码库安全性的原因。如果您发现或遇到任何潜在的安全问题,请立即告诉我们,以便我们解决这些问题。

要报告安全漏洞,请使用Tidelift安全联系。Tidelift将协调修复和披露。

为什么选择hug?

HUG简单地代表“希望有用的指南”。这代表了项目的目标,即帮助开发者创建书写良好且直观的API。


谢谢,希望您觉得这个拥抱对您开发下一个Python API有所帮助!

~Timothy Crosley

项目详情


发布历史 发布通知 | RSS订阅

下载文件

下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。

源代码分发

hug-2.6.1.tar.gz (76.3 kB 查看哈希值)

上传时间 源代码

构建分发

hug-2.6.1-py2.py3-none-any.whl (75.1 kB 查看哈希值)

上传时间 Python 2 Python 3

支持者