restful web services with python - confoo

37
Juozas “Joe” Kaziukėnas http://juokaz.com / [email protected] / @juokaz

Upload: juozas-kaziukenas

Post on 10-May-2015

5.324 views

Category:

Technology


6 download

TRANSCRIPT

Page 1: RESTful Web Services with Python - Confoo

Juozas “Joe” Kaziukėnas

http://juokaz.com / [email protected] / @juokaz

Page 2: RESTful Web Services with Python - Confoo

• 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 - Confoo
Page 4: RESTful Web Services with Python - Confoo

• 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 - Confoo

• 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 - Confoo

• 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 - Confoo

• 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 - Confoo

$ 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

Page 9: RESTful Web Services with Python - Confoo
Page 10: RESTful Web Services with Python - Confoo

• 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 - Confoo

• 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 - Confoo

• 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 - Confoo

Hypermedia as the Engine of Application State

Page 14: RESTful Web Services with Python - Confoo

• “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 - Confoo

• 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 - Confoo

<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 - Confoo

• 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 - Confoo
Page 19: RESTful Web Services with Python - Confoo

• 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 - Confoo

• 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 - Confoo

• 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 - Confoo

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)

)

Page 23: RESTful Web Services with Python - Confoo

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()

Page 24: RESTful Web Services with Python - Confoo

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()

Page 25: RESTful Web Services with Python - Confoo

• 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 - Confoo

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()

Page 27: RESTful Web Services with Python - Confoo

• 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

Page 28: RESTful Web Services with Python - Confoo

• 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 - Confoo

• Cache headers

• Authentication

• Different types

• No real REST framework

Page 30: RESTful Web Services with Python - Confoo
Page 31: RESTful Web Services with Python - Confoo

• 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

Page 32: RESTful Web Services with Python - Confoo
Page 33: RESTful Web Services with Python - Confoo

• 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 - Confoo
Page 35: RESTful Web Services with Python - Confoo

• REST is awesome

• Support different formats

• Follow HATEOAS

• Try to create as little as possible custom behavior

• Go with light Python code