Monday, November 18, 2013

使用Pyramid和Cornice构建多格式支持的RESTful API

在Pyramid中利用Cornice可以很方便的基于HTTP Accept header不同构建不同格式的响应内容。

1. 安装Cornice
    pip install Cornice

2. 安装Cornice之后,会在系统中增加一个名为cornice的template,在学习时可以使用它创建一个简单的项目框架。
    pcreate -t cornice myapp
    创建好的项目相比pyramid的项目简单,只有一个__init__.py,一个views.py

3. 在views.py中定义了一个简单的api例子
hello = Service(name='hello', path='/', description="Simplest app")


@hello.get()
def get_info(request):
    """Returns Hello in JSON."""
    return {'Hello': 'World’} 

在该例子中,定义了一个url为/的api,访问这个api链接,将返回一个application/json响应。

4. 在__init__.py中使用include包含了cornice包
from pyramid.config import Configurator


def main(global_config, **settings):
    config = Configurator(settings=settings)
    config.include("cornice")
    config.scan("myapp.views")
    return config.make_wsgi_app() 

5. 运行该程序,查看结果
python setup.py develop 
pserve --reload myapp.ini 
我们通过curl访问该url:curl -D - http://0.0.0.0:6543,得到如下响应内容
HTTP/1.1 200 OK
Content-Length: 18
Content-Type: application/json; charset=UTF-8
Date: Mon, 18 Nov 2013 06:46:49 GMT
Server: waitress

{"Hello": "World"} 
从Content-Type中可以看到,取得的内容为application/json格式

6. 构建一个文本格式返回结果
为了取得文本结果,我们需要将view的结果进行格式化,因此在__init__.py中加入如下renderer
class TextRenderer(object):

    def __init__(self, info):
        pass

    def __call__(self, value, system):
        request = system.get('request')
        if request is not None:
            response = request.response
            response.content_type = 'text/plain'
        name = value['Hello']
        return u"Hello, {}!".format(name) 

注:如果不需要进行类似上面的数据转化,可以直接使用string renderer。

然后,在main函数中加入config.add_renderer('text', TextRenderer)

7. 修改views.py 以接收不同的HTTP Header
@hello.get(accept='text/plain', renderer='text')
@hello.get(accept='application/json', renderer='json')
def get_info(request):
    """Returns Hello in JSON."""
    return {'Hello': 'World'} 

上面的两个@分别表示当get中的HTTP Header不同时的处理(使用不同的renderer对数据进行不同渲染)

8. 使用不同的HTTP Header查看结果
$ curl -D - -H 'Accept: text/plain' http://0.0.0.0:6543
HTTP/1.1 200 OK
Content-Length: 13
Content-Type: text/plain; charset=UTF-8
Date: Fri, 15 Nov 2013 11:22:41 GMT
Server: waitress

Hello, World!


$ curl -D - -H 'Accept: application/json' http://0.0.0.0:6543
HTTP/1.1 200 OK
Content-Length: 18
Content-Type: application/json; charset=UTF-8
Date: Fri, 15 Nov 2013 11:22:48 GMT
Server: waitress

{"Hello": "World"} 


9. cornice与参数校验的整合
cornice可以很好的跟colander校验库结合使用。下面我们加入一个输入参数尝试一下。

9.1 安装colander
pip install colander

9.2 在views.py中增加一个校验规则
import colander

class NameSchema(colander.MappingSchema):
    name = colander.SchemaNode(colander.String(),
                               validator=colander.Length(2)) 

该校验规则表示系统接收一个名为name的参数,且该参数为字符串类型,最小长度为2(Length参数为min,max,这里省略了max)

9.3 在views.py中增加参数处理方法
@hello.post(accept='text/plain', renderer='text', schema=NameSchema)
@hello.post(accept='application/json', renderer='json', schema=NameSchema)
def post_info(request):
    """Returns Hello in JSON."""
    name = request.validated['name']
    return {'Hello': name} 

上面的方法为/这个url增加了post处理。

9.4 取得运行结果
curl -H 'Accept: application/json' http://0.0.0.0:6543 -d '{"name": "Alex"}' 
结果:{"status": "error", "errors": [{"location": "body", "name": "name", "description": "name is missing"}]}
这是因为cornice默认接收的Content-Type是application/x-www-form-urlencoded,因此不能解析-d '{"name": "Alex"}' 这种参数

$ curl -H 'Accept: application/json' http://0.0.0.0:6543 -d 'name=Alex'
{"Hello": "Alex"} 

$ curl -H 'Accept: application/json' -H 'Content-Type: application/json' http://0.0.0.0:6543 -d '{"name": "Alex"}'
{"Hello": "Alex"} 
该例子中指定了Content-Type,因此系统能识别-d '{"name": "Alex"}'

$ curl -H 'Accept: application/json' -H 'Content-Type: application/json' http://0.0.0.0:6543 -d '{"name": "A"}'
{"status": "error", "errors": [{"location": "body", "name": "name", "description": "Shorter than minimum length 2"}]} 


本文是http://makina-corpus.com/blog/metier/multi-format-restful-api-with-cornice的一个摘要翻译,需要查看原文请自行前往。 

No comments:

Post a Comment