Asynchronous operations

Asynchronous operations are, in my opinion, an advanced topic of Flask. Luckily, Miguel Grinberg (https://blog.miguelgrinberg.com/), whose Flask work I am a big fan of, provides many posts and examples on his blog and GitHub. For asynchronous operations, the example code in chapter9_8.py referenced Miguel's GitHub code on the Raspberry Pi file (https://github.com/miguelgrinberg/oreilly-flask-apis-video/blob/master/camera/camera.py) for the background decorator. We start by importing a few more modules:

from flask import Flask, url_for, jsonify, request,
make_response, copy_current_request_context
...
import uuid
import functools
from threading import Thread

The background decorator takes in a function and runs it as a background task using Thread and UUID for the task ID. It returns the status code 202 accepted and the location of the new resources for the requester to check. We will make a new URL for status checking:

@app.route('/status/<id>', methods=['GET'])
def get_task_status(id):
global background_tasks
rv = background_tasks.get(id)
if rv is None:
return not_found(None)

if isinstance(rv, Thread):
return jsonify({}), 202, {'Location': url_for('get_task_status', id=id)}

if app.config['AUTO_DELETE_BG_TASKS']:
del background_tasks[id]
return rv

Once we retrieve the resource, it is deleted. This was done via setting app.config['AUTO_DELETE_BG_TASKS'] to true at the top of the app. We will add this decorator to our version endpoints without changing the other part of the code because all of the complexity is hidden in the decorator (how cool is that!):

@app.route('/devices/<int:id>/version', methods=['GET'])
@background
def get_device_version(id):
device = Device.query.get_or_404(id)
...

@app.route('/devices/<device_role>/version', methods=['GET'])
@background
def get_role_version(device_role):
device_id_list = [device.id for device in Device.query.all() if device.role == device_role]
...

The end result is a two-part process. We will perform the GET request for the endpoint and receive the location header:

$ http GET http://172.16.1.173:5000/devices/spine/version
HTTP/1.0 202 ACCEPTED
Content-Length: 2
Content-Type: application/json
Date: <skip>
Location: http://172.16.1.173:5000/status/d02c3f58f4014e96a5dca075e1bb65d4
Server: Werkzeug/0.9.6 Python/3.5.2

{}

We can then make a second request to the location to retrieve the result:

$ http GET http://172.16.1.173:5000/status/d02c3f58f4014e96a5dca075e1bb65d4
HTTP/1.0 200 OK
Content-Length: 370
Content-Type: application/json
Date: <skip>
Server: Werkzeug/0.9.6 Python/3.5.2

{
"iosv-1": "('iosv-1', b'show version | i V\r\nCisco IOS Software, IOSv Software (VIOS-ADVENTERPRISEK9-M), Version 15.6(2)T, RELEASE SOFTWARE (fc2)\r\n')",
"iosv-2": "('iosv-2', b'show version | i V\r\nCisco IOS Software, IOSv Software (VIOS-ADVENTERPRISEK9-M), Version 15.6(2)T, RELEASE SOFTWARE (fc2)\r\nProcessor board ID 9T7CB2J2V6F0DLWK7V48E\r\n')"
}

To verify that the status code 202 is returned when the resource is not ready, we will use the following script to immediately make a request to the new resource:

import requests, time

server = 'http://172.16.1.173:5000'
endpoint = '/devices/1/version'

# First request to get the new resource
r = requests.get(server+endpoint)
resource = r.headers['location']
print("Status: {} Resource: {}".format(r.status_code, resource))

# Second request to get the resource status
r = requests.get(resource)
print("Immediate Status Query to Resource: " + str(r.status_code))

print("Sleep for 2 seconds")
time.sleep(2)
# Third request to get the resource status
r = requests.get(resource)
print("Status after 2 seconds: " + str(r.status_code))

As you can see in the result, the status code is returned while the resource is still being run in the background as 202:

$ python chapter9_request_1.py
Status: 202 Resource: http://172.16.1.173:5000/status/1de21f5235c94236a38abd5606680b92
Immediate Status Query to Resource: 202
Sleep for 2 seconds
Status after 2 seconds: 200

Our APIs are coming along nicely. Because our network resource is valuable to us, we should secure API access to only authorized personnel. We will add basic security measures to our API in the next section.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.75.217