Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Definitive Introduction to Falcon

The Definitive Introduction to Falcon

This presentation refreshes you on HTTP and Python/WSGI, then proceeds to walk you through the process of creating a subset of MultiBlog - the multi-author blogging platform - using the Falcon WSGI framework.

You should come out of this knowing: 1) what Falcon is, 2) how to design an API using Falcon, and 3) how to automate testing of APIs implemented with Falcon.

Alejandro Cabrera

November 13, 2013
Tweet

More Decks by Alejandro Cabrera

Other Decks in Programming

Transcript

  1. The Definitive Introduction to Falcon Alejandro Cabrera (alejandro.cabrera@rackspace.com) November 13,

    2013 Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  2. from pprint import pprint if __name__ == ’__main__’: meta =

    { ’author’ : ’Alejandro Cabrera’, ’email’ : ’alejandro.cabrera@rackspace.com’, ’objective’ : ’Introduce Falcon!’ } pprint(meta) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  3. About Me Software developer @ Rackspace Likes: Haskell, Python, Linux,

    open-source, automation, quality, cordiality Dislikes: Proprietary, manual processes, hostility Github: cabrera Twitter: @cppcabrera IRC: alcabrera @ freenode Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  4. Falcon Is. . . Falcon is a high-performance Python framework

    for building cloud APIs. It encourages the REST architectural style, and tries to do as little as possible while remaining highly effective. Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  5. Falcon Is. . . A simple web framework Alejandro Cabrera

    (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  6. Falcon Is. . . A simple web framework WSGI/Python Alejandro

    Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  7. Falcon Is. . . A simple web framework WSGI/Python Fast

    Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  8. But First. . . HTTP Primer WSGI Primer Alejandro Cabrera

    (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  9. HTTP: In Short HTTP/1.1 200 OK Connection: close Content-Length: 119

    Content-Location: /v1/queues Content-Type: application/json; charset=utf-8 Date: Tue, 12 Nov 2013 19:45:55 GMT Server: gunicorn/18.0 { "queues": [ { "href": "/v1/queues/taco", "name": "taco" } ] } Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  10. HTTP: Status Codes Five classes: 100, 200, 300, 400, 500

    Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  11. HTTP: Status Codes Five classes: 100, 200, 300, 400, 500

    100: Informational Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  12. HTTP: Status Codes Five classes: 100, 200, 300, 400, 500

    100: Informational 200: Good - it worked Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  13. HTTP: Status Codes Five classes: 100, 200, 300, 400, 500

    100: Informational 200: Good - it worked 300: Redirections Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  14. HTTP: Status Codes Five classes: 100, 200, 300, 400, 500

    100: Informational 200: Good - it worked 300: Redirections 400: Client-side oops Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  15. HTTP: Status Codes Five classes: 100, 200, 300, 400, 500

    100: Informational 200: Good - it worked 300: Redirections 400: Client-side oops 500: Server side error Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  16. HTTP: Headers Like a dictionary Many standard-defined, some used by

    convention Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  17. HTTP: Headers Connection: close Content-Length: 119 Content-Location: /v1/queues Content-Type: application/json;

    charset=utf-8 Date: Tue, 12 Nov 2013 19:45:55 GMT Server: gunicorn/18.0 Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  18. HTTP: Body Actual data Can be anything Good idea -

    set Content-Type to be descriptive Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  19. HTTP: Body Actual data Can be anything Good idea -

    set Content-Type to be descriptive json -> application/json Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  20. HTTP: Body Actual data Can be anything Good idea -

    set Content-Type to be descriptive json -> application/json html -> text/html Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  21. HTTP: Body Actual data Can be anything Good idea -

    set Content-Type to be descriptive json -> application/json html -> text/html msgpack -> application/x-msgpack Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  22. HTTP: Body Actual data Can be anything Good idea -

    set Content-Type to be descriptive json -> application/json html -> text/html msgpack -> application/x-msgpack binary -> application/octet-stream Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  23. HTTP: Body { "links": [ { "href": "/v1/queues?marker=taco", "rel": "next"

    } ], "queues": [ { "href": "/v1/queues/taco", "name": "taco" } ] } Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  24. HTTP: Request A client makes a request The request carries

    information that a server uses to reply Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  25. HTTP: Request A client makes a request The request carries

    information that a server uses to reply What kind of request is it? (HTTP verb) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  26. HTTP: Request A client makes a request The request carries

    information that a server uses to reply What kind of request is it? (HTTP verb) How large is my payload? (Content-Length) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  27. HTTP: Request A client makes a request The request carries

    information that a server uses to reply What kind of request is it? (HTTP verb) How large is my payload? (Content-Length) What type of data am I sending? (Content-Type) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  28. HTTP: Request A client makes a request The request carries

    information that a server uses to reply What kind of request is it? (HTTP verb) How large is my payload? (Content-Length) What type of data am I sending? (Content-Type) What type of data can I receive? (Accept) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  29. HTTP: Response A server makes a response The response also

    carries metadata Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  30. HTTP: Response A server makes a response The response also

    carries metadata Was it successful? (status code) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  31. HTTP: Response A server makes a response The response also

    carries metadata Was it successful? (status code) What type of data am I replying with? (Content-Type) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  32. HTTP: Verbs This request/response cycle is further controlled by HTTP

    verbs: Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  33. HTTP: Verbs This request/response cycle is further controlled by HTTP

    verbs: HEAD Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  34. HTTP: Verbs This request/response cycle is further controlled by HTTP

    verbs: HEAD GET Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  35. HTTP: Verbs This request/response cycle is further controlled by HTTP

    verbs: HEAD GET PUT Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  36. HTTP: Verbs This request/response cycle is further controlled by HTTP

    verbs: HEAD GET PUT POST Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  37. HTTP: Verbs This request/response cycle is further controlled by HTTP

    verbs: HEAD GET PUT POST DELETE Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  38. HTTP: Verbs This request/response cycle is further controlled by HTTP

    verbs: HEAD GET PUT POST DELETE PATCH Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  39. HTTP: Routing Finally, the server needs to know what you

    want to access to respond Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  40. HTTP: Routing Finally, the server needs to know what you

    want to access to respond A route looks like: Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  41. HTTP: Routing # ||| Method GET /v1/queues HTTP/1.1 Alejandro Cabrera

    (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  42. HTTP: Routing # ||| Route GET /v1/queues HTTP/1.1 Alejandro Cabrera

    (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  43. HTTP: Routing # ||| Protocol GET /v1/queues HTTP/1.1 Alejandro Cabrera

    (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  44. HTTP: Routing The Host tells us which server to access

    Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  45. HTTP: Routing The Host tells us which server to access

    The URI tells us what resource to access Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  46. HTTP: Routing The Host tells us which server to access

    The URI tells us what resource to access The URI can also have a query string (more on this later) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  47. An Aside: REST REST is a style of writing web

    applications Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  48. An Aside: REST REST is a style of writing web

    applications In short, it means - follow the HTTP standard Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  49. An Aside: REST REST is a style of writing web

    applications In short, it means - follow the HTTP standard Key points: Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  50. An Aside: REST REST is a style of writing web

    applications In short, it means - follow the HTTP standard Key points: HEAD|GET are read-only, pure, safe operations Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  51. An Aside: REST REST is a style of writing web

    applications In short, it means - follow the HTTP standard Key points: HEAD|GET are read-only, pure, safe operations PUT|DELETE modify a resource, but should be idempotent Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  52. An Aside: REST REST is a style of writing web

    applications In short, it means - follow the HTTP standard Key points: HEAD|GET are read-only, pure, safe operations PUT|DELETE modify a resource, but should be idempotent POST creates an entity subordinate to the given URI Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  53. An Aside: REST REST is a style of writing web

    applications In short, it means - follow the HTTP standard Key points: HEAD|GET are read-only, pure, safe operations PUT|DELETE modify a resource, but should be idempotent POST creates an entity subordinate to the given URI PATCH modifies a portion of an entity Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  54. WSGI: What? A Pythonic approach to HTTP application development Alejandro

    Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  55. WSGI: What? A Pythonic approach to HTTP application development Takes

    HTTP headers and metadata and stuffs them in dictionaries Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  56. WSGI: What? A Pythonic approach to HTTP application development Takes

    HTTP headers and metadata and stuffs them in dictionaries Takes body content and stores it as a stream Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  57. WSGI: What? A Pythonic approach to HTTP application development Takes

    HTTP headers and metadata and stuffs them in dictionaries Takes body content and stores it as a stream Think of it as: HTTP made easy Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  58. WSGI: Hello World def hello(env, start_response): print(env[’PATH_INFO’]) status = ’200

    OK’ headers = [(’Content-Type’, ’text/plain’)] body = b’hello’ start_response(status, headers) return [body] Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  59. Falcon: WSGI Made Easy Falcon wraps WSGI and gives us:

    Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  60. Falcon: WSGI Made Easy Falcon wraps WSGI and gives us:

    Easy routing + method not allowed Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  61. Falcon: WSGI Made Easy Falcon wraps WSGI and gives us:

    Easy routing + method not allowed Request/response objects Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  62. Falcon: WSGI Made Easy Falcon wraps WSGI and gives us:

    Easy routing + method not allowed Request/response objects Automatic header setting Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  63. Falcon: WSGI Made Easy Falcon wraps WSGI and gives us:

    Easy routing + method not allowed Request/response objects Automatic header setting Clean, consistent exceptions (400s, 500s) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  64. Falcon: WSGI Made Easy Falcon wraps WSGI and gives us:

    Easy routing + method not allowed Request/response objects Automatic header setting Clean, consistent exceptions (400s, 500s) Classes to express responders Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  65. Falcon: Hello World import falcon class Hello(object): def on_get(self, request,

    response): response.body = b’hello’ response.status = falcon.HTTP_200 app = falcon.API() app.add_route(’/’, Hello()) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  66. Falcon: Request Objects Contain at least the following information: Alejandro

    Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  67. Falcon: Request Objects Contain at least the following information: path

    - /v1/queues Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  68. Falcon: Request Objects Contain at least the following information: path

    - /v1/queues query string - detailed=True Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  69. Falcon: Request Objects Contain at least the following information: path

    - /v1/queues query string - detailed=True content length - how long is the body? Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  70. Falcon: Request Objects Contain at least the following information: path

    - /v1/queues query string - detailed=True content length - how long is the body? content type Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  71. Falcon: Request Objects Contain at least the following information: path

    - /v1/queues query string - detailed=True content length - how long is the body? content type uri - localhost:8000/v1/queues?detailed=True Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  72. Falcon: Request Objects Contain at least the following information: path

    - /v1/queues query string - detailed=True content length - how long is the body? content type uri - localhost:8000/v1/queues?detailed=True relative uri - /v1/queues?detailed=True Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  73. Falcon: Request Objects Contain at least the following information: path

    - /v1/queues query string - detailed=True content length - how long is the body? content type uri - localhost:8000/v1/queues?detailed=True relative uri - /v1/queues?detailed=True More! Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  74. Falcon: Request Objects Contain at least the following information: path

    - /v1/queues query string - detailed=True content length - how long is the body? content type uri - localhost:8000/v1/queues?detailed=True relative uri - /v1/queues?detailed=True More! Also has methods for handling query params! Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  75. Falcon: Response Objects Responses have: body - set this to

    return content to the client Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  76. Falcon: Response Objects Responses have: body - set this to

    return content to the client location - sets Location header Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  77. Falcon: Response Objects Responses have: body - set this to

    return content to the client location - sets Location header content type Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  78. Falcon: Response Objects Responses have: body - set this to

    return content to the client location - sets Location header content type etag Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  79. Falcon: Response Objects Responses have: body - set this to

    return content to the client location - sets Location header content type etag set header(s) - custom header handling Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  80. Falcon: Response Objects Responses have: body - set this to

    return content to the client location - sets Location header content type etag set header(s) - custom header handling More! Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  81. Crafting an API API == zip(routes, resources) Route: a URI

    associated with one or more HTTP verbs Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  82. Crafting an API API == zip(routes, resources) Route: a URI

    associated with one or more HTTP verbs Resource: a responder that contains application logic Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  83. Crafting an API API == zip(routes, resources) Route: a URI

    associated with one or more HTTP verbs Resource: a responder that contains application logic Put them together! Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  84. Crafting an API API == zip(routes, resources) Route: a URI

    associated with one or more HTTP verbs Resource: a responder that contains application logic Put them together! One resource per route (usually) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  85. Crafting an API API == zip(routes, resources) Route: a URI

    associated with one or more HTTP verbs Resource: a responder that contains application logic Put them together! One resource per route (usually) Let’s practice with. . . Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  86. Crafting an API: MultiBlog It helps to layout the routes

    and resources before writing even a single line of code Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  87. Crafting an API: MultiBlog It helps to layout the routes

    and resources before writing even a single line of code Let’s do that now Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  88. Crafting an API: MultiBlog GET /v1 GET /v1/health GET /v1/stats

    Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  89. Crafting an API: MultiBlog GET /v1 GET /v1/health GET /v1/stats

    GET /v1/authors POST /v1/authors Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  90. Crafting an API: MultiBlog GET /v1 GET /v1/health GET /v1/stats

    GET /v1/authors POST /v1/authors GET /v1/authors/{author} PATCH /v1/authors/{author} DELETE /v1/authors/{author} Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  91. Crafting an API: MultiBlog GET /v1 GET /v1/health GET /v1/stats

    GET /v1/authors POST /v1/authors GET /v1/authors/{author} PATCH /v1/authors/{author} DELETE /v1/authors/{author} GET /v1/blog/{author} POST /v1/blog/{author} Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  92. Crafting an API: MultiBlog GET /v1/authors POST /v1/authors GET /v1/authors/{author}

    PATCH /v1/authors/{author} DELETE /v1/authors/{author} GET /v1/blog/{author} POST /v1/blog/{author} GET /v1/blog/{author}/{post} PATCH /v1/blog/{author}/{post} DELETE /v1/blog/{author}/{post} Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  93. Crafting an API: MultiBlog # Management routes GET /v1 GET

    /v1/health GET /v1/stats Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  94. Crafting an API: MultiBlog # Listing and creating authors GET

    /v1/authors POST /v1/authors Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  95. Crafting an API: MultiBlog # Working with specific authors GET

    /v1/authors/{author} PATCH /v1/authors/{author} DELETE /v1/authors/{author} Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  96. Crafting an API: MultiBlog # Reading blog details, creating an

    entry GET /v1/blog/{author} POST /v1/blog/{author} Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  97. Crafting an API: MultiBlog # Working with existing posts GET

    /v1/blog/{author}/{post} PATCH /v1/blog/{author}/{post} DELETE /v1/blog/{author}/{post} Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  98. Falcon: Crafting a Resource Resources are classes that serve as

    responders Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  99. Falcon: Crafting a Resource Resources are classes that serve as

    responders Example follows: we’ll create a BlogEntry resource! Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  100. Falcon: Crafting a Resource Resources are classes that serve as

    responders Example follows: we’ll create a BlogEntry resource! Expresses part of the “existing posts” routes Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  101. Falcon: Crafting a Resource class BlogEntry(object): def __init__(self, db_client): self._post_ctrl

    = db_client Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  102. Falcon: Crafting a Resource class BlogEntry(object): def __init__(self, db_client): self._post_ctrl

    = db_client def on_get(self, request, response, author, post): content = self._post_ctrl.get(author, post) if not content: raise falcon.exceptions.HTTPNotFound() response.content_type = ’application/json’ response.body = content[’body’] Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  103. Falcon: Crafting a Resource class BlogEntry(object): def __init__(self, db_client): self._post_ctrl

    = db_client def on_get(self, request, response, author, post): content = self._post_ctrl.get(author, post) if not content: raise falcon.exceptions.HTTPNotFound() response.content_type = ’application/json’ response.body = content[’body’] def on_delete(self, request, response, author, post): self._post_ctrl.delete(author, post) response.status = falcon.HTTP_204 Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  104. Falcon: Crafting a Resource class BlogEntry(object): def __init__(self, db_client): self._post_ctrl

    = db_client Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  105. Falcon: Crafting a Resource class BlogEntry(object): # ||| responds to

    GET requests def on_get(self, request, response, author, post): content = self._post_ctrl.get(author, post) if not content: raise falcon.exceptions.HTTPNotFound() response.content_type = ’application/json’ response.body = content[’body’] Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  106. Falcon: Crafting a Resource class BlogEntry(object): def on_get(self, request, response,

    author, post): ... # ||| Returning a 404 if not content: raise falcon.exceptions.HTTPNotFound() ... Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  107. Falcon: Crafting a Resource class BlogEntry(object): def on_get(self, request, response,

    author, post): ... # ||| user-visible response: 200 OK by default response.content_type = ’application/json’ response.body = content[’body’] Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  108. Falcon: Crafting a Resource class BlogEntry(object): # ||| Responds to

    DELETEs def on_delete(self, request, response, author, post): self._post_ctrl.delete(author, post) response.status = falcon.HTTP_204 Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  109. Falcon: Crafting a Resource class BlogEntry(object): # ||| Request object

    def on_get(self, request, response, author, post): ... Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  110. Falcon: Crafting a Resource class BlogEntry(object): # ||| Response object

    def on_get(self, request, response, author, post): ... Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  111. Falcon: Crafting a Resource class BlogEntry(object): # ||| URI template

    args def on_get(self, ..., author, post): ... Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  112. Falcon: Crafting a Resource class BlogEntry(object): def on_patch(...): pass Alejandro

    Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  113. Falcon: Crafting a Resource class BlogEntry(object): def on_patch(...): pass #

    Left as an exercise for the reader! Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  114. Falcon: Exposing the API Here, we come back to routes

    Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  115. Falcon: Exposing the API Here, we come back to routes

    To connect a resource to a route. . . Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  116. Falcon: Exposing the API # blog.py app = falcon.API() app.add_route(’/v1/blog/{author}/{post}’,

    BlogEntry(db_client)) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  117. Falcon: Exposing the API # ||| Falcon’s API object app

    = falcon.API() Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  118. Falcon: Exposing the API # ||| The route app.add_route(’/v1/blog/{author}/{post}’, ...)

    Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  119. Falcon: Exposing the API # ||| The responder app.add_route(..., BlogEntry(db_client))

    Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  120. Falcon: Exposing the API # ||| URI templates # |||

    passed as param to responder app.add_route(’/v1/blog/{author}/{post}’, ...) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  121. Falcon: Making it Fly Now we have to run it

    For this demo, we’ll use gunicorn Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  122. Falcon: Make it Fly $ pip install gunicorn ... Alejandro

    Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  123. Falcon: Make it Fly $ pip install gunicorn ... Successfully

    installed gunicorn Cleaning up... Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  124. Falcon: Make it Fly $ gunicorn blog:app [INFO] Starting gunicorn

    18.0 [INFO] Listening at: http://127.0.0.1:8000 (6194) [INFO] Using worker: sync [INFO] Booting worker with pid: 6199 Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  125. Falcon: Manual Testing Allow me to recommend httpie: Alejandro Cabrera

    (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  126. Falcon: Manual Testing Allow me to recommend httpie: It’s built

    on python-requests Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  127. Falcon: Manual Testing Allow me to recommend httpie: It’s built

    on python-requests It’s human-friendly Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  128. Falcon: Manual Testing Allow me to recommend httpie: It’s built

    on python-requests It’s human-friendly It’s easy to install Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  129. Falcon: Manual Testing Allow me to recommend httpie: It’s built

    on python-requests It’s human-friendly It’s easy to install It’s well-behaved and handles HTTP really well Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  130. Falcon: Manual Testing $ pip install httpie ... Alejandro Cabrera

    (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  131. Falcon: Manual Testing $ pip install httpie ... Successfully installed

    httpie Cleaning up... Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  132. Falcon: Manual Testing $ http get localhost:8000/v1/blog/alej/1 HTTP/1.1 200 OK

    Connection: close Content-Type: application/text Date: Tue, 12 Nov 2013 20:13:58 GMT Server: gunicorn/18.0 Transfer-Encoding: chunked Cool story, bro. Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  133. Falcon: Manual Testing $ http get localhost:8000/v1/alej/1 HTTP/1.1 404 Not

    Found Connection: close Content-Length: 0 Date: Tue, 12 Nov 2013 20:49:17 GMT Server: gunicorn/18.0 Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  134. Falcon: Manual Testing $ http post localhost:8000/v1/blog/alej/1 HTTP/1.1 405 Method

    Not Allowed Allow: GET Connection: close Content-Length: 0 Date: Tue, 12 Nov 2013 20:50:02 GMT Server: gunicorn/18.0 Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  135. Falcon: Manual Testing $ http delete localhost:8000/v1/blog/alej/1 HTTP/1.1 204 No

    Content Connection: close Date: Tue, 12 Nov 2013 20:50:35 GMT Server: gunicorn/18.0 Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  136. Falcon: Automated Testing Manual testing is kinda cool. . .

    Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  137. Falcon: Automated Testing Manual testing is kinda cool. . .

    . . . but not ideal for long-term maintenance Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  138. Falcon: Automated Testing Manual testing is kinda cool. . .

    . . . but not ideal for long-term maintenance Unit testing with Falcon is pretty easy Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  139. Falcon: Automated Testing Manual testing is kinda cool. . .

    . . . but not ideal for long-term maintenance Unit testing with Falcon is pretty easy Functional testing with Falcon + python-requests is doable, as well Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  140. Falcon: Unit Testing (The Base Class) First, let’s start with

    a base class to help us simulate requests Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  141. Falcon: Unit Testing (The Base Class) class TestBase(unittest.TestCase): def setUp(self):

    self.app = blog.app self.srmock = falcon.testing.StartResponseMock() Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  142. Falcon: Unit Testing (The Base Class) class TestBase(unittest.TestCase): def setUp(self):

    self.app = blog.app self.srmock = falcon.testing.StartResponseMock() def simulate_request(self, path, ...): env = falcon.testing.create_environ( path=path, **kwargs ) return self.app(env, self.srmock) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  143. Falcon: Unit Testing (The Base Class) class TestBase(unittest.TestCase): def setUp(self):

    self.app = blog.app self.srmock = falcon.testing.StartResponseMock() def simulate_request(self, path, ...): env = falcon.testing.create_environ( path=path, **kwargs ) return self.app(env, self.srmock) def simulate_get(self, *args, **kwargs): kwargs[’method’] = ’GET’ return self.simulate_request(*args, **kwargs) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  144. Falcon: Unit Testing (The Base Class) # ||| unittest as

    foundation class TestBase(unittest.TestCase): Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  145. Falcon: Unit Testing (The Base Class) class TestBase(unittest.TestCase): def setUp(self):

    # ||| your blog API self.app = blog.app self.srmock = falcon.testing.StartResponseMock() Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  146. Falcon: Unit Testing (The Base Class) class TestBase(unittest.TestCase): # |||

    generic request handler def simulate_request(self, path, ...): env = falcon.testing.create_environ( path=path, **kwargs ) return self.app(env, self.srmock) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  147. Falcon: Unit Testing (The Base Class) class TestBase(unittest.TestCase): def simulate_request(self,

    path, ...): # ||| create a mock WSGI environment env = falcon.testing.create_environ( path=path, **kwargs ) return self.app(env, self.srmock) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  148. Falcon: Unit Testing (The Base Class) class TestBase(unittest.TestCase): # |||

    a method for simulating GETs def simulate_get(self, *args, **kwargs): kwargs[’method’] = ’GET’ return self.simulate_request(*args, **kwargs) ... Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  149. Falcon: Unit Testing (The Base Class) class TestBase(unittest.TestCase): # more

    methods, more methods! (just like GET) def simulate_head(self, *args, **kwargs): ... def simulate_put(self, *args, **kwargs): ... def simulate_delete(self, *args, **kwargs): ... def simulate_patch(self, *args, **kwargs): ... def simulate_post(self, *args, **kwargs): ... Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  150. Falcon: Unit Testing (The Test) With a handy base class

    in hand, let’s actually test this thing! Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  151. Falcon: Unit Testing (The Test) @ddt.ddt class TestBlogEntry(base.TestBase): def setUp(self):

    super(TestBlogEntry, self).setUp() # create a blog post self.entry_path = ’/v1/blog/alej/1’ self.simulate_post(’/v1/blog/alej’) def tearDown(self): self.simulate_delete(’/v1/blog/alej/1’) super(TestBlogEntry, self).tearDown() Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  152. Falcon: Unit Testing (The Test) @ddt.ddt class TestBlogEntry(base.TestBase): ... def

    test_get_returns_200_when_entry_exists(self): self.simulate_get(self.entry_path) self.assertEqual(self.srmock.status, falcon.HTTP_200) def test_get_returns_404_when_entry_not_found(self): self.simulate_get(’/v1/blog/alej/notfound’) self.assertEqual(self.srmock.status, falcon.HTTP_404) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  153. Falcon: Unit Testing (The Test) @ddt.ddt class TestBlogEntry(base.TestBase): ... @ddt.data([self.entry_path,

    ’/v1/blog/alej/notfound’]) def test_delete_always_returns_204(self, path): self.simulate_delete(path) self.assertEqual(self.srmock.status, falcon.HTTP_204) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  154. Falcon: Unit Testing (The Test) @ddt.ddt class TestBlogEntry(base.TestBase): ... @ddt.data(’post’,

    ’put’, ’patch’, ’head’) def test_method_not_allowed_respected(self, method): getattr(self, ’on_’ + method)(self.entry_path) self.assertEqual(self.srmock.status, falcon.HTTP_405) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  155. Falcon: Run the Tests $ nosetests -v tests/test_blog.py Alejandro Cabrera

    (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  156. Falcon: Run the Tests $ nosetests -v tests/test_blog.py ... Ran

    8 tests in 0.008s OK Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  157. Recap With a basic understanding of HTTP. . . Alejandro

    Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  158. Recap With a basic understanding of HTTP. . . .

    . . adding a smidgen of WSGI. . . Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  159. Recap With a basic understanding of HTTP. . . .

    . . adding a smidgen of WSGI. . . . . . a couple of routes. . . Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  160. Recap With a basic understanding of HTTP. . . .

    . . adding a smidgen of WSGI. . . . . . a couple of routes. . . . . . and a dash of resources . . . Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  161. Recap With a basic understanding of HTTP. . . .

    . . adding a smidgen of WSGI. . . . . . a couple of routes. . . . . . and a dash of resources . . . . . . allowed to bake in a test oven for a few minutes . . . Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  162. Recap With a basic understanding of HTTP. . . .

    . . adding a smidgen of WSGI. . . . . . a couple of routes. . . . . . and a dash of resources . . . . . . allowed to bake in a test oven for a few minutes . . . . . . you, too, can have a Falcon-powered web application! Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  163. Quick Takes How do I read the request contents? Alejandro

    Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  164. Quick Takes How do I read the request contents? request.stream.read()

    Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  165. Quick Takes How do I set a header for the

    response? Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  166. Quick Takes How do I set a header for the

    response? response.set_header(’X-Awesomeness’, ’You’) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  167. Quick Takes Where can I find all the errors falcon

    can raise? (400s, 500s) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  168. Quick Takes Where can I find all the errors falcon

    can raise? (400s, 500s) from falcon import exceptions dir(exceptions) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  169. Quick Takes How can I generate an etag? Alejandro Cabrera

    (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  170. Quick Takes How can I generate an etag? import hashlib

    md5 = hashlib.md5 response.etag = md5(request.stream.read()).hexdigest() Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  171. Quick Takes How can I retrieve URI query parameters? Alejandro

    Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  172. Quick Takes How can I retrieve URI query parameters? limit

    = request.get_param_as_int(’limit’) detailed = request.get_param_as_bool(’detailed’) marker = request.get_param(’marker’) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  173. Falcon: Next Steps Write your own application Add storage Alejandro

    Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  174. Falcon: Next Steps Write your own application Add storage Learn

    about middleware Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  175. Falcon: Next Steps Write your own application Add storage Learn

    about middleware Leveling up your tests: tox, mock, httpretty Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  176. Falcon: Next Steps Write your own application Add storage Learn

    about middleware Leveling up your tests: tox, mock, httpretty Contribute! Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon
  177. Falcon: Thanks To These Falconians! Kurt Griffiths (kgriffs) created Falcon

    and is its current maintainer. Many thanks to all the mighty fine contributors to the project, listed below by date of contribution: Alejandro Cabrera (cabrera) Chad Lung (chadlung) Josh Brand (joshbrand) Jamie Painter (painterjd) Flavio Percoco (flaper87) Randall Burt (rs-randallburt) Zhihao Yuan (lichray) Ashutosh Das (pyprism) Emanuele Rocca (ema) Flavio Percoco (flaper87) Soren Hansen (sorenh) Alejandro Cabrera (alejandro.cabrera@rackspace.com) The Definitive Introduction to Falcon