Simple Flask API Server For Beginners - With Sample Code

Simple Flask API Server For Beginners - With Sample Code

Open-source API server that might help beginners to understand better the API concept

ยท

4 min read

Hello Coders!

This article presents a simple API starter that might help beginners to understand better the API concept. The codebase can be downloaded from Github and used for eLearning activities or production. The framework that powers the API is Flask, a leading software library actively supported and versioned by many open-source enthusiasts.

Thanks for reading! What's in the box:

  • ๐Ÿ‘‰ Simple API over a minimal Datas table
  • ๐Ÿ‘‰ SQLite Persistence managed by an elegant ORM (SqlAlchemy)
  • ๐Ÿ‘‰ Powerful API core provided by Flask-RestX
  • ๐Ÿ‘‰ Strong Input validation
  • ๐ŸŽ Free support via email and Discord (1k+ community).

API Definition

RouteVerbInfoStatus
/datasGETreturn all itemsโœ”๏ธ
POSTcreate a new itemโœ”๏ธ
/datas:idGETreturn one itemโœ”๏ธ
PUTupdate itemโœ”๏ธ
DELETEdelete itemโœ”๏ธ

Technology Stack

  • Flask for routing and overall management
  • Flask-RestX for API
  • Flask-SqlAlchemy - manages the DB with minimal code
  • Docker set up provides a quick start for lazy devs (like me)

โœจ API Coding & Implementation Rules

  • Simple Interface
  • Consistent, intuitive actions
  • Use the right verbs for each action
    • GET for read-only actions
    • DELETE for item removal
    • POST for updates
  • Strong Input Validation

โœจ Codebase Structure

All relevant files are listed below. Other files like docker-compose.yml, README, LICENSE are omitted.

api-server-flask/
โ”œโ”€โ”€ api
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ config.py
โ”‚   โ”œโ”€โ”€ models.py
โ”‚   โ””โ”€โ”€ routes.py
โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ requirements.txt
โ””โ”€โ”€ run.py

A few words about each one:

  • run.py - the entry point
  • api folder
    • __init__.py constructs the APP
    • models.py - define a single (simple) model
    • routes.py - does the hard work
    • config.py - implements a minimal set up

โœจ API Models

The information managed by the API is saved using a simple table defined with three fields: id, data, date_created. Here is the source code:

# Contents of "api/models.py" (truncated)
...
class Datas(db.Model):

    id           = db.Column(db.Integer()   , primary_key=True)
    data         = db.Column(db.String(256) , nullable=False)
    date_created = db.Column(db.DateTime()  , default=datetime.utcnow)
...

The source code provides a few helpers that make our life, as a developer, easier:

  • update_data - update the data field
  • save - save & commit the updates of the current object
  • toJSON - returns the JSON representation

โœจ Routing

Each method is kept as simple as possible but at the same time, provides a robust validation and elegant SQL access.

For instance, the route that manages the update operation for an item:

# Contents of "api/routes.py" (truncated)
....
@rest_api.route('/api/datas/<int:id>')
class ItemManager(Resource):
...
    """
       Update Item
    """
    @rest_api.expect(update_model, validate=True)
    def put(self, id):

        item = Datas.get_by_id(id)

        # Read ALL input from body  
        req_data = request.get_json()

        # Get the information    
        item_data = req_data.get("data")

        if not item:
            return {"success": False,
                    "msg": "Item not found."}, 400

        item.update_data(item_data)
        item.save()

        return {"success" : True,
                "msg"     : "Item [" +str(id)+ "] successfully updated",
                "data"    :  item.toJSON()}, 200 
...

Let's iterate over the relevant lines:

@rest_api.route('/api/datas/<int:id>') defines the route

Flask will route the request to this section when user access /api/datas/1 for instance .

@rest_api.expect(update_model, validate=True)

This decorator trigger a validation previously defined as bellow:

update_model = rest_api.model('UpdateModel', {"data": fields.String(required=True, min_length=1, max_length=255)})

If the data field has a size over 255, the request is rejected. For us, as developers, the coding effort is minimal.

The next steps performed by our handler are:

  • Select the Item from DB using the ID
    • item = Datas.get_by_id(id) via SQLAlchemy
  • Exit with a comprehensive error if item not found
  • If Item is found
    • Update the data field
    • Save the new object in database

โœจ Where to go from here

This simple API will be extended with more features soon:

  • Add more fields to Datas model
  • Implement authentication
  • restrict update actions to authenticated users.

Have an idea? Please mention your suggestion in the comments section.


Thank you!


โœจ For more resources, feel free to access:

ย