A simple API application using Python & Flask

How to create a simple API application with minimal learning and clean code for beginners.

Most of the times developers create a simple frontend application that needs a couple of API's but to do that they might rely on the backend team or mock API tools like Postman or create their own.
So let us write a tiny application which covers this requirement.

Why flask?

We do have multiple choices to make a minimal API setup,

  1. NodeJS with Express
  2. Python with Flask or Django
  3. C# with .Net Core or
  4. Ruby on Rails.

We can use any of the above but I am an old friend of Ruby on Rails so chose Python with Flask for a bare minimum code. ( Actually less than 50 lines πŸ‘€)

This article doesn't intended to be production-ready code, but to make quick APIs with a database for beginners.

What we are going to cover

  1. System setup
  2. Project setup
  3. Implementation
  4. Testing the API's

Okey, lets start to code πŸ”₯

1. System setup - prerequisites

Mac OS and Python 3.X, VS Code, Postgresql and Git.

If you are using Ubuntu then the flow will be same but need to find the equivalent commands in installation.

2. Project setup

2.1 Install / Verify the python

brew install python

Check the installation

python --version

2.2 Install virtualenv

To manage the python and dependencies across the system at least on the dev environment we must use the virtualenv

pip install virtualenv

2.3 Project initiation

Create a folder for the project

mkdir flash-sample
cd flask-sample
ls
__pycache__ env

2.4. virtualenv initialization

python -m venv env
source env/bin/activate

2.5 install SQL ORM

In this article, we will use sqlalchemy with PostgreSQL

pip install flask_sqlalchemy
pip install psycopg2

2.6 Create project requirements

python -m pip freeze requirements.txt

click==8.0.1
Flask==2.0.1
Flask-SQLAlchemy==2.5.1
greenlet==1.1.1
itsdangerous==2.0.1
Jinja2==3.0.1
MarkupSafe==2.0.1
psycopg2==2.9.1
SQLAlchemy==1.4.25
Werkzeug==2.0.1

2.7 Version control

We will use the git as version control and let's initialize

git init.
Initialized empty Git repository in /PROJECT_FOLDER/.git/

git s
  On branch master
  No commits yet
  Untracked files:
  (use "git add file..." to include in what will be committed)

  env/
  requirements.txt
  nothing added to commit but untracked files present (use "git add" to track)

Create gitignore file to remove the unwanted files tobe tracked and pushed to the repository

touch .gitignore

Add the standard gitignore file from here and make sure you add the virtualenv folder name in the gitignore.

git add.
git commit -m "Initial commit"

So the base code is ready now.

3. Implementation

As mentioned earlier in this article we are going to add two rest API endpoints to save and retrieve data using Postgresql.

Create the python file to handle our API's

touch app.py

3.1 Import section

Import required modules

from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy
from flask import jsonify

3.2 setup database configurations

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql:///hands_contact'
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)

If PostgreSQL running in a remote location then we can add the URL along with user name and password like

'postgresql://usernamr:password@server/database_name'

3.3 Define the model

Let's create a user model

class SampleUser(db.Model):
  id = db.Column(db.Integer, primary_key=True)
  first_name = db.Column(db.String(80), nullable=False)
  last_name = db.Column(db.String(120), nullable=False)

  def __init__(self, first_name, last_name):
    self.first_name = first_name
    self.last_name = last_name

3.4 Invoke the app

Let's create a module to run the application and set the database with models

if __name__ == '__main__':
  db.create_all()
  app.run()

3.5 Create the users

def creation():

  content=request.get_json(silent=True)
  try:
    db.session.add(SampleUser(content["first_name"],
    content["last_name"]))
    db.session.commit()
    return'Ok', 200
  exceptExceptionase:
    return'Invalid request', 400

The request will be converted into JSON and required parameters are loaded from there to create the user.

Finally, mound this method into the route using

@app.route("/create_users", methods=['POST'])

3.6 List users

Similar to the creation let's create a get users route as GET method.

@app.route('/users', methods=['GET'])
def home():<br /> data = []
for user in SampleUser.query.all():
  data.append(
    { "id": user.id,
      "first_name": user.first_name,
      "last_name": user.last_name
    })
  return jsonify(total_users_count=len(data), data=data, status=200)

To be basic used the jsonify but to be more proper we can use the marshmallow serializer.

Import

from flask_marshmallow import Marshmallow

Initialize

ma = Marshmallow(app)

Setup a schema that defined what are the columns needs to be constructed in JSON

class SampleUserSchema(ma.Schema):
  class Meta:
    fields = ("id", "first_name")

sample_user_schema = SampleUserSchema()
sample_user_schema = SampleUserSchema(many=True)

Now update the get users method.

@app.route('/users', methods=['GET'])
def listing():
  all_notes = SampleUser.query.all()
  return jsonify(sample_user_schema.dump(all_notes)), 200

that's it! so simple isn't it? The complete code for convenience below

from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
from flask import jsonify

# Database ORM Configs
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql:///hands_contact'
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)
ma = Marshmallow(app)

# User model for contact us
class SampleUser(db.Model):
  id = db.Column(db.Integer, primary_key=True)
  first_name = db.Column(db.String(80), nullable=False)
  last_name = db.Column(db.String(120), nullable=False)
  def __init__(self, first_name, last_name):
    self.first_name = first_name
    self.last_name = last_name

# JSON response serializer
class SampleUserSchema(ma.Schema):
  class Meta:
    fields = ("id", "first_name")
sample_user_schema = SampleUserSchema()
sample_user_schema = SampleUserSchema(many=True)

# Simple Dashboard
@app.route('/users', methods=['GET'])
def listing():
  all_notes = SampleUser.query.all()
  return jsonify(sample_user_schema.dump(all_notes)), 200

# Contact us POST API
@app.route("/create_users", methods=['POST'])
def creation():
  content = request.get_json(silent=True)
  try:
    db.session.add(SampleUser(content["first_name"], content["last_name"]))
    db.session.commit()
    return 'Ok', 200
  except Exception as e:
    return 'Invalid request', 400

# Invoke the application
if __name__ == '__main__':
    db.create_all()
    app.run()

4.Let's test now

Run the application from terminal

flask run

The default port for flask application is 5000 and applictaion will be listening to http://127.0.0.1:5000.

Create users using the POST endpoint /create_users with the payload

curl -X POST -d '{ "first_name": "Badsha", "last_name": "Manik" }' http://127.0.0.1:5000/create_users -H 'Content-Type: application/json' -H 'Accept: application/json'

Ok

List users using GET endpoint /users

curl http://127.0.0.1:5000/users

[{"first_name":"Vijay","id":1},{"first_name":"" 1","id":2},{"first_name":"Ajith","id":3}]

So as a starting point this single file serves the purpose but for production, as per required patterns you can split the configs, serializer, models and API methods and import wherever required.

22