restful web services with python - dynamic languages conference
TRANSCRIPT
![Page 1: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/1.jpg)
RESTful Web Services with
Python
Juozas “Joe” Kaziukėnashttp://juokaz.com / [email protected] / @juokaz
![Page 2: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/2.jpg)
Who is this guy?• 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
![Page 3: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/3.jpg)
What is a RESTful API?
![Page 4: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/4.jpg)
What is an API?• 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
![Page 5: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/5.jpg)
REST• 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
![Page 6: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/6.jpg)
Difference from other web services• XML-RPC• Single url as a front controller • Calling methods on a remote app• Most of the actions are via POST
• SOAP• No comments…
![Page 7: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/7.jpg)
Difference from web apps• 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
![Page 8: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/8.jpg)
Accept header means the format
$ curl -H "Accept: application/html" localhost/products/iphone<html><body>Iphone 5</body></html>
$ curl -H "Accept: application/xml" localhost/products/iphone<name>Iphone 5</name>
$ curl -H "Accept: application/json“ localhost/products/iphone{‘name’:‘Iphone 5’}
$ curl -H "Accept: text/plain" localhost/products/iphoneIphone 5
![Page 9: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/9.jpg)
Doing it wrong
![Page 10: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/10.jpg)
URLs• 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
![Page 11: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/11.jpg)
REST + XML-RPC• 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
![Page 12: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/12.jpg)
Wrong• 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…
![Page 13: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/13.jpg)
HATEOASHypermedia as the Engine of Application State
![Page 14: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/14.jpg)
The steps to being REST• “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
![Page 15: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/15.jpg)
HATEOAS• 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
![Page 16: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/16.jpg)
XML example
<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>
![Page 17: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/17.jpg)
Accept header means the format• 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’}
![Page 18: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/18.jpg)
Solving the problems with Python
![Page 19: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/19.jpg)
How to create a REST protocol• What are the URIs?• What's the format?• What methods are supported at each URI?• What status codes could be returned?
By Joe Gregorio
![Page 20: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/20.jpg)
Why Python?• 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
![Page 21: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/21.jpg)
Python• 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
![Page 22: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/22.jpg)
Sample API with Djangoxml_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'^xml/polls/(.*?)/?$', xml_poll_resource), url(r'^xml/choices/(.*?)/?$', xml_choice_resource) )
![Page 23: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/23.jpg)
Sample API with Bottleimport 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))
bottle.debug(True) run()
![Page 24: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/24.jpg)
Sample API with Tornadoclass 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()
![Page 25: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/25.jpg)
MIME types• 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"
![Page 26: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/26.jpg)
Mimerenderrender_xml = lambda message: '<message>%s</message>'%messagerender_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()
![Page 27: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/27.jpg)
Return formats• Rendering XML takes a lot of code• doc = xml.dom.minidom.Document()# Something happensreturn 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, if not XML brings huge advantages
![Page 28: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/28.jpg)
Which framework to choose• 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
![Page 29: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/29.jpg)
What’s missing• Cache headers• Authentication• Different types
• No real REST framework
![Page 30: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/30.jpg)
Applying it practically for Edinburgh Festivals
![Page 31: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/31.jpg)
Applying it practically for Edinburgh Festivals• Start at http://api.festivalslab.com• 7 summer festivals• Built in 100% Python• Fast• Very stable• Some bad decisions• Works awesome• More info in the blog
![Page 32: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/32.jpg)
Structure
![Page 33: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/33.jpg)
Inside• 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
![Page 34: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/34.jpg)
Conclusion
![Page 35: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/35.jpg)
Conclusion• REST is awesome• Support different formats• Follow HATEOAS• Try to create as little as possible custom
behaviour• Go with light Python code
![Page 36: RESTful Web Services with Python - Dynamic Languages conference](https://reader035.vdocuments.mx/reader035/viewer/2022062405/554f3f28b4c905cd048b530d/html5/thumbnails/36.jpg)
Keep in touch: http://juokaz.com / [email protected] / @juokaz
Thank you!
We can help you build them, talk to us!