Skip to main content

Adds SQLAlchemy support to your Flask application for handle apis.

Project description

sqlalchemy-api-handler

SQLAlchemy-Api-Handler is an extension that adds support for handling apis with sqlalchemy. It helps to handle models with :

  • humanized ids once it is jsonified,
  • throwing api errors for some casting of value during the save time,
  • dictification of the model objects into jsonified ones.
  • It also gives an activate method to help you better handle offline operational transforms, based on the PostgreSQL-Audit Activity model.

CircleCI

Installing

Install and update using pip:

  $ pip install -U SQLAlchemy-Api-Handler

A Simple Example

Suppose a request POST /users {'email': 'marx.foo@plop.fr', name: 'Marx Foo'} :

    from flask import Flask, jsonify, request
    from sqlalchemy_api_handler import ApiHandler

    app = Flask(__name__)
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.sqlite'
    db = SQLAlchemy(app)
    ApiHandler.set_db(db)

    class User(ApiHandler, db.Model):
        email = db.Column(db.String, unique=True, nullable=False)
        name = db.Column(db.String, unique=True, nullable=False)

    @app.route('/users', methods=['POST'])
    def post_user():
      user = User(**request.form)
      ApiHandler.save(user)
      return jsonify(as_dict(user))

The success result will have stored a user object at, let's say id = 32, and so will fetch an object at humanized id = humanize(32), ie

  {'id': 'EA', 'email': 'marx.foo@plop.fr', name: 'Marx Foo'}

Playing with nesting data

Suppose a request GET /offers

    from flask import Flask, jsonify, request
    from sqlalchemy.orm import relationship
    from sqlalchemy_api_handler import ApiHandler

    app = Flask(__name__)
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.sqlite'
    db = SQLAlchemy(app)
    ApiHandler.set_db(db)

    class Venue(ApiHandler, db.Model):
        address = db.Column(db.String, unique=True, nullable=False)
        name = db.Column(db.String, unique=True, nullable=False)

    class Offer(ApiHandler, db.Model):
        name = db.Column(db.String, unique=True, nullable=False)
        venueId = db.Column(db.BigInteger,
                     db.ForeignKey('venue.id'),
                     nullable=False,
                     index=True)
        venue = relationship('Venue',
                             foreign_keys=[venueId],
                             backref='offers')

    class Stock(ApiHandler, db.Model):
        available = db.Column(db.Integer, nullable=False)
        offerId = db.Column(db.BigInteger,
                         db.ForeignKey('offer.id'),
                         index=True,
                         nullable=False)
        offer = relationship('Offer',
                             foreign_keys=[offerId],
                             backref='stocks')

    venue = Venue(address='Somewhere I belong', name='MyVenue')
    offer = Offer(name='MyOffer')
    stock = Stock(available=10)
    stock.offer = offer
    offer.venue = venue
    ApiHandler.save(stock)

    offer_includes = [
      'stocks',
      {
        'key': 'venue',
        'includes': [
          '-address'
        ]
      }
    ]

    @app.route('/offers', methods=['GET'])
    def get_offers():
      offers = Offer.query.all()
      return jsonify(as_dict(offers, includes=offer_includes))

The success will return

  [
    {
      'id': 'AE',
      'name': 'MyOffer',
      'stocks': [
        {
          'available': 10,
          'id': 'AE'
        }
      ],
      'venue': {
        'name': 'MyVenue'
      }
    }
  ]

Activity

If you need to manage operation transforms of your entities (typically with a collaborative app working offline) :

    from flask import Flask, jsonify, request
    from sqlalchemy.orm import relationship
    from sqlalchemy_api_handler import ApiHandler
    from sqlalchemy_api_handler.mixins import ActivityMixin, \
                                              HasActivitiesMixin

    app = Flask(__name__)
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.sqlite'
    db = SQLAlchemy(app)
    ApiHandler.set_db(db)

    versioning_manager.init(db.Model)
    class Activity(ActivityMixin,
                   ApiHandler,
                   versioning_manager.activity_cls):
        __table_args__ = {'extend_existing': True}

        id = versioning_manager.activity_cls.id
    ApiHandler.set_activity(Activity)

    class Venue(ApiHandler,
                db.Model,
                HasActivitiesMixin):
        address = db.Column(db.String, unique=True, nullable=False)
        name = db.Column(db.String, unique=True, nullable=False)

    @app.route('/__activities__', methods=['POST'])
    def create_activities():
        activities = [Activity(**a) for a in request.json]
        ApiHandler.activate(*activities)
        return jsonify([as_dict(activity) for activity in activities]), 201

The request POST /activities helps you to sync your backend with the last state of pushed activities. For example, if the data posted is :

[
  {
    "dateCreated": "2020-08-05T08:34:06.415000Z" ,
    "entityIdentifier": "4039fb61-f085-43c4-a2ed-e5e97c5dcebc",
    "modelName": "Venue",
    "patch": { "address": "22 rue de la Loire", "name": "MyVenue" }
  },
  {
    "dateCreated": "2020-08-06T09:34:06.415000Z" ,
    "entityIdentifier": "4039fb61-f085-43c4-a2ed-e5e97c5dcebc",
    "modelName": "Venue",
    "patch": { "name": "MyVenueChanged" }
  }
]

It will then end to create a venue instance:

venue = Venue.query.filter_by(name='MyVenueChanged').first()
print(as_dict(venue, includes=['__activities__']))
{
  '__activities__': [
    {
      'dateCreated': '2020-08-05T08:34:06.415000Z',
      'entityIdentifier': '4039fb61-f085-43c4-a2ed-e5e97c5dcebc',
      'id': 'BA',
      'modelName': 'Venue',
      'patch': {
        'address': '22 rue de la Loire',
        'name': 'MyVenue'
      },
      'verb': 'insert'
    },
    {
      'dateCreated': '2020-08-06T09:34:06.415000Z',
      'entityIdentifier': '4039fb61-f085-43c4-a2ed-e5e97c5dcebc',
      'id': 'BF',
      'modelName': 'Venue',
      'patch': {
        'name': 'MyVenueChanged'
      },
      'verb': 'update'
    }
  ],
  'activityIdentifier': '2020-08-05T08:34:06.415000Z',
  'address': "22 rue de la Loire",
  'id': 'AE',
  'name': 'MyVenueChanged'
}

Celery

Sometimes it's hard to track celery tasks from the celery cli itself. And you may not want use flower when you have one exposed port by application, like in scalingo classic services. Therefore, ApiHandler can also synchronise the tasks to be stored in your postgres db, then you can build your Tasks Manager Dashboard front easy as you want, querying from classic postgres api routes. See how the example is build in the api folder.

Links

Deploy

First, make sure that the deploy environment is started:

  ./sqlaah start

In a second tab, then:

  1. Change the version into sqlalchemy_api_handler/init.py

  2. Pre publish:

  ./sqlaah prepublish
  1. Publish:
  ./sqlaah publish

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

SQLAlchemy-Api-Handler-0.12.3.tar.gz (35.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

SQLAlchemy_Api_Handler-0.12.3-py2.py3-none-any.whl (37.4 kB view details)

Uploaded Python 2Python 3

File details

Details for the file SQLAlchemy-Api-Handler-0.12.3.tar.gz.

File metadata

  • Download URL: SQLAlchemy-Api-Handler-0.12.3.tar.gz
  • Upload date:
  • Size: 35.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.7.0 requests/2.25.1 setuptools/41.4.0 requests-toolbelt/0.9.1 tqdm/4.59.0 CPython/3.7.5

File hashes

Hashes for SQLAlchemy-Api-Handler-0.12.3.tar.gz
Algorithm Hash digest
SHA256 ffec4ca65882113662ce2b04f189a9f4d4d3491f44e6af1131f83a7a705a0902
MD5 d228b2735c620451f9c46113dec982a3
BLAKE2b-256 764b2e9b910408de4edb0ad6a994bb4cc35ee85e09d4f0a447d04d1c4ed9f232

See more details on using hashes here.

File details

Details for the file SQLAlchemy_Api_Handler-0.12.3-py2.py3-none-any.whl.

File metadata

  • Download URL: SQLAlchemy_Api_Handler-0.12.3-py2.py3-none-any.whl
  • Upload date:
  • Size: 37.4 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.7.0 requests/2.25.1 setuptools/41.4.0 requests-toolbelt/0.9.1 tqdm/4.59.0 CPython/3.7.5

File hashes

Hashes for SQLAlchemy_Api_Handler-0.12.3-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 1f2966ae2860207d6e0092787856d4ef29dc995ce20162833ab1509195ddb537
MD5 08f9c723c2790940d7b32adfecf39a26
BLAKE2b-256 e2f9dc33b04c87789a57788c7625c394f1a908b00624a248ddf1e5366367011e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page