2. Lo necesario
Intentar crear un API Rest con Python
Que cumpla con todos los estandares REST
Que sea facil de utilizar y probar
Que sea customizable
Que tenga buena documentacion y soporte
Que utilize y se integre con Mongo facilmente
10. Python REST API Framework
Powered by Flask, MongoDB, Redis and good
intentions
Eve allows to effortlessly build and deploy
highly customizable, fully featured RESTful
Web Services
19. HATEOAS
API entry points adhere to the HATEOAS
Hypermedia as the Engine of Application State
(HATEOAS)
20. HATEOAS
The principle is that a client interacts with a
network application entirely through
hypermedia provided dynamically by
application servers
21. Database Interlude
# Let's just use the local mongod instance. Edit as needed.
# Please note that MONGO_HOST and MONGO_PORT could very well be left
# out as they already default to a bare bones local 'mongod' instance.
MONGO_HOST = 'localhost'
MONGO_PORT = 27017
MONGO_USERNAME = 'user'
MONGO_PASSWORD = 'user'
MONGO_DBNAME = 'apitest'
22. A More Complex Application
So far our API has been read-only. Let’s enable the full spectrum of CRUD operations:
# Enable reads (GET), inserts (POST) and DELETE for resources/collections
# (if you omit this line, the API will default to ['GET'] and provide
# read-only access to the endpoint).
RESOURCE_METHODS = ['GET', 'POST', 'DELETE']
# Enable reads (GET), edits (PATCH), replacements (PUT) and deletes of
# individual items (defaults to read-only item access).
ITEM_METHODS = ['GET', 'PATCH', 'PUT', 'DELETE']
23. Schema
schema = {
# Schema definition, based on Cerberus grammar. Check the Cerberus project
# (https://github.com/nicolaiarocci/cerberus) for details.
'firstname': {
'type': 'string',
'minlength': 1,
'maxlength': 10,
},
'lastname': {
'type': 'string',
'minlength': 1,
'maxlength': 15,
'required': True,
# talk about hard constraints! For the purpose of the demo
# 'lastname' is an API entry-point, so we need it to be unique.
'unique': True,
},
24. # 'role' is a list, and can only contain values from 'allowed'.
'role': {
'type': 'list',
'allowed': ["author", "contributor", "copy"],
},
# An embedded 'strongly-typed' dictionary.
'location': {
'type': 'dict',
'schema': {
'address': {'type': 'string'},
'city': {'type': 'string'}
},
},
'born': {
'type': 'datetime',
},
}
25. Better Customization
Now let’s say that we want to further customize the people endpoint
people = {
# 'title' tag used in item links. Defaults to the resource title minus
# the final, plural 's' (works fine in most cases but not for 'people')
'item_title': 'person',
# by default the standard item entry point is defined as
# '/people/<ObjectId>'. We leave it untouched, and we also enable an
# additional read-only entry point. This way consumers can also perform
# GET requests at '/people/<lastname>'.
'additional_lookup': {
'url': 'regex("[w]+")',
'field': 'lastname'
},
26. # We choose to override global cache-control directives for this resource.
'cache_control': 'max-age=10,must-revalidate',
'cache_expires': 10,
# most global settings can be overridden at resource level
'resource_methods': ['GET', 'POST'],
'schema': schema
}
28. Full range of CRUD
Action HTTP Verb Context
Create POST Collection
Read GET, HEAD Collection/Document
Update PATCH Document
Replace PUT Document
Delete DELETECollection/Document
29. More info
Field Description
_created item creation date.
_updated item last updated on.
_etag ETag, to be used for concurrency control and
conditional requests.
_id unique item key, also needed to access the
individual item endpoint.
30. Sub Resources
Endpoints support sub-resources so you could have something like:/people/<contact_id>/invoices
invoices = {
'url': 'people/<regex("[a-f0-9]{24}"):contact_id>/invoices'
Then this GET to the endpoint, which would roughly translate to give me all the invoices by <contact_id>:
31. Customizable, item endpoints
Resources can or cannot expose individual item endpoints. API consumers could get access to /people,
/people/<ObjectId> and /people/Doe
$ curl -i http://eve-demo.herokuapp.com/people/521d6840c437dc0002d1203c
HTTP/1.1 200 OK
Etag: 28995829ee85d69c4c18d597a0f68ae606a266cc
Last-Modified: Wed, 21 Nov 2012 16:04:56 GMT
$ curl -i http://eve-demo.herokuapp.com/people/Doe
HTTP/1.1 200 OK
Etag: 28995829ee85d69c4c18d597a0f68ae606a266cc
Last-Modified: Wed, 21 Nov 2012 16:04:56 GMT
33. Filtering and Sorting
$ curl -i http://eve-demo.herokuapp.com/people?where={"lastname": "Doe"}
HTTP/1.1 200 OK
34. Sorting
$ curl -i http://eve-demo.herokuapp.com/people?sort=[("lastname", -1)]
HTTP/1.1 200 OK
35. Pagination
Resource pagination is enabled by default in order to improve performance and preserve bandwidth
$ curl -i http://eve-demo.herokuapp.com/people?max_results=20&page=2
36. Mix then all
$ curl -i http://eve-demo.herokuapp.com/people?where={"lastname": "Doe"}&sort=[("firstname", 1)]&page=5
37. JSON and XML Rendering
Eve responses are automatically rendered as JSON (the default) or XML, depending on the request Accept
header. Inbound documents (for inserts and edits) are in JSON format.
45. Authentication
Customizable Basic Authentication (RFC-2617), Token-based authentication and HMAC-based Authentication
are supported.
You can lockdown the whole API, or just some endpoints
. You can also restrict CRUD commands, like allowing open read-only access while restricting edits, inserts
and deletes to authorized users. Role-based access control is supported as well
46. Read-only by default
If all you need is a read-only API, then you can have it up and running in a matter of minutes.
50. Event Hooks
>>> def pre_get_callback(resource, request, lookup):
... print 'A GET request on the "%s" endpoint has just been received!' % resource
>>> def pre_contacts_get_callback(request, lookup):
... print 'A GET request on the contacts endpoint has just been received!'
>>> app = Eve()
>>> app.on_pre_GET += pre_get_callback
>>> app.on_pre_GET_contacts += pre_contacts_get_callback
>>> app.run()
51. Post-Request Event Hooks
>>> def post_get_callback(resource, request, payload):
... print 'A GET on the "%s" endpoint was just performed!' % resource
>>> def post_contacts_get_callback(request, payload):
... print 'A get on "contacts" was just performed!'
>>> app = Eve()
>>> app.on_post_GET += post_get_callback
>>> app.on_post_GET_contacts += post_contacts_get_callback
>>> app.run()
55. File Storage
Media files (images, pdf, etc.) can be uploaded as media document fields. Upload is done via POST, PUT and PATCH
as usual, but using the multipart/data-form content-type.
accounts = {
'name': {'type': 'string'},
'pic': {'type': 'media'},
...
}