简单的python web api框架,基于gevent、json、crud。
apiphant的Python项目详细描述
功能:
基于gevent.wsgi,为成千上万的并发用户优化。
很简单!试试看:
mkdir -p myproduct/api/v0 touch {myproduct,myproduct/api,myproduct/api/v0}/__init__.py cat <<END >myproduct/api/v0/echo.py # from myproduct.api import anything def read(request): response = request.copy() response.server = 'myproduct' return response END sudo apt-get install --yes gcc libevent-dev python-dev sudo pip install apiphant apiphant myproduct 127.0.0.1:8001 # POST http://{host}:{port}/api/{version}/{t/a/r/g/e/t}/{action} curl -X POST http://127.0.0.1:8001/api/v0/echo/read -d '{"hello": "world"}' {"hello": "world", "server": "myproduct"}
python中的自动功能测试:
apiphant myproduct 127.0.0.1:8888 cat <<END >test.py from apiphant.test import test test('echo', 'read', {"hello": "world"}, 200, {"hello": "world", "server": "myproduct"}) END python test.py POST http://127.0.0.1:8888/api/v0/echo/read {"hello": "world"} --> 200 {'hello': 'world', 'server': 'myproduct'}
可选的全堆栈部署!主管、nginx、logrotate、apt、pip等。
- Copy myproduct template.
- Replace ^{tt1}$ with your product name in all configs and scripts.
- Run root ^{tt2}$ and enjoy the show.
- This deploy framework is going:
- To get Virtualenv bootstraper.
- To be extracted to a separate opensource repo.
验证请求字段和子字段,引发错误:
from apiphant.validation import ApiError, field, Invalid def read(request): id = field(request, 'id', is_required=True, valid_type=int) # More options: default_value, valid_value, valid_length, max_length, explain. item = get_item(id) if not item: raise Invalid('id') # that is a shortcut for: raise ApiError(400, {"field": "id", "state": "invalid"}) raise Invalid('id', id) # {"field": "id", "state": "invalid", "explain": -1}
可以安排后台任务:
cat <<END >myproduct/api/background.py # Or background/__init__.py importing modules of tasks. from apiphant.background import seconds @seconds(60) def update_something(): pass END apiphant-background myproduct INFO at background.main:107 [2013-08-12 13:16:52,624] Task update_something: OK. INFO at background.main:107 [2013-08-12 13:17:53,012] Task update_something: OK. * Error tracebacks are logged and may be e.g. emailed:: def on_error(error): send_email_message(to=email_config['user'], subject='Error', text=error, **email_config) # See https://pypi.python.org/pypi/send_email_message @seconds(60) def update_something(): 1/0 apiphant-background myproduct ERROR at background.main:92 [2013-08-12 13:22:41,205] Task update_something failed: Traceback (most recent call last): File "...myproduct/api/background.py", line 18, in update_something 1/0 ZeroDivisionError: integer division or modulo by zero INFO at background.main:104 [2013-08-12 13:22:43,229] on_error: OK. # Email is sent.
versionvaluev0meansapi尚未公开,也许永远不会公开, 因此预计将在不通知的情况下进行更改。
action是CRUD之一: create,read,update,delete。
为什么CRUD 在不使用http方法的情况下实现 由REST:
推荐的- Best match for generally partial «Update» action is PATCH method, but it is not supported by our gevent.wsgi webserver and several clients.
- Much more standard ^{tt10}$ method means «Replace», that is not how «Update» should work in general case. Imagine SQL ^{tt11}$ working as «Replace».
- Some cases allow only ^{tt12}$ and ^{tt13}$, e.g. cross-origin requests in some browsers, while at least ^{tt14}$ method is required for full set of actions.
- So ^{tt13}$ is selected as «a uniform method», suitable for all actions: «The actual function performed by the POST method is determined by the server» - HTTP/1.1.
{“json”: “object”}用于请求和响应, 与任何客户轻松地说一种语言。
- No X-Custom-HTTP: Headers.
- No ?url=encoded%20query%20string.
- No need to check the type of root JSON value, it is always ^{tt16}$ with self-describing names inside, not just bare value like ^{tt17}$.
但是,url仍然包含几个请求参数,因为:
- Different targets may be routed by load balancers to different backend servers using simple URL location routing.
- ^{tt3}$, ^{tt19}$ and ^{tt5}$ are always required, so may be positional parameters, improving readability and saving resources in a natural way.
上述概念的纯洁性不应妨碍你。 如果您需要上传一个文件作为“多部分/表单数据”, 您可以使用原始wsgi环境:
sudo pip install multipart from multipart import parse_form_data from apiphant.server import raw_environ @raw_environ def create(environ): forms, files = parse_form_data(environ)
如果需要返回,例如不返回“application/json”, 您可以使用原始wsgi响应,有或没有@raw_environ:
from apiphant.server import raw_environ, raw_response @raw_environ @raw_response def create(environ, start_response): try: ... except: ... finally: start_response(status, headers) return [response]