Lab 7 - Flask


Create a basic RESTful web application backend using Flask. Consume the API endpoints using cURL and httpie.

Flask

Navigate to a new folder and initialize a new Python virtual environment.

mkdir cmput404lab7
cd cmput404lab7
virtualenv venv --python=python3
source venv/bin/activate

Install Flask.

pip install Flask

Create a new Python file named hello.py and edit its contents so it looks like this:

#!/usr/bin/env python3

from flask import Flask
app = Flask(__name__)


@app.route("/")
def hello():
    return "Hello, world!"


if __name__ == "__main__":
    app.run(debug=True)

Make the file executable and run the application. Navigate to the page in your browser.

chmod +x hello.py
./hello.py
# or
python3 hello.py

# In a new terminal
curl localhost:5000 # the port may be different on your machine

Modify the hello.py file to serve a RESTful api for managing a TODO list. First, install flask_restful.

pip install flask_restful

Update hello.py so it looks like the following.

#!/usr/bin/env python3

from flask import Flask
from flask_restful import Resource, Api

app = Flask(__name__)
api = Api(app)


class HelloWorld(Resource):
    def get(self):
        return {'hello': 'world'}


api.add_resource(HelloWorld, "/")


if __name__ == "__main__":
    app.run(debug=True)

Run the server and see what it returns in your browser, or using cURL.

curl localhost:5000

Change the contents of hello.py to the following:

#!/usr/bin/env python3

from flask import Flask
from flask_restful import reqparse, abort, Api, Resource

app = Flask(__name__)
api = Api(app)

parser = reqparse.RequestParser()
parser.add_argument("task")

TODOs = {
    1: {"task": "build an API"},
    2: {"task": "?????"},
    3: {"task": "profit"},
}


def abort_if_todo_not_found(todo_id):
    if todo_id not in TODOs:
        abort(404, message="TODO {} does not exist".format(todo_id))


def add_todo(todo_id):
    args = parser.parse_args()
    todo = {"task": args["task"]}
    TODOs[todo_id] = todo
    return todo


class Todo(Resource):
    """
    Shows a single TODO item and lets you delete a TODO item.
    """

    def get(self, todo_id):
        abort_if_todo_not_found(todo_id)
        return TODOs[todo_id]

    def delete(self, todo_id):
        abort_if_todo_not_found(todo_id)
        del TODOs[todo_id]
        return "", 204

    def put(self, todo_id):
        return add_todo(todo_id), 201


class TodoList(Resource):
    """
    Shows a list of all TODOs and lets you POST to add new tasks.
    """

    def get(self):
        return TODOs

    def post(self):
        todo_id = max(TODOs.keys()) + 1
        return add_todo(todo_id), 201


api.add_resource(Todo, "/todos/<int:todo_id>")
api.add_resource(TodoList, "/todos")

if __name__ == "__main__":
    app.run(debug=True)

What does the browser show you when you navigate to /todos and /todos/1?

Try running the following cURL commands.

curl localhost:5000/todos
curl localhost:5000/todos/3
curl -v -X DELETE localhost:5000/todos/2
curl -v -X POST localhost:5000/todos -d "task=make sure to do lab 7 questions"
curl -v -X PUT localhost:5000/todos/3 -d "task=profit more"

Httpie

In addition to using cURL, httpie is specifically designed for interacting with RESTful JSON APIs. It has colour output and automatically pretty prints JSON for you.

pip install httpie
http localhost:5000/todos
http :5000/todos
http HEAD :5000/todos
http POST :5000/todos task="Try httpie!"

Question 1: How are Flask and Django different? What does Django provide for you that Flask does not?

Question 2: What does REST stand for? When I say something is RESTful, what does that mean?

Question 3: What does CRUD stand for? For each letter in CRUD, give the associated HTTP method.

Question 4: What do HTTP 1XX Status Codes mean? HTTP 2xx? HTTP 3xx? HTTP 4xx? HTTP 5xx?

Question 5: What is an XSS attack? Provide one way a site can be vulneratble to an XSS attack.

Question 6: What does CORS stand for? What situation in web application development will you need to implement CORS?


Optional: Deploy your Flask application to Heroku.