Core Extensions¶
Microdot is a highly extensible web application framework. The extensions described in this section are maintained as part of the Microdot project and can be obtained from the same source code repository.
Asynchronous Support with Asyncio¶
Compatibility |
CPython & MicroPython
|
Required Microdot source files |
|
Required external dependencies |
CPython: None
MicroPython: uasyncio
|
Examples |
Microdot can be extended to use an asynchronous programming model based on the
asyncio
package. When the Microdot
class is imported from the microdot_asyncio
package, an asynchronous server
is used, and handlers can be defined as coroutines.
The example that follows uses asyncio
coroutines for concurrency:
from microdot_asyncio import Microdot
app = Microdot()
@app.route('/')
async def hello(request):
return 'Hello, world!'
app.run()
Rendering HTML Templates¶
Many web applications use HTML templates for rendering content to clients. Microdot includes extensions to render templates with the utemplate package on CPython and MicroPython, and with Jinja only on CPython.
Using the uTemplate Engine¶
Compatibility |
CPython & MicroPython
|
Required Microdot source files |
|
Required external dependencies |
|
Examples |
The render_template
function is
used to render HTML templates with the uTemplate engine. The first argument is
the template filename, relative to the templates directory, which is
templates by default. Any additional arguments are passed to the template
engine to be used as arguments.
Example:
from microdot_utemplate import render_template
@app.get('/')
def index(req):
return render_template('index.html')
The default location from where templates are loaded is the templates
subdirectory. This location can be changed with the
init_templates
function:
from microdot_utemplate import init_templates
init_templates('my_templates')
Using the Jinja Engine¶
Compatibility |
CPython only
|
Required Microdot source files |
|
Required external dependencies |
|
Examples |
The render_template
function is used
to render HTML templates with the Jinja engine. The first argument is the
template filename, relative to the templates directory, which is templates by
default. Any additional arguments are passed to the template engine to be used
as arguments.
Example:
from microdot_jinja import render_template
@app.get('/')
def index(req):
return render_template('index.html')
The default location from where templates are loaded is the templates
subdirectory. This location can be changed with the
init_templates
function:
from microdot_jinja import init_templates
init_templates('my_templates')
Note
The Jinja extension is not compatible with MicroPython.
Maintaining Secure User Sessions¶
Compatibility |
CPython & MicroPython
|
Required Microdot source files |
|
Required external dependencies |
|
Examples |
The session extension provides a secure way for the application to maintain user sessions. The session is stored as a signed cookie in the client’s browser, in JSON Web Token (JWT) format.
To work with user sessions, the application first must configure the secret key that will be used to sign the session cookies. It is very important that this key is kept secret. An attacker who is in possession of this key can generate valid user session cookies with any contents.
To set the secret key, use the set_session_secret_key
function:
from microdot_session import set_session_secret_key
set_session_secret_key('top-secret!')
To get_session
,
update_session
and
delete_session
functions are used
inside route handlers to retrieve, store and delete session data respectively.
The with_session
decorator is provided
as a convenient way to retrieve the session at the start of a route handler.
Example:
from microdot import Microdot
from microdot_session import set_session_secret_key, with_session, \
update_session, delete_session
app = Microdot()
set_session_secret_key('top-secret')
@app.route('/', methods=['GET', 'POST'])
@with_session
def index(req, session):
username = session.get('username')
if req.method == 'POST':
username = req.form.get('username')
update_session(req, {'username': username})
return redirect('/')
if username is None:
return 'Not logged in'
else:
return 'Logged in as ' + username
@app.post('/logout')
def logout(req):
delete_session(req)
return redirect('/')
Cross-Origin Resource Sharing (CORS)¶
Compatibility |
CPython & MicroPython
|
Required Microdot source files |
|
Required external dependencies |
None
|
Examples |
The CORS extension provides support for Cross-Origin Resource Sharing
(CORS). CORS is a
mechanism that allows web applications running on different origins to access
resources from each other. For example, a web application running on
https://example.com
can access resources from https://api.example.com
.
To enable CORS support, create an instance of the
CORS
class and configure the desired options.
Example:
from microdot import Microdot
from microdot_cors import CORS
app = Microdot()
cors = CORS(app, allowed_origins=['https://example.com'],
allow_credentials=True)
WebSocket Support¶
Compatibility |
CPython & MicroPython
|
Required Microdot source files |
|
Required external dependencies |
None
|
Examples |
The WebSocket extension provides a way for the application to handle WebSocket
requests. The websocket
decorator
is used to mark a route handler as a WebSocket handler. The handler receives
a WebSocket object as a second argument. The WebSocket object provides
send()
and receive()
methods to send and receive messages respectively.
Example:
@app.route('/echo')
@with_websocket
def echo(request, ws):
while True:
message = ws.receive()
ws.send(message)
Note
An unsupported microdot_websocket_alt.py module, with the same interface, is also provided. This module uses the native WebSocket support in MicroPython that powers the WebREPL, and may provide slightly better performance for MicroPython low-end boards. This module is not compatible with CPython.
Asynchronous WebSocket¶
Compatibility |
CPython & MicroPython
|
Required Microdot source files |
|
Required external dependencies |
CPython: None
MicroPython: uasyncio
|
Examples |
This extension has the same interface as the synchronous WebSocket extension,
but the receive()
and send()
methods are asynchronous.
Note
An unsupported microdot_asgi_websocket.py module, with the same interface, is also provided. This module must be used instead of microdot_asyncio_websocket.py when the ASGI support is used. The echo_asgi.py example shows how to use this module.
HTTPS Support¶
Compatibility |
CPython & MicroPython
|
Required Microdot source files |
|
Examples |
The run()
function accepts an optional ssl
argument, through which an
initialized SSLContext
object can be passed. MicroPython does not currently
have a SSLContext
implementation, so the microdot_ssl
module provides
a basic implementation that can be used to create a context.
Example:
from microdot import Microdot
from microdot_ssl import create_ssl_context
app = Microdot()
@app.route('/')
def index(req):
return 'Hello, World!'
sslctx = create_ssl_context('cert.der', 'key.der')
app.run(port=4443, debug=True, ssl=sslctx)
Note
The microdot_ssl
module is only needed for MicroPython. When used under
CPython, this module creates a standard SSLContext
instance.
Note
The uasyncio
library for MicroPython does not currently support TLS, so
this feature is not available for asynchronous applications on that
platform. The asyncio
library for CPython is fully supported.
Test Client¶
Compatibility |
CPython & MicroPython
|
Required Microdot source files |
|
Required external dependencies |
None
|
The Microdot Test Client is a utility class that can be used during testing to send requests into the application.
Example:
from microdot import Microdot
from microdot_test_client import TestClient
app = Microdot()
@app.route('/')
def index(req):
return 'Hello, World!'
def test_app():
client = TestClient(app)
response = client.get('/')
assert response.text == 'Hello, World!'
See the documentation for the TestClient
class for more details.
Asynchronous Test Client¶
Compatibility |
CPython & MicroPython
|
Required Microdot source files |
|
Required external dependencies |
None
|
Similar to the TestClient
class
above, but for asynchronous applications.
Example usage:
from microdot_asyncio_test_client import TestClient
async def test_app():
client = TestClient(app)
response = await client.get('/')
assert response.text == 'Hello, World!'
See the reference documentation
for details.
Deploying on a Production Web Server¶
The Microdot
class creates its own simple web server. This is enough for an
application deployed with MicroPython, but when using CPython it may be useful
to use a separate, battle-tested web server. To address this need, Microdot
provides extensions that implement the WSGI and ASGI protocols.
Using a WSGI Web Server¶
Compatibility |
CPython only
|
Required Microdot source files |
|
Required external dependencies |
A WSGI web server, such as Gunicorn.
|
Examples |
The microdot_wsgi
module provides an extended Microdot
class that
implements the WSGI protocol and can be used with a compliant WSGI web server
such as Gunicorn or
uWSGI.
To use a WSGI web server, the application must import the
Microdot
class from the microdot_wsgi
module:
from microdot_wsgi import Microdot
app = Microdot()
@app.route('/')
def index(req):
return 'Hello, World!'
The app
application instance created from this class is a WSGI application
that can be used with any complaint WSGI web server. If the above application
is stored in a file called test.py, then the following command runs the
web application using the Gunicorn web server:
gunicorn test:app
When using this WSGI adapter, the environ
dictionary provided by the web
server is available to request handlers as request.environ
.
Using an ASGI Web Server¶
Compatibility |
CPython only
|
Required Microdot source files |
|
Required external dependencies |
An ASGI web server, such as Uvicorn.
|
Examples |
The microdot_asgi
module provides an extended Microdot
class that
implements the ASGI protocol and can be used with a compliant ASGI server such
as Uvicorn.
To use an ASGI web server, the application must import the
Microdot
class from the microdot_asgi
module:
from microdot_asgi import Microdot
app = Microdot()
@app.route('/')
async def index(req):
return 'Hello, World!'
The app
application instance created from this class is an ASGI application
that can be used with any complaint ASGI web server. If the above application
is stored in a file called test.py, then the following command runs the
web application using the Uvicorn web server:
uvicorn test:app
When using this ASGI adapter, the scope
dictionary provided by the web
server is available to request handlers as request.asgi_scope
.