Simple Flask API Server For Beginners - With Sample Code

Sm0ke - Feb 1 '22 - - Dev Community

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

Route Verb Info Status
/datas GET return all items βœ”οΈ
POST create a new item βœ”οΈ
/datas:id GET return one item βœ”οΈ
PUT update item βœ”οΈ
DELETE delete 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
Enter fullscreen mode Exit fullscreen mode

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)
...
Enter fullscreen mode Exit fullscreen mode

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, provide 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 
... 
Enter fullscreen mode Exit fullscreen mode

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)})
Enter fullscreen mode Exit fullscreen mode

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:

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player