Answers:
设计RESTful API时要注意的一点是GET和POST的合并,就好像它们是同一件事一样。使用Django的基于函数的视图和CherryPy的默认分派器很容易犯此错误,尽管这两个框架现在都提供了解决此问题的方法(分别基于类的视图和MethodDispatcher)。
HTTP谓词在REST 中非常重要,除非对此特别小心,否则最终会陷入REST反模式。
一些正确的框架是web.py,Flask和Bottle。当与mimerender库结合使用时(充分披露:我写了它),它们使您可以编写漂亮的RESTful Web服务:
import web
import json
from mimerender import mimerender
render_xml = lambda message: '<message>%s</message>'%message
render_json = lambda **args: json.dumps(args)
render_html = lambda message: '<html><body>%s</body></html>'%message
render_txt = lambda message: message
urls = (
'/(.*)', 'greet'
)
app = web.application(urls, globals())
class greet:
@mimerender(
default = 'html',
html = render_html,
xml = render_xml,
json = render_json,
txt = render_txt
)
def GET(self, name):
if not name:
name = 'world'
return {'message': 'Hello, ' + name + '!'}
if __name__ == "__main__":
app.run()
该服务的逻辑仅实现一次,并且正确的表示选择(Accept标头)+分配给正确的呈现函数(或模板)的操作是整齐,透明的。
$ curl localhost:8080/x
<html><body>Hello, x!</body></html>
$ curl -H "Accept: application/html" localhost:8080/x
<html><body>Hello, x!</body></html>
$ curl -H "Accept: application/xml" localhost:8080/x
<message>Hello, x!</message>
$ curl -H "Accept: application/json" localhost:8080/x
{'message':'Hello, x!'}
$ curl -H "Accept: text/plain" localhost:8080/x
Hello, x!
更新(2012年4月):添加了有关Django基于类的视图,CherryPy的MethodDispatcher和Flask and Bottle框架的信息。提出问题时,两者都不存在。
没人惊讶烧瓶。
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
我们正在将Django用于RESTful Web服务。
请注意,开箱即用的Django没有满足我们需求的足够细粒度的身份验证。我们使用了Django-REST接口,它帮了很多忙。[我们已经推出了自己的产品,因为我们进行了太多扩展,已经成为维护的噩梦。]
我们有两种URL:实现面向人的HTML页面的“ html” URL和实现面向Web服务的处理的“ json” URL。我们的视图功能通常看起来像这样。
def someUsefulThing( request, object_id ):
# do some processing
return { a dictionary with results }
def htmlView( request, object_id ):
d = someUsefulThing( request, object_id )
render_to_response( 'template.html', d, ... )
def jsonView( request, object_id ):
d = someUsefulThing( request, object_id )
data = serializers.serialize( 'json', d['object'], fields=EXPOSED_FIELDS )
response = HttpResponse( data, status=200, content_type='application/json' )
response['Location']= reverse( 'some.path.to.this.view', kwargs={...} )
return response
关键是有用的功能是从两个演示中排除的。JSON表示形式通常只是所请求的一个对象。HTML演示文稿通常包括各种导航辅助工具和其他有助于人们提高工作效率的上下文提示。
这些jsonView
功能都非常相似,可能有点烦人。但这是Python,因此请使其成为可调用类的一部分,或者在有帮助的情况下编写装饰器。
y = someUsefulThing(...)
是“糟糕的重复”,那么对所有函数和方法的所有引用都是“糟糕的”。我不明白如何避免多次引用一个函数。
someUsefulThing(request, object_id)
是一个数据检索表达式。现在,您在程序中的不同点有了两个相同表达式的副本。在接受的答案中,数据表达式只写入一次。someUsefulThing
用一个长字符串替换您的呼叫,例如,paginate(request, Post.objects.filter(deleted=False, owner=request.user).order_by('comment_count'))
然后看一下代码。我希望它能说明我的观点。
请参阅Python Web Frameworks Wiki。
您可能不需要完整的堆栈框架,但是其余列表仍然很长。
我真的很喜欢CherryPy。这是一个宁静的Web服务的示例:
import cherrypy
from cherrypy import expose
class Converter:
@expose
def index(self):
return "Hello World!"
@expose
def fahr_to_celc(self, degrees):
temp = (float(degrees) - 32) * 5 / 9
return "%.01f" % temp
@expose
def celc_to_fahr(self, degrees):
temp = float(degrees) * 9 / 5 + 32
return "%.01f" % temp
cherrypy.quickstart(Converter())
这强调了我对CherryPy的真正喜欢;这是一个完全可行的示例,即使对于不了解该框架的人也非常容易理解。如果运行此代码,则可以立即在Web浏览器中看到结果;例如,访问http:// localhost:8080 / celc_to_fahr?degrees = 50将显示122.0
在您的Web浏览器中。
我看不出有任何理由使用Django来公开REST api,有更轻便,更灵活的解决方案。Django将很多其他东西带到了表中,这些东西并非总是需要的。如果您只想将某些代码公开为REST服务,则可以肯定不需要。
我的个人经验是,一旦有了一个千篇一律的框架,您就会开始使用它的ORM,其插件等,只是因为它很容易,而且在任何时候您都最终没有依赖关系这很难摆脱。
选择一个Web框架是一个艰难的决定,并且我会避免为了展示REST api而选择一个完整的堆栈解决方案。
现在,如果您确实需要/想要使用Django,那么Piston是一个适用于Django应用程序的不错的REST框架。
话虽如此,CherryPy看起来也非常不错,但是看起来比REST更像RPC。
查看示例(我从未使用过),如果您只需要REST,则web.py可能是最好的和最干净的。
这是基于REST的CherryPy文档中的讨论:http : //docs.cherrypy.org/dev/progguide/REST.html
特别是提到了一个内置的CherryPy调度程序,称为MethodDispatcher,该调度程序根据其HTTP动词标识符(GET,POST等)调用方法。
似乎所有种类的python Web框架现在都可以实现RESTful接口。
对于Django,除了好吃的东西和活塞,django-rest-framework是一个很有前途的值得一提的东西。我已经顺利地迁移了我的一个项目。
Django REST框架是适用于Django的轻量级REST框架,旨在简化构建相互连接,自描述的RESTful Web API的过程。
快速示例:
from django.conf.urls.defaults import patterns, url
from djangorestframework.resources import ModelResource
from djangorestframework.views import ListOrCreateModelView, InstanceModelView
from myapp.models import MyModel
class MyResource(ModelResource):
model = MyModel
urlpatterns = patterns('',
url(r'^$', ListOrCreateModelView.as_view(resource=MyResource)),
url(r'^(?P<pk>[^/]+)/$', InstanceModelView.as_view(resource=MyResource)),
)
以官方网站为例,以上所有代码均提供api,自我解释的文档(如基于soap的webservice)甚至沙盒进行测试。非常方便。
web2py包括对轻松构建RESTful API的支持,如此处和此处所述(视频)。特别地,请看一下parse_as_rest
,它使您可以定义将请求参数映射到数据库查询的URL模式。和smart_query
,使您可以在URL中传递任意自然语言查询。
如果您使用的是Django,则可以考虑使用django-tastypie替代django-piston。与活塞相比,调整到非ORM数据源更容易,并且文档丰富。
我们正在为严格的REST服务开发框架,请访问http://prestans.googlecode.com。
目前在Alpha早期,我们正在针对mod_wsgi和Google的AppEngine进行测试。
寻找测试人员和反馈。谢谢。