Build RESTful APIs using Python / Flask

dev0928

dev0928

Posted on July 30, 2020

Build RESTful APIs using Python / Flask

Python / Flask framework combination is one of the popular choices for building back-end APIs for a web application. Building an application’s back-end this way gives several options for coming up with a front-end using different technology stack.

In this article, let’s walk through the steps involved in building a simple API for maintaining Quotes using the Flask framework with SQLite database as its datastore.

Project Setup

Create a project folder - mkdir quotes-api
Setup and activate virtual environment - Virtual Environment Setup
Install below packages in project’s virtual environment:

 pip install flask
 pip install flask-sqlalchemy
 pip install flask-marshmallow
Enter fullscreen mode Exit fullscreen mode

Application Setup

Create a file called app.py in the project folder and add necessary imports, application setup code along with Marshmallow library setup like shown below:

from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import Column, Integer, String
from flask_marshmallow import Marshmallow
import os


#Application and database setup
app = Flask(__name__)
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'quotes.db')

db = SQLAlchemy(app)
# Marshmallow library is used for effective object serialization
ma = Marshmallow(app)
Enter fullscreen mode Exit fullscreen mode

Database Setup

Let’s add below code to the app.py file so we could create a quotes database and seed data through the flask commands.

#Database creation flask commands
@app.cli.command('db_create')
def db_create():
    db.create_all()
    print('Database created!')


@app.cli.command('db_drop')
def db_drop():
    db.drop_all()
    print('Database dropped!')


@app.cli.command('db_seed')
def db_seed():
    quote1 = Quote(quote_desc='It always seem impossible until it is done.',
                     quote_type='Motivation',
                     author='Nelson Mandela')

    quote2 = Quote(quote_desc='With the new day comes new strength and new thoughts.',
                         quote_type='Motivation',
                         author='Eleanor Roosevelt')

    quote3 = Quote(quote_desc='The secret of getting ahead is getting started.',
                     quote_type='Motivation',
                     author='Mark Twain')

    quote4 = Quote(quote_desc='With self-discipline most anything is possible.',
                     quote_type='Inspiration',
                     author='Theodore Roosevelt')

    quote5 = Quote(quote_desc='It is during our darkest moments that we must focus to see the light.',
                     quote_type='Inspiration',
                     author='Aristotle')


    db.session.add(quote1)
    db.session.add(quote2)
    db.session.add(quote3)
    db.session.add(quote4)
    db.session.add(quote5)
    db.session.commit()
    print('Database seeded!')


# database model
class Quote(db.Model):
    __tablename__ = 'quotes'
    quote_id = Column(Integer, primary_key = True)
    quote_desc = Column(String)
    quote_type = Column(String)
    author = Column(String)


# Quote model added to the Marshmallow library for JSON serialization
class QuoteSchema(ma.Schema):
    class Meta:
        fields = ('quote_id', 'quote_desc', 'quote_type', 'author')


quote_schema = QuoteSchema()
quotes_schema = QuoteSchema(many=True)

Enter fullscreen mode Exit fullscreen mode

Execute below code in project’s virtual environment to create and seed the quotes data:

flask db_create
flask db_seed 
Enter fullscreen mode Exit fullscreen mode

CRUD Operations

Now that all of the setup part is complete, below methods added to the app.py file help perform the actual CRUD (Create, Read, Update and Delete) operations. Note the appropriate use of HTTP Methods and status codes to signify success or failure of a particular API endpoint.

Read Endpoint

@app.route('/quotes', methods=['GET'])
def quotes():
    quotes_list = Quote.query.all()
    result = quotes_schema.dump(quotes_list)
    return jsonify(result)


@app.route('/quote_details/<int:quote_id>', methods=['GET'])   
def quote_details(quote_id: int):
    quote = Quote.query.filter_by(quote_id=quote_id).first()
    if quote:
        result = quote_schema.dump(quote)
        return jsonify(result)
    else:
        return jsonify(message="That quote does not exist."), 404
Enter fullscreen mode Exit fullscreen mode

Add Endpoint

@app.route('/add_quote', methods=['POST'])   
def add_quote():
    quote_desc = request.form['quote_desc']
    test = Quote.query.filter_by(quote_desc=quote_desc).first()
    if test:
        return jsonify(message="There is already a quote by that description."), 409
    else:
        quote_type= request.form['quote_type']
        author= request.form['author']
        quote =  Quote(quote_desc=quote_desc,
                         quote_type= quote_type,
                         author= author)  
        db.session.add(quote)
        db.session.commit()                 
        return jsonify(message="Quote added successfully!"), 201
Enter fullscreen mode Exit fullscreen mode

Update Endpoint

@app.route('/update_quote/<int:quote_id>', methods=['PUT'])   
def update_quote(quote_id : int):
    quote = Quote.query.filter_by(quote_id=quote_id).first()
    if quote:
        quote.quote_desc = request.form['quote_desc']
        quote.quote_type = request.form['quote_type']
        quote.author= request.form['author']
        db.session.commit()                 
        return jsonify(message="Quote successfully updated!")
    else:
        return jsonify(message="That quote does not exist"), 404
Enter fullscreen mode Exit fullscreen mode

Delete Endpoint

@app.route('/remove_quote/<int:quote_id>', methods=['DELETE'])   
def remove_quote(quote_id : int):
    quote = Quote.query.filter_by(quote_id=quote_id).first()
    if quote:
        db.session.delete(quote)
        db.session.commit()                 
        return jsonify(message="Quote successfully deleted!"), 200
    else:
        return jsonify(message="That quote does not exist"), 404
Enter fullscreen mode Exit fullscreen mode

How to test the API?

Add below code to the end of the app.py file, so we could start application using python app.py. API endpoints could be tested using Postman application.

if __name__ == '__main__':
    app.run()
Enter fullscreen mode Exit fullscreen mode

Next Steps:

  • Extend API to provide more endpoints
  • Secure API using JWT
  • Build a front-end using react.js, vue.js or any other suitable technology
  • Deploy built API by installing WSGI complaint server on any of the cloud platforms

Further Learning:

💖 💪 🙅 🚩
dev0928
dev0928

Posted on July 30, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related