Python API Development Part1

In previous blogs we saw about the basic syntax of python and after that we setup our first app on flask.

In this post to understand flask better, we will implement a simple todo app.

These are the routes that we will setp

GET /todo    (return all todos)
POST /todo (add new todo)
PUT /todo/3 (update an existing todo with id 3)
DELETE /todo/3 (delete todo with id 3)

At this point it’s also important to understand what is rest api and what do these get, post, put, delete means if you are not already aware of it.

https://restfulapi.net/

https://restfulapi.net/http-methods/

Now let’s get started with coding

GET Route

This is how the code looks and we will go through it step by step


from flask import Flask , jsonify
app = Flask(__name__)

tasks = [
{
'id': 1,
'title': 'Buy groceries',
'description': 'Milk, Cheese, Pizza, Fruit, Tylenol',
'done': False
},
{
'id': 2,
'title': 'Learn Python',
'description': 'Need to find a good Python tutorial on the web',
'done': False
}
]

@app.route('/todo', methods=["GET"])
def todo():
return jsonify(tasks)

To explain things tasks = [] is array which we will use our data structure to store todos. You can learn more about lists and dict here

https://www.learnpython.org/en/Lists

https://www.learnpython.org/en/Dictionaries

http://flask.pocoo.org/docs/1.0/quickstart/#routing

you can find many more articles online to understand more about Lists, Dictionaries

Next, in all our routes we would we need to return a json response not text hence the library “jsonfiy” is used which converts array, dict to json.

Now if we run this application and open http://127.0.0.1:5000/todo on the browser you will see the json output.

Flask Debug Mode

At this point we should also look at flask debug mode. When we develop our flask application, we have to keep stopping and starting the flask app as we develop it. Rather it should automatically restart and take the latest code. To do this do

$ export FLASK_DEBUG=1
$ python -m flask run

Serving Flask app "hello.py" (lazy loading)
Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
Debug mode: on
Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Restarting with stat
Debugger is active!
Debugger PIN: 187-186-371

Now as you keep writing code, the flask app will keep restarting and even show errors.

POST Route

Let’s do this step by step. First we will simply define a route



@app.route('/todo', methods=["GET"])
def todo():
return jsonify(tasks)


@app.route('/todo', methods=["POST"])
def add_todo():
return ""


To test this route, we need to use a tool called postman

Since this is a POST route, we cannot just simply open this in browser, we need specific tool to fire such api. So install postman and from there we can do this easily.

Its important to note that spacing, indentation and line breaks are very important to python syntax or else python gives syntax error. Easiest way to is to avoid this is use VSCode formatting feature.

You need to import jsonify or any new packages we use. see the entire code base at the end of the blog

Now, if we open postman and test this route we should get status 200 which means this works.

POST 200 Status via Postman

Next, we need to add a new todo but first we need to add some validations and pass the todo data from postman.

Now our code looks like this


@app.route('/todo', methods=["POST"])
def add_todo():
if not request.json:
abort(500)

id = request.json.get("id", None)
title = request.json.get("title", None)
desc = request.json.get("description", "")

if id is None or title is None:
return jsonify(message="Invalid Request"), 500

return ""

In the code, we are first check if request has json else we throw error 500 using abort

Next we fetch and validate each parameter from request json and throw error if important parameter are missing and set status as 500 when we return the json.

Finally we need to append to the tasks array so code goes like this now


@app.route('/todo', methods=["POST"])
def add_todo():
if not request.json:
abort(500)

id = request.json.get("id", None)
title = request.json.get("title", None)
desc = request.json.get("description", "")

if id is None or title is None:
return jsonify(message="Invalid Request"), 500

tasks.append({
"id" : id,
"title" : title,
"description" : desc,
"done" : False
})
return jsonify(len(tasks))

PUT Route

Now we will see we can update the tasks array

so first lets setup the route


@app.route("/todo/<int:id>", methods=['PUT'])
def update_todo(id):
return ""

and test it on postman. Next add the standard validations we added before. Now we need to update the existing array, and for that we need to use python list comprehension. This is a very useful feature in python if you understand it well and can be used as replacement of map() and filter() from javascript.

Now our update code looks like this


def update(task, task_id, data):
if task["id"] == task_id:
if 'title' in data:
task["title"] = data['title']
if 'description' in data:
task["description"] = data["description"]
return task


@app.route("/todo/<int:id>", methods=['PUT'])
def update_todo(id):

if not request.json:
abort(500)


todo_id = request.json.get("id", None)
title = request.json.get("title", None)
desc = request.json.get("description", "")

if todo_id is None or title is None:
return jsonify(message="Invalid Request") , 500

global tasks
tasks = [update(task, id, request.json) for task in tasks]

return jsonify(tasks)

Go through the above code in detail, its important to understand python list comprehension and you can find many blogs about it online as well.

DELETE Route

Now, finally in we are left with delete todo for which we will again use list comprehension


@app.route("/todo/<int:id>", methods=["DELETE"])
def delete_todo(id):

global tasks
tasks = [task for task in tasks if task["id"] != id]

return jsonify(tasks)

Delete Route

This finishes our basic todo app. At this stage, it’s important to sink your head in what you read about and try different things to get a good grasp of it.

Here is the entire final code for reference


from flask import Flask, jsonify, abort, request
app = Flask(__name__)

tasks = [
{
'id': 1,
'title': 'Buy groceries',
'description': 'Milk, Cheese, Pizza, Fruit, Tylenol',
'done': False
},
{
'id': 2,
'title': 'Learn Python',
'description': 'Need to find a good Python tutorial on the web',
'done': False
}
]


@app.route('/todo', methods=["GET"])
def todo():
return jsonify(tasks)


@app.route('/todo', methods=["POST"])
def add_todo():
if not request.json:
abort(500)

id = request.json.get("id", None)
title = request.json.get("title", None)
desc = request.json.get("description", "")

if id is None or title is None:
return jsonify(message="Invalid Request") , 500

tasks.append({
"id": id,
"title": title,
"description": desc,
"done": False
})
return jsonify(len(tasks))


def update(task, task_id, data):
if task["id"] == task_id:
if 'title' in data:
task["title"] = data['title']
if 'description' in data:
task["description"] = data["description"]
return task


@app.route("/todo/<int:id>", methods=['PUT'])
def update_todo(id):

if not request.json:
abort(500)

todo_id = request.json.get("id", None)
title = request.json.get("title", None)
desc = request.json.get("description", "")

if todo_id is None or title is None:
return jsonify(message="Invalid Request") , 500

global tasks
tasks = [update(task, id, request.json) for task in tasks]

return jsonify(tasks)


@app.route("/todo/<int:id>", methods=["DELETE"])
def delete_todo(id):

global tasks
tasks = [task for task in tasks if task["id"] != id]

return jsonify(tasks)

excellence-social-linkdin
excellence-social-facebook
excellence-social-instagram
excellence-social-skype