Python Falcon – Environment Setup ”; Previous Next The latest version of Falcon requires Python 3.5 or newer version. The easiest as well as recommended way to install Falcon is with PIP installer, preferably in a virtual environment. The latest stable version can be installed by running the following command − pip3 install falcon To verify if the installation has been performed successfully, import the library and check its version. >>> import falcon >>>falcon.__version__ ”3.1.0” To install the latest beta version, following command should be used − pip3 install –pre falcon Right from the early version, Falcon supports WSGI. A Falcon app can be run with the help of built-in WSGI server in Python”s standard library module wsgiref. However, it is not suitable for production environment, for which WSGI servers such as gunicorn, waitress or uwsgi are required. For Falcon on Windows, one can use Waitress, a production-quality, pure-Python WSGI server. As usual, install it with pip installer. pip3 install waitress The Gunicorn server can”t be installed on Windows. However, it can be used inside a Windows Subsystem Linux (WSL) environment on Windows 10. For using gunicorn on Linux, WSL or inside Docker containers, use pip3 install gunicorn If you want to run an asynchronous Falcon app, an ASGI compliant application server is required. The Uvicorn server can be used on Windows as well as Linux systems. pip3 install uvicorn Print Page Previous Next Advertisements ”;
Category: python Falcon
Python Falcon – Jinja2 Template ”; Previous Next The Falcon library is primarily used to build APIs and microservices. Hence, by default, a Falcon responder returns a JSON response. However, if the content type is changed to falcon.MEDIA_HTML, it is possible to render HTML output. Rendering a HTML content with variable data is very tedious. For this purpose, web templating libraries are used. Many Python web frameworks are bundled with specific template library. But Falcon being a minimalist micro framework doesn”t come pre-bundled with anyone. Jinja2 is one of the most popular template libraries used by many python frameworks. In this section, we shall see how to use inja2 with Falcon application. The jinja2 is a fast and designer-friendly templating language that is easy to configure and debug. Its sandboxed environment makes it easy to prevent the execution of untrusted code, prohibit potentially unsafe data, and prevent cross-site scripting attacks (called XSS attacks). Another very powerful feature of jinja2 is the template inheritance, wherein You can define a base template having common design features which child templates can override. First of all, install jinja2 in the current Python environment with the use of PIP utility. pip3 install jinja2 Hello World Template The jinja2 module defines a Template class. A Template object is obtained by reading the contents of a file containing HTML script (one with .html extension). By invoking the render() method of this Template object, HTML response can be rendered to the client browser. The content_type property of Response object must be set to falcon.MEDIA_HTML. Let us save the following HTML script as hello.py in the application folder. <html> <body> <h2>Hello World</h2> </body> </html> Example The on_get() responder in the resource class below reads this file and renders it as HTML response. import uvicorn import falcon import falcon.asgi from jinja2 import Template class HelloResource: async def on_get(self, req, resp): resp.status = falcon.HTTP_200 resp.content_type = ”text/html” fp=open(“hello.html”,”r”) tempobj=Template(fp.read()) resp.body=tempobj.render() app = falcon.asgi.App() hello = HelloResource() app.add_route(”/hello”, hello) if __name__ == “__main__”: uvicorn.run(“hello:app”, host=”0.0.0.0″, port=8000, reload=True) Output Run the above Python code and visit http://localhost:8000/hello link in the browser. Template Variable jinja2 is a server-side templating library. The web page is constructed as a template by putting various elements of jinja2 templating language as place-holders within appropriate delimiters inside the HTML script. The template engine reads the HTML script, substitutes the place-holders with context data on the server, reassembles the HTML, and renders it to the client. The Template.render() function has an optional context dictionary parameter. The key attributes of this dictionary become the template variables. This helps in rendering the data passed by the responders in the web page. Example In the following example, the route /hello/nm is registered with the resource object, where nm is the path parameter. The on_get() responder passes it as a context to the template object obtained from a web page. import uvicorn import falcon import falcon.asgi from jinja2 import Template class HelloResource: async def on_get(self, req, resp, nm): resp.status = falcon.HTTP_200 resp.content_type = ”text/html” fp=open(“hello.html”,”r”) tempobj=Template(fp.read()) resp.body=tempobj.render({”name”:nm}) app = falcon.asgi.App() hello = HelloResource() app.add_route(”/hello/{nm}”, hello) if __name__ == “__main__”: uvicorn.run(“hello:app”, host=”0.0.0.0″, port=8000, reload=True) The hello.html reads the path parameter in a template variable name. It acts as a place holder in the HTML script. It is put in {{ and }} symbols so that its value appears as a HTML response. <html> <body> <h2>Hello {{ name }}</h2> </body> </html> Output Run the Python code and enter http://localhost:8000/hello/Priya as the URL. The browser displays the following output − Loop in jinja2 Template If the responder passes any Python iterable object such as a list, tuple or a dictionary, its elements can be traversed inside the jinja2 template using its looping construct syntax. {% for item in collection %} HTML block {% endfor %} In the following example, the on_get() responder sends students object which is a list of dict objects, to the template list.html. It in turn traverses the data and renders it as a HTML table. import falcon import json from waitress import serve from jinja2 import Template students = [ {“id”: 1, “name”: “Ravi”, “percent”: 75.50}, {“id”: 2, “name”: “Mona”, “percent”: 80.00}, {“id”: 3, “name”: “Mathews”, “percent”: 65.25}, ] class StudentResource: def on_get(self, req, resp): resp.status = falcon.HTTP_OK resp.content_type = falcon.MEDIA_HTML fp=open(“list.html”,”r”) tempobj=Template(fp.read()) resp.body=tempobj.render({”students”:students}) list.html is a jinja2 template. It receives the students object as list of dictionary objects and puts the value of each key inside <td>..<.td> element of a table. <html> <body> <table border=1> <thead> <tr> <th>Student ID</th> <th>Student Name</th> <th>percentage</th> <th>Actions</th> </tr> </thead> <tbody> {% for Student in students %} <tr> <td>{{ Student.id }}</td> <td>{{ Student.name }}</td> <td>{{ Student.percent }}</td> <td> <a href=”#”>Edit</a> <a href=”#”>Delete</a> </td> </tr> {% endfor %} </tbody> </table> </body> </html> Visit the /students route in the browser”s address bar. The list of students is rendered in the browser. HTML Form Template In this section, we shall see how Falcon reads the data from HTML form. Let us save the following HTML script as myform.html. We shall use it for obtaining Template object and render it. <html> <body> <form method=”POST” action=”http://localhost:8000/students”> <p>Student Id: <input type=”text” name=”id”/> </p> <p>student Name: <input type=”text” name=”name”/> </p> <p>Percentage: <input type=”text” name=”percent”/> </p> <p><input type=”submit”> </p> </body> </html> The Falcon App object is declared in Hello.py file which also has a resource class mapped to /adddnew route. The on_get() responder reads the myform.html and renders the same. The HTML form will be displayed. The form is submitted to /students route by POST method. To be able to read the form data, the auto_parse_form_urlencoded property of falcon.RequestOptions class must be set to True. app = falcon.App() app.req_options.auto_parse_form_urlencoded = True Here, we also import StudentResource
Python Falcon – Routing
Python Falcon – Routing ”; Previous Next Falcon adopts RESTful architectural style. Hence it uses resource based routing. A resource class is responsible for handling the HTTP methods by the responders, which are essentially class methods with a name that starts with on_ and ends in the lowercased HTTP method name (e.g., on_get(), on_patch(), on_delete(), etc.). The add_route() method of the Falcon Application object associates its router with an instance of resource class. In the Hellofalcon.py example used above, the on_get() and on_post() responders are invoked when the /hello route is requested by the client by GET and POST method respectively. If no route matches the request, an instance of HTTPRouteNotFound is raised. On the other hand, if a route is matched but the resource does not implement a responder for the requested HTTP method, a default responder raises an instance of HTTPMethodNotAllowed. Field Converters Falcon”s routing mechanism allows URLs to pass parameters to the responders. The URL comprises of three parts: The protocol (such as http:// or https://) followed by the IP address or hostname. The remaining part of the URL after first / after the hostname is called as the path or endpoint. Parameters to be passed are after the endpoint. This acts as a resource identifier such as a unique ID or primary key. The parameter names are enclosed in curly brackets. Value of a path parameter goes to the argument defined in the responder method in addition to request and response. In the following example, the router associates the resource class object with a URL consisting of a parameter after the endpoint. from waitress import serve import falcon import json class HelloResource: def on_get(self, req, resp, nm): “””Handles GET requests””” resp.status = falcon.HTTP_200 resp.content_type = falcon.MEDIA_TEXT resp.text = ( ”Hello ”+nm ) app = falcon.App() hello = HelloResource() app.add_route(”/hello/{nm}”, hello) if __name__ == ”__main__”: serve(app, host=”0.0.0.0”, port=8000) We can see that the on_get() responder method has an additional parameter nm to accept the data parsed from the URL route. Let us test http://localhost:8000/hello/Priya with HTTPie tool. >http GET localhost:8000/hello/Priya HTTP/1.1 200 OK Content-Length: 11 Content-Type: text/plain; charset=utf-8 Date: Mon, 18 Apr 2022 12:27:35 GMT Server: waitress Hello Priya The default data type to which the path parameters are parsed to is str (i.e. string). However, Falcon”s router engine has the following built-in field converters using which they can be read into other data types as well. IntConverter − This class is defined in falcon.routing module. The constructor uses the following arguments − IntConverter(num_digits=None, min=None, max=None) Where, num_digits − The value must have given number of digits. min − minimum required value of the parameter max − maximum allowed value of the parameter. For example, the following add_route() function accepts an integer between 1 to 100 as rollno. app.add_route(”/student/{rollno:int(1,1,100}”, StudentResource()) UUIDConverter − This class in the falcon.routing module gives converts a string of 32 hexadecimal digits into a UUID (Universal Unique Identifier). DateTimeConverter − Converts the parameter string to a datetime variable. The parameter must be a string in any format recognized by strptime() function, the default being ”%Y-%m-%dT%H:%M:%SZ”. Format string uses the following format codes − %a Abbreviated weekday name Sun, Mon %A Full weekday name Sunday, Monday %d Day of the month as a zero-padded decimal 01, 02 %-d day of the month as decimal number 1, 2.. %b Abbreviated month name Jan, Feb %m month as a zero padded decimal number 01, 02 %B Full month name January, February %-y year without century as a decimal number 0, 99 %Y year with century as a decimal number 2000, 1999 %H hour(24 hour clock) as a zero padded decimal number 01, 23 %p locale”s AM or PM AM, PM %-M Minute as a decimal number 1, 59 %-S Second as a decimal number 1, 59 In the following example, the add_route() function associates a URL with two parameters with the Resource object. First parameter nm is a string by default. The second parameter age uses IntConverter. from waitress import serve import falcon import json class HelloResource: def on_get(self, req, resp, nm,age): “””Handles GET requests””” retvalue={“name”:nm, “age”:age} resp.body=json.dumps(retvalue) resp.status = falcon.HTTP_200 resp.content_type = falcon.MEDIA_JSON app = falcon.App() hello = HelloResource() app.add_route(”/hello/{nm}/{age:int}”, hello) if __name__ == ”__main__”: serve(app, host=”0.0.0.0”, port=8000) Note that the on_get() responder uses the path parameters to form a dict object – retvalue. Its JSON representation is then assigned as the value of response body and returned to the client. As mentioned earlier, JSON is the default content type of Falcon”s response object. Start the Waitress server and check the response for the URL http://localhost:8000/hello/Priya/21 with the help of HTTPie. http GET localhost:8000/hello/Priya/21 HTTP/1.1 200 OK Content-Length: 28 Content-Type: application/json Date: Fri, 22 Apr 2022 14:22:47 GMT Server: waitress { “age”: 21, “name”: “Priya” } You can also check the response in a browser as follows − Print Page Previous Next Advertisements ”;
Python Falcon – ASGI
Python Falcon – ASGI ”; Previous Next ASGI stands for Asynchronous Server Gateway Interface (as per its official documentation, it is a spiritual successor to WSGI), it adds the async capabilities to Python web servers, applications and frameworks. For running an async web application, we”ll need an ASGI application server. Popular choices include − Uvicorn Daphne Hypercorn We shall use Uvicorn server for async examples in this tutorial. Hello World – ASGI The ASGI related functionality of Falcon is available in the falcon.asgi module. Hence, we need to import it in the beginning. import falcon import falcon.asgi While the resource class remains the same as in the previous example, the on_get() method must be declared with async keyword. we have to obtain the instance of Falson”s ASGI app. app = falcon.asgi.App() Example Hence, the hellofalcon.py for ASGI will be as follows − import falcon import falcon.asgi class HelloResource: async def on_get(self, req, resp): “””Handles GET requests””” resp.status = falcon.HTTP_200 resp.content_type = falcon.MEDIA_TEXT resp.text = ( ”Hello World” ) app = falcon.asgi.App() hello = HelloResource() app.add_route(”/hello”, hello) To run the application, start the Uvicorn server from the command line as follows − uvicorn hellofalcon:app –reload Output Open the browser and visit http://localhost:/8000/hello. You will see the response in the browser window. Print Page Previous Next Advertisements ”;
Python Falcon – Resource Class ”; Previous Next Falcon”s design borrows several key concepts from the REST architectural style. REST stands for Relational State Transfer. REST defines how the architecture of web applications should behave. REST is a resource-based architecture. Here, everything that the REST server hosts, be it a file, an image or row in a table of a database, is treated as a resource, which may have many representations. The REST API provides a controlled access to these resources so that the client can retrieve and modify them. A resource with the server should have only one uniform resource identifier (URI). It only identifies the resource; it does not specify what action to take on that resource. Instead, users choose from a set of standard methods. HTTP verb or method to be used for the operation on the resources. The POST, GET, PUT and DELETE methods perform CREATE, READ, UPDATE and DELETE operations respectively. Falcon uses normal Python classes to represent resources. Such a class acts as a controller in your application. It converts an incoming request into one or more internal actions, and then compose a response back to the client based on the results of those actions. Each resource class defines various “responder” methods, one for each HTTP method the resource allows. Responder names start with “on_” and are named according to which HTTP method they handle, as in on_get(), on_post(), on_put(), etc. In the hellofalcon.py example code used above, HelloResource (the resource class) has an on_get() responder method. Responders must always define at least two arguments to receive Request and Response objects. import falcon class HelloResource: def on_get(self, req, resp): “””Handles GET requests””” resp.status = falcon.HTTP_200 resp.content_type = falcon.MEDIA_TEXT resp.text = ( ”Hello World” ) For ASGI apps, the responder must be a coroutine function, i.e. must be defined with async keyword. class HelloResource: async def on_get(self, req, resp): “””Handles GET requests””” resp.status = falcon.HTTP_200 resp.content_type = falcon.MEDIA_TEXT resp.text = ( ”Hello World” ) The Request object represents the incoming HTTP request. Request headers, query string parameters, and other metadata associated with the request can be accessed through this object. The Response object represents the application”s HTTP response to the request. Properties and methods of this object set status, header and body data. It also exposes a dict-like context property for passing arbitrary data to hooks and other middleware methods. Note that HelloResource in the above example is just a normal Python class. It can have any name; however, the convention is to name it as xxxResource. Print Page Previous Next Advertisements ”;
Python Falcon – Hooks
Python Falcon – Hooks ”; Previous Next Hooks are the user defined functions that are executed automatically when a specific responder method in the resource class is invoked in response to the client request. Falcon supports before and after hooks. A function to be used as a hook is defined with the request, response and resource class as parameters, in additional to any optional parameters as may be necessary. def hookfunction(req, resp, resource): . . . . . . . . . . Such a function is attached to either an individual responder or the entire resource class by applying one of the following decorators − @falcon.before(hookfunction) @falcon.after(hookfunction) To apply the before hook to the on_post() responder − @falcon.before(hookfunction) def on_post(self, req, resp): . . . . . . To apply an after hook − @falcon.after(hookfunction) def on_get(self, req, resp): . . . . . . To decorate the entire resource class, use the decorator above the declaration of the class − @falcon.after(hookfunction) class SomeResource: def on_get(self, req, resp): . . . . . . def on_post(self, req, resp): . . . . . . In the following example, we have the StudentResource class in which on_get() and on_post() responders have been defined. The on_post() responder is invoked when a POST request sends some data and a new dict object created with it is added in the Students list. The data received needs to be validated before processing. For this purpose, the following function has been defined. It checks whether value of percent parameter is between 0 and 100. Only if the data passes this condition, it is passed to the responder. def checkinput(req, resp, resource,params): student = json.load(req.bounded_stream) if “name” not in student: raise falcon.HTTPBadRequest( title=”Bad request”, description=”Bad input, name must be provided.” ) per=int(student[”percent”]) if per<0 or per>100: raise falcon.HTTPBadRequest( title=”Bad request”, description=”Bad input, invalid percentage” ) req.context.data = student This function is applied as a hook on the on_post() responder of the StudentResource class. import falcon import json from waitress import serve students = [ {“id”: 1, “name”: “Ravi”, “percent”: 75.50}, {“id”: 2, “name”: “Mona”, “percent”: 80.00}, {“id”: 3, “name”: “Mathews”, “percent”: 65.25}, ] class StudentResource: def on_get(self, req, resp): resp.text = json.dumps(students) resp.status = falcon.HTTP_OK resp.content_type = falcon.MEDIA_JSON @falcon.before(checkinput) def on_post(self, req, resp): student = json.load(req.context.data) students.append(student) resp.text = “Student added successfully.” resp.status = falcon.HTTP_OK resp.content_type = falcon.MEDIA_TEXT def on_get_student(self, req, resp, id): resp.text = json.dumps(students[id-1]) resp.status = falcon.HTTP_OK resp.content_type = falcon.MEDIA_JSON app = falcon.App() app.add_route(“/students”, StudentResource()) if __name__ == ”__main__”: serve(app, host=”0.0.0.0”, port=8000) Let us run the Waitress server and initiate the POST request. http POST localhost:8000/students id=4 percent=50 HTTP/1.1 400 Bad Request Content-Length: 76 Content-Type: application/json Date: Tue, 26 Apr 2022 14:49:07 GMT Server: waitress Vary: Accept { “description”: “Bad input, name must be provided.”, “title”: “Bad request” } Since the data doesn”t contain value of name parameter, the exception is raised. In another POST request as shown below, the value of percent parameter fails to meet the required criteria, hence the exception. http POST localhost:8000/students id=4 name=”aaa” percent=500 HTTP/1.1 400 Bad Request Content-Length: 72 Content-Type: application/json Date: Tue, 26 Apr 2022 15:01:20 GMT Server: waitress Vary: Accept { “description”: “Bad input, invalid percentage”, “title”: “Bad request” } Print Page Previous Next Advertisements ”;
Python Falcon – Hello World(WSGI) ”; Previous Next To create a simple Hello World Falcon app, start with importing the library and declaring an instance of App object. import falcon app = falcon.App() Falcon follows REST architectural style. Declare a resource class that includes one or more methods representing the standard HTTP verbs. The following HelloResource class contains on_get() method that is expected to get called when the server receives GET request. The method returns Hello World response. class HelloResource: def on_get(self, req, resp): “””Handles GET requests””” resp.status = falcon.HTTP_200 resp.content_type = falcon.MEDIA_TEXT resp.text = ( ”Hello World” ) To invoke this method, we need to register it to a route or URL. The Falcon application object handles the incoming requests by assigning the handler methods to corresponding URLs by add_rule method. hello = HelloResource() app.add_route(”/hello”, hello) The Falcon application object is nothing but a WSGI application. We can use the built-in WSGI server in the wsgiref module of Python”s standard library. from wsgiref.simple_server import make_server if __name__ == ”__main__”: with make_server(””, 8000, app) as httpd: print(”Serving on port 8000…”) # Serve until process is killed httpd.serve_forever() Example Let us put all these code fragments in hellofalcon.py from wsgiref.simple_server import make_server import falcon app = falcon.App() class HelloResource: def on_get(self, req, resp): “””Handles GET requests””” resp.status = falcon.HTTP_200 resp.content_type = falcon.MEDIA_TEXT resp.text = ( ”Hello World” ) hello = HelloResource() app.add_route(”/hello”, hello) if __name__ == ”__main__”: with make_server(””, 8000, app) as httpd: print(”Serving on port 8000…”) # Serve until process is killed httpd.serve_forever() Run this code from the command prompt. (falconenv) E:falconenv>python hellofalcon.py Serving on port 8000… Output In another terminal, run the Curl command as follows − C:Usersuser>curl localhost:8000/hello Hello World You can also open a browser window and enter the above URL to obtain the “Hello World” response. Print Page Previous Next Advertisements ”;
Python Falcon – Introduction
Python Falcon – Introduction ”; Previous Next Falcon is a Python library for developing mission-critical REST APIs and microservices. It supports both WSGI and ASGI specifications. Falcon framework has been developed by Kurt Griffiths in Jan. 2013. The latest version of Falcon is 3.1.0, released in March 2022. Falcon is a lightweight web development framework. Its minimalist design allows the developer to select the best strategies and 3rd-party packages as required. Falcon – Important Features Falcon is released under the terms of the Apache 2.0 License. Some of the important features of Falcon include − Latest version of Falcon supports ASGI, WSGI, as well as WebSocket. Falcon provides native support for asyncio. Its stable interfaces ensure backwards-compatibility Falcon follows REST architectural style for building APIs. Class based construction of HTTP resources. Highly-optimized, extensible code base. Falcon provides easy access to headers and bodies through request and response classes Middleware components and hooks available for DRY request processing. Idiomatic HTTP error responses and exception handling. Falcon – Design Philosophy Falcon minimizes the instantiation of number of objects so as to avoid the expense of creating the object, and to reduce memory usage. The same instance will be used to serve all requests coming in on that route. Exceptions are properly handled by the resource responders (methods such as on_get(), on_post(), etc.). Falcon doesn”t try very hard to protect responder code from itself. A high-quality Falcon API should fulfil following requirements − Resource responders set response variables to sane values. Your code is well-tested, with high code coverage. Custom error handlers are provided within each responder to anticipate, detect, and handle errors. The Falcon framework is thread-safe. Separate new Request and Response objects are created for each incoming HTTP request. However, a single instance of each resource class attached to a route is shared among all requests. Middleware objects, hooks, and custom error handlers, are also shared. Therefore, your WSGI app as a whole will be thread-safe. Starting with version 3.0, Falcon supports asyncio. Use the falcon.asgi.App class to create an async application, and serve it via an ASGI application server such as Uvicorn. The async version of Falcon supports the ASGI WebSocket protocol. Falcon – Comparison with Other Frameworks There are two major categories of Python web frameworks − full-stack and micro frameworks. Full-stack frameworks come with built-in features and libraries. Django, Turbogears, and Web2Py are full-stack frameworks. In contrast, micro-frameworks are minimalistic, only providing the bare minimum; thus gives developers the freedom to choose official or third-party extensions and only include plugins which they need. Flask, Falcon, Pyramid belong to micro framework category. We compare Falcon framework against different frameworks on the basis of the following parameters − Performance Falcon application is very fast, in comparison with micro frameworks such as Flask and pyramid. The full stack frameworks are generally slow. REST Support Falcon is intended to be a framework of choice for development of REST APIs and microservices. FastAPI also encourages REST development. Flask and Django don”t have built-in REST support. However, it can be enabled using extensions. Templating Falcon app is not supposed to serve template web pages. It is not bundled with any templating library. However, one can use jinja2 or Macho libraries. On the other hand, Flask has a built-in support for jinja2. Django has its own templating library. FastAPI also can handle any template library of choice. Database Support In Falcon database support is not built-in. It is possible to use SQLAlchemy models to interact with relational databases like MyQL, PostgreSQL, SQLite etc. Django on the other hand has its own ORM framework for use out of the box. A Flask application also can interact with databases through Flask extensions. Earlier versions of TurboGears had compatibility with SQLObject ORM library. The newer version is compatible with SQLAlchemy. Flexibility Falcon applications are very flexible. It is ideal for applications that require a high degree of customization and performance tuning. FastAPI and Flask too are flexible to code and doesn”t restrict users to a particular project or code layout. Security Falcon has no built-in support to ensure security. Other frameworks like Django and FastAPI ensure high degree of security. Flask also provides excellent protection against security threats such as CSRF and XSS attacks. Testing Falcon offers built-in testing support using unittest and Pytest. Flask and Django also supports unittest. FastAPI supports unittest and starlette testing features. Print Page Previous Next Advertisements ”;