Flask Neon Kit: The extension which automatically generates CRUD endpoints

valentinesean22

Valentine Sean Chanengeta

Posted on September 2, 2024

Flask Neon Kit: The extension which automatically generates CRUD endpoints

This is a submission for the Neon Open Source Starter Kit Challenge : Ultimate Starter Kit

My Kit

The flask-neon-kit is a Flask extension which generates CRUD endpoints out of the box from defined models of the Neon Postgres database. It empowers developers with resources' CRUD endpoints by just defining database models and instantiating the kit. This solution is built upon the foundation of the Flask-SQLAlchemy. This initiative was driven by the tedious nature of manually writing CRUD logic for every Flask application entity. It was also motivated by flask-mongo-crud, the package I am working on that automatically generates CRUD endpoints for MongoDB models.

Features of the solution are:

  • Automatically generates CRUD endpoints from defined model.
  • Allows to customize app base URL as well as each model’s url prefix.
  • Allows to paginate when getting many entities from database table.

Prerequisites for using the kit:

  • Familiarity with implementing Flask Applications.
  • Familiarity with integrating Flask Applications with Postgres database using Flask-SQLAlchemy.

Installation

pip install flask-neon-kit
Enter fullscreen mode Exit fullscreen mode

Folder Structure of Basic Application

project_root
|    __init__.py
|    config.py
|    app.py
|
|____models
     |    professor_subject.py
Enter fullscreen mode Exit fullscreen mode

Configuration

  • Empty init.py file required in project root directory.
  • ROOT_URL can be configured in application's configurations and it is optional.
  • If configured, it is used by all generated endpoints.
  • Code snippet in Basic Application section shows how to configure ROOT_URL.
  • Database Configuration (config.py):

    class DbConfig(object):
        SQLALCHEMY_DATABASE_URI = "<NEON-POSTGRES-CONNECTION-STRING>"
    
  • Models:

    • Models directory is required in the project root directory:
    • If custom name Models directory is not defined, as:

      app.config[MODELS_DIRECTORY] = "<CUSTOM_NAME>"
      
      • then, default “models” directory will be used.
      • This is where models files are defined.
      • Inside these files declare models classes and their configurations such as:
        • model_url_prefix [OPTIONAL]
        • and those supported by Flask SQLAlchemy
      • model_url_prefix allows to have unique URLs for each and every model.
      • If this configuration is not defined, default configuration will be used.
    • Model Class Code Snippet (professor_subject.py):

      class ProfessorSubject:
          model_url_prefix = "/professor-subject-test"
      
          id = db.Column(db.Integer, primary_key=True, autoincrement=True)
          professor_first_name = db.Column(db.String())
          professor_last_name = db.Column(db.String())
          subject_name = db.Column(db.String())
      
          # These are entity fields
          def __init__(self, professor_first_name, professor_last_name, subject_name):
              self.professor_first_name = professor_first_name
              self.professor_last_name = professor_last_name
              self.subject_name = subject_name
      

Basic Application

  • Code Snippet (app.py):

    from flask import Flask, request
    from flask_sqlalchemy import SQLAlchemy
    from .config import DbConfig
    from flask_neon_kit import FlaskNeonKit
    
    app = Flask(__name__)
    # If models directory is not defined, default "models" directory will be used
    app.config["MODELS_DIRECTORY"] = "<CUSTOM_NAME>"
    # If root URL is not defined, generated endpoints will not have a root URL
    app.config["ROOT_URL"] = "/flask-neon-kit/v1"
    
    app.config.from_object(DbConfig)
    
    # Database related part
    db = SQLAlchemy()
    db.init_app(app)
    
    flask_neon_kit = FlaskNeonKit()
    flask_neon.init_app(app, request, db)
    
    if __name__ == "__main__":
        app.run(debug=True)
    

Generated Endpoints Examples and HTTP Methods:

  • HTTP Methods supported are POST, GET, PUT and DELETE.
  • The following generated endpoints will be using model snippet defined earlier in Configuration as well Basic Application sections.
  • These endpoints are after application base URL: <IP_ADDRESS>:<PORT_NUMBER>
  • Basic complete URL looks like:

    <IP_ADDRESS>:<PORT_NUMBER>/<ROOT_URL>/<MODEL_URL_PREFIX>/<RESOURCE_NAME>

    or

    <IP_ADDRESS>:<PORT_NUMBER>/<ROOT_URL>/<MODEL_URL_PREFIX>/<RESOURCE_NAME>/<RESOURCE_IDENTIFIER>

  • RESOURCE_NAME is automatically generated, and a developer can not customize it.

  • RESOURCE_IDENTIFIER should be the entity ID.

  • Given the generated URL:
    localhost:5000/flask-neon-kit/v1/professor-subject-test/professor-subject/2:

    • "/professor-subject" is the RESOURCE_NAME.
    • "/2" is the RESOURCE_IDENTIFIER.
    • In case ROOT_URL is not specified:
      • In the above URL, ROOT_URL is /flask-neon-kit/v1.
      • The URL without ROOT_URL is /professor-subject-test/professor-subject
    • In case MODEL_URL_PREFIX is not specified:
      • In the above URL, MODEL_URL_PREFIX is /professor-subject-test
      • The URL without MODEL_URL_PREFIX is /flask-neon-kit/v1/professor-subject
    • In case both ROOT_URL and MODEL_URL_PREFIX are not specified:
      • The URL without both is /professor-subject
      • It contains only the RESOURCE_NAME.

POST

  • Saves new entity into the database
  • Only saves one entity at a time.
  • Supports only JSON data.

  • JSON Request Payload Example:

    {
        "professor_first_name": "Foo",
        "professor_last_name": "Bar",
        "subject_name": "Comp Science"
    }
    
  • JSON Response Payload Example:

    {
        "message": "professor-subject created successfully"
    }
    

GET

  • Retrieves entities from the database.
  • Can retrieve only one entity or a list of entities.
  • To retrieve only one entity, include RESOURCE_IDENTIFIER in the URL.
  • This RESOURCE_IDENTIFIER will be used to identify that one entity.
  • If RESOURCE_IDENTIFIER is not provided, list of entities will be retrieved.
  • Developer can opt for pagination when retrieving many entities.
  • To paginate, provide the following query parameters:

    • pagination = true. If "false", all entities will be retrieved from the database table.
    • limit = "number of entities" per page. Should be integer greater than 0. If not provided and pagination is true, default value of 5 will be used.
    • page = "page number". Should be integer greater than 0. If not provided and pagination is true, default value of 1 will be used.
  • JSON Response Payload Example for Paginated Entities:

    {
        {
            "count": 2,
            "current_page": 1,
            "data": [
                {
                    "id": 2,
                    "professor_first_name": "John",
                    "professor_last_name": "Doe",
                    "subject_name": "Math"
                },
                {
                    "id": 3,
                    "professor_first_name": "Foo",
                    "professor_last_name": "Bar",
                    "subject_name": "Comp Science"
                }
            ],
            "has_next": false,
            "has_pagination": true,
            "has_prev": false,
            "limit": 5,
            "message": "professor-subject retrieved successfully",
            "total": 2
          }
    }
    

PUT

  • Updates one entity at a time.
  • That entity is identified by RESOURCE_IDENTIFIER in the URL.
  • If there is no such entity in the database, " not found" response will be returned.

DELETE

  • Deletes one entity at a time.
  • That entity is identified by RESOURCE_IDENTIFIER in the URL.
  • If there is no such entity in the database, the endpoint will return a payload:

    {
        "message": "<RESOURCE_NAME> not found"
    }
    

Link to Kit

GitHub:

Flask Neon Kit Docs

Features

  • Automatically generates CRUD endpoints from defined model.
  • Allows to customize app base URL as well as each model's url prefix.
  • Allows to paginate when getting many entities from database table.

Installation

pip install flask-neon-kit
Enter fullscreen mode Exit fullscreen mode

Configuration

  • Empty init.py file required in project root directory.
  • ROOT_URL can be configured in application's configurations and it is optional.
  • If configured, it is used by all generated endpoints.
  • Code snippet in Basic Application section shows how to configure ROOT_URL.
  • Models
    • Models directory is required in the project root directory:
    • If custom name Models directory is not defined, as
      app.config[MODELS_DIRECTORY] = "<CUSTOM_NAME>"
      Enter fullscreen mode Exit fullscreen mode
      • then, default “models” directory will be used.
      • This is where models files are defined.
      • Inside these files declare models classes and their configurations such as
        • model_url_prefix [OPTIONAL]
        • and those supported by Flask SQLAlchemy
      • model_url_prefix allows to have unique URLs for each and…




The kit was also uploaded on Python Package Index (PyPI)

Your Journey

Main objective of this solution is to minimize the tedious nature of manually writing common CRUD logic for every Flask application entity. There is also a plan to integrate some cool Neon features like data branches management in the future. This will enable developers to switch among their data branches to work with different versions of their data whilst in their application development environment. This should have been integrated in this version but seems Neon API currently has some limitations to support such features. I learned a lot during the course, and the concept of data branches is one of the features I am looking forward into exploring in the future.

💖 💪 🙅 🚩
valentinesean22
Valentine Sean Chanengeta

Posted on September 2, 2024

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

Sign up to receive the latest update from our blog.

Related