restful web services with python - confoo

Post on 10-May-2015

5.324 Views

Category:

Technology

6 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Juozas “Joe” Kaziukėnas

http://juokaz.com / juozas@juokaz.com / @juokaz

• Juozas Kaziukėnas, Lithuanian

• You can call me Joe

• 3 years in Edinburgh, UK

• CEO of Web Species

• Occasional open source

developer

• Conferences speaker

• More info in http://juokaz.com

• Tweet me @juokaz

• Web service is a type of web application

• Integrate different apps together

• Mashups

• Content is in multiple formats

• JSON

• XML

• HTML?

• Used by other apps mainly

• Not necessary

• REpresentational State Transfer

• 99% HTTP, 1% conventions/ideas

• Stateless

• Resources

• Name -> URI

• http://apple.com/devices/iphone

• Hierarchy

• Operations

• Not in the URL, but via HTTP terms

• Trivial to cache

• Cache-control, Last-Modified, Expires, Etag

• XML-RPC

• Single url as a front controller

• Calling methods on a remote app

• Most of the actions are via POST

• SOAP

• No comments…

• PUT and DELETE HTTP verbs

• POST and GET only supported by browsers today

• Create: POST

• Update: PUT

• Delete: DELETE

• View: GET

• Status codes

• Not just 404 and 500

• Meaning of the response without analyzing the returned data

• And many other headers

• Web page is not a resource, it’s a representation of a resource

$ curl -H "Accept: application/html" localhost/products/iphone <html><body>Iphone 5</body></html> $ curl -H "Accept: application/xml" localhost/products/iphone <product><name>Iphone 5</name></product> $ curl -H "Accept: application/json“ localhost/products/iphone {‘name’:‘Iphone 5’} $ curl -H "Accept: text/plain" localhost/products/iphone Iphone 5

• Before we had:

http://www.example.com/videos.py?by=joe&type=funny

• Now we have:

http://www.example.com/videos/funny/joe/offset/0/10

• This is wrong

• What is new?

http://www.example.com/clients/new

• Unclear hierarchy

http://www.example.com/clients/photos/32723

• Filtering

http://www.example.com/clients/name/john/offset/10

/sort/name

• Everything is REST now

• But it’s not

• Twitter, Facebook, Google all inventing their own @$^&$s

• “Users are stupid”, ditching standards

• How to figure out the URIs?

• To fix this you need…

Hypermedia as the Engine of Application State

• “The Swamp of POX.” You’re using HTTP to make RPC calls.

HTTP is only really used as a tunnel.

• Resources. Rather than making every call to a service endpoint,

you have multiple endpoints that are used to represent

resources, and you’re talking to them. This is the very beginnings

of supporting REST.

• HTTP Verbs. This is the level that something like Rails gives you

out of the box: You interact with these Resources using HTTP

verbs, rather than always using POST.

• Hypermedia Controls. HATEOAS. You’re 100% REST compliant.

From Richardson Maturity Model

• A requirement for REST

• One url, everything else is discoverable

• What to

• Do next?

• Do with the resource?

• Reduces code errors

• Invalid URLS

• Invalid state transfers

• Documentation is not needed

• Evolution

<appointment>

<slot id="1234" doctor="mjones" start="1400" end="1450“/>

<patient id="jsmith“/>

<link rel="cancel" uri="/slots/1234/appointment"/>

<link rel="addTest" uri="/slots/1234/appointment/tests"/>

<link rel="updateContactInfo" uri="/patients/jsmith/contactInfo"/>

</appointment>

• Media type

• Versioning

$ curl -H "Accept: application/vnd.demo.v1+json“ localhost/products/iphone

{‘name’:‘Iphone 5’} $ curl -H "Accept: application/vnd.demo.v2+json" localhost/products/iphone

{‘product_name’:‘Iphone 5’}

• What are the URIs?

• What's the format?

• What methods are supported at each URI?

• What status codes could be returned?

By Joe Gregorio

• Fast, relatively

• Robust to develop

• New code live in seconds

• Huge selection of web frameworks

• Interfaces with databases, servers etc.

• APIs do not need much else

• As long as it’s WSGI it’s OK

• Simple code

• Different feature sets

• Talking here about

• Django

• Bottle, similar to Flask

• Web.py

• Tornado (asynchronous)

• Render content in the request format

xml_poll_resource = Collection(

queryset = Poll.objects.all(),

permitted_methods = ('GET', 'POST', 'PUT', 'DELETE'),

expose_fields = ('id', 'question', 'pub_date'),

responder = XMLResponder(paginate_by = 10)

)

xml_choice_resource = Collection(

queryset = Choice.objects.all(),

permitted_methods = ('GET',),

expose_fields = ('id', 'poll_id', 'choice'),

responder = XMLResponder(paginate_by = 5)

)

urlpatterns = patterns('',

url(r'^polls/(.*?)/?$', xml_poll_resource),

url(r'^choices/(.*?)/?$', xml_choice_resource)

)

import bottle from bottle import route, run

@route('/', method='GET')

def homepage():

return 'Hello world!'

@route('/events/:id', method='GET')

def get_event(id):

return dict(name = 'Event ' + str(id))

run()

class PlaceHandler(tornado.web.RequestHandler):

def get(self, id):

self.write('GETting something')

def post(self):

self.write('POSTing something')

application = tornado.web.Application([

(r"/place", PlaceHandler),

(r"/place/([0-9]+)", PlaceHandler)

])

if __name__ == "__main__":

http_server = tornado.httpserver.HTTPServer(application)

tornado.ioloop.IOLoop.instance().start()

• Detect which format to use from Accept header

• Content negotiation

• Mimeparse - http://code.google.com/p/mimeparse/

• Use it, works great

> mimeparse:best_match(["application/xbel+xml", "text/xml"], "text/*;q=0.5,*/*; q=0.1"). > "text/xml"

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 urls = ('/(.*)', 'greet') app = web.application(urls, globals())

class greet: @mimerender(default = 'html', html = render_html, xml = render_xml, json = render_json) def GET(self, name): if not name: name = 'world' return {'message': 'Hello, ' + name + '!'} if __name__ == "__main__": app.run()

• Rendering XML takes a lot of code

• doc = xml.dom.minidom.Document() # Something happens return doc.toxml()

• JSON is as easy as

• json_dumps(data, sort_keys=True)

• Maybe allow human readable output

• json_dumps(data, sort_keys=True, indent=4)

• JSON is great for Ajax consumption

• XML is better than JSON for anything else

• Django for existing apps

• Different sub-frameworks for REST

• Bottle or similar

• Small

• Effective

• Build your own logic

• Asynchronous Tornado

• If API needs to be asynchronous

• Cache headers

• Authentication

• Different types

• No real REST framework

• Start at http://api.festivalslab.com

• 7 summer festivals

• Built in 100% Python

• Fast

• Very stable

• Some bad decisions

• Works really well

• More info in the blog

• Whole API – 100 LoC of Python code

• Mainly interacting with the ElasticSearch server

• Scheduled data imports – main task

• Nginx as a reverse proxy

• Supervisor to manage the processes

• REST is awesome

• Support different formats

• Follow HATEOAS

• Try to create as little as possible custom behavior

• Go with light Python code

Keep in touch: http://juokaz.com / juozas@juokaz.com / @juokaz

We can help you build them, talk to us!

top related