API Starter Kit

Python Flask API — Starter Kit and Project Layout

Before we start with code…

Let’s first discuss the project dependencies, why each of them is necessary, and how it can benefit our project.

  • flasgger: It’s a module that helps us integrate swagger docs to a flask API.
  • flask-marshmallow: Object serializer, ideal for parsing and dumping JSON data in and out of our API.
  • apispec: Required for the integration between marshmallow and flasgger.

Project Layout

We will start discussing how the project layout looks like by taking a look into the folder structure:

project/
api/
model/
__init__.py
welcome.py
route/
home.py
schema/
__init__.py
welcome.py

test/
route/
__init__.py
test_home.py
__init.py

.gitignore
app.py
Pipfile
Pipfile.lock
  • The routes are the paths to our application (e.g. /api/home or /api/users) and it's where we will define the route logic, data retrieval, insertion, updates, etc.
  • The schemas are the views (serializers) for our data structures. We should have at least one schema per model. The schemas will have it's own definition as we will see later.

Route example

from http import HTTPStatus
from flask import Blueprint
from flasgger import swag_from
from api.model.welcome import WelcomeModel
from api.schema.welcome import WelcomeSchema

home_api = Blueprint('api', __name__)


@home_api.route('/')
@swag_from({
'responses': {
HTTPStatus.OK.value: {
'description': 'Welcome to the Flask Starter Kit',
'schema': WelcomeSchema
}
}
})
def welcome():
"""
1 liner about the route
A more detailed description of the endpoint
---
"""
result = WelcomeModel()
return WelcomeSchema().dump(result), 200
home_api = Blueprint('api', __name__)
@home_api.route('/')
@swag_from({
'responses': {
HTTPStatus.OK.value: {
'description': 'Welcome to the Flask Starter Kit',
'schema': WelcomeSchema
}
}
})
def welcome():
"""
1 liner about the route
A more detailed description of the endpoint
---
"""
result = WelcomeModel()
return WelcomeSchema().dump(result), 200

Schemas

The schemas are a very important part of this setup, and they are covered in detail in the flask-marshmallow documentation, but in essence a schema is a class that defines the properties and relationships among models and others in so that python can serialize the objects.

from flask_marshmallow import Schema
from marshmallow.fields import Nested, Str, Number
from api.schema.transaction import TransactionSchema


class BlockSchema(Schema):
class Meta:
# Fields to expose
fields = ["index", "timestamp", "transactions", "nonce", "previous_hash", "hash"]

index = Number()
nonce = Str()
timestamp = Number()
previous_hash = Str()
hash = Str()
transactions = Nested(TransactionSchema, many=True)
from flask_marshmallow import Schema
from marshmallow.fields import Nested
from api.schema.block import BlockSchema


class BlockchainSchema(Schema):
class Meta:
# Fields to expose
fields = ["blockchain"]

blockchain = Nested(BlockSchema, many=True)

Tests

As with any other application, tests are super important, and I could have an entire post discussing why. But here we will keep it simple. For tests I’m simply using unittest module from python, and I try to build tests for each component. Here is an example for our home route:

from unittest import TestCase
from app import create_app


class TestWelcome(TestCase):
def setUp(self):
self.app = create_app().test_client()

def test_welcome(self):
"""
Tests the route screen message
"""
rv = self.app.get('/api/')

# If we recalculate the hash on the block we should get the same result as we have stored
self.assertEqual({"message": 'Hello World!'}, rv.get_json())

Application

Finally, we need the place where we glue it all together, and we create our python API

from flask import Flask
from flasgger import Swagger
from api.route.home import home_api

def create_app():
app = Flask(__name__)

app.config['SWAGGER'] = {
'title': 'Flask API Starter Kit',
}
swagger = Swagger(app)

app.register_blueprint(home_api, url_prefix='/api')

return app


if __name__ == '__main__':
from argparse import ArgumentParser

parser = ArgumentParser()
parser.add_argument('-p', '--port', default=5000, type=int, help='port to listen on')
args = parser.parse_args()
port = args.port

app = create_app()

app.run(host='0.0.0.0', port=port)

Environment Set Up

Swagger Doc UI Example

I’m an entrepreneur, developer, author, speaker, and doer of things. I write about JavaScript, Python, AI, and programming in general.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store