Flask Framework: WSGI Explained
WSGI is the bridge between web server and the actual application code. This article will explore about how Flask framework utilises WSGI for REST APIs.
Topics to be covered:
- What is WSGI?
- WSGI in action without Flask Framework
- Python inbuilt __call__ function
- WSGI in Flask
What is WSGI?
WSGI is the bridge between web server and the actual application code. Its a protocol or convention that helps application to work together with web server. When we hit an API, the request comes to web server and from web server the request is passed on to the actual code to be processed accordingly. This passing of request from web server to application code can be done through WSGI.
WSGI in action without Flask Framework
A small WSGI application can be written as follows in Python.
import os
from werkzeug.wrappers import Request, Response
from werkzeug.middleware.shared_data import SharedDataMiddlewareclass FrameWork(object):
def __init__(self, name):
self.name = name def dispatch_request(self, request):
return Response(f'Hello {self.name}!') def wsgi_app(self, environ, start_response):
request = Request(environ)
response = self.dispatch_request(request)
return response(environ, start_response) def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)def create_app(name="World", with_static=True):
a = FrameWork("World")
if with_static:
a.wsgi_app = SharedDataMiddleware(a.wsgi_app, {
'/static': os.path.join(os.path.dirname(__file__), 'static')
})
return aif __name__ == '__main__':
from werkzeug.serving import run_simple
a = create_app() // This creates an object of FrameWork class
run_simple('127.0.0.1', 5000, a, use_debugger=True, use_reloader=True)
Here we are using werkzeug Python library for WSGI. Lets save this file as wsgi.py
Next we can run this code just as any Python code. In terminal, we can just do
python wsgi.py , this will get our development server up and running on 127.0.0.1:5000
We can simply hit the same URL from Postman.
To understand the above piece of code we need to first understand how __call__ function works.
Python inbuilt __call__ function
Lets take the following example.
class FrameWork(object):
def __init__(self, name):
self.name = name def __call__(self, a, b):
return f"{a} {b} {self.name}"def create_app(name="World"):
a = FrameWork(name)
return aif __name__ == '__main__':
a = create_app() // This creates an object of FrameWork class
print(a("Hello", "to"))
In the above example if we look at the last line, FrameWork’s object is called as a function. This is what __call__ function does. It enables the object of the class to be called as functions. In the above example when we say a(“Hello”, “to”), it translates to a.__call__(“Hello”, “to”)
The output of the above code will be “Hello to World”.
Now we can go back to our previous wsgi.py example and have a look at the following lines.
if __name__ == '__main__':
from werkzeug.serving import run_simple
a = create_app() // This creates an object of FrameWork class
run_simple('127.0.0.1', 5000, a, use_debugger=True, use_reloader=True)
If we look at the parameters passed to run_simple function, we will see that the third parameter is actually the object of Framework class. Every time we hit the API, this object will be called as a function and the __call__ method on FrameWork class will trigger.
def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)
Here “environ” holds the data of incoming request and “start_response” is a function which indicates the start of the response. This function calls the wsgi_app function defined in Framework class.
def wsgi_app(self, environ, start_response):
request = Request(environ)
response = self.dispatch_request(request) // Creates Response object
return response(environ, start_response)
The above function now uses the environ and start_response and creates the actual Request and Response objects.
request = Request Object
response = Response Object
The return statement of this function also calls the response object, which means it internally calls the __call__ method defined inside Response class.
This function returns the response back to client.
To learn more about WSGI through werkzeug Python library, refer to werkzeug documentation.
Now lets see how this all connects with Flask framework.
WSGI in Flask
Lets consider a very simple Flask app.
from flask import Flaskapp = Flask(__name__)@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
Here if we take a look at
app = Flask(__name__)
“app” is an object of Flask class. Flask internally uses werkzeug library for WSGI.
Flask class has implemented __call__ functions similar to our example.
Flask class implementation of __call__ function is:
def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)
This method will be called if Flask object is called as a function, in this case “app”. Flask development server is run by calling run_simple function as we did in our example.
run_simple(host, port, self, **options)
Here third parameter is an object of Flask class.
Every time we hit the API, this object will be called as a function and the __call__ method on Flask class will trigger.
So this is how Flask uses WSGI which connects web server with actual Flask application.
Thanks for Reading.
Any questions/suggestions regarding this topic are welcome in comments. :)