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.
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'
}
Links
-
Issue tracker: https://github.com/betagouv/sqlalchemy-api-handler/issues
-
SQLAlchemy: https://www.sqlalchemy.org
Deploy
First, make sure that the deploy environment is started:
./sqlaah start
In a second tab, then:
-
Change the version into sqlalchemy_api_handler/init.py
-
Pre publish:
./sqlaah prepublish
- 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
Built Distribution
Hashes for SQLAlchemy-Api-Handler-0.9.4.tar.gz
Algorithm | Hash digest | |
---|---|---|
SHA256 | 917e3437211c9a2ce17ab5bbbe5f048d218940e175e551cb237af2f74eb838a3 |
|
MD5 | dd71e96b7c7e0dbe4a790a93b449c1de |
|
BLAKE2b-256 | d2ee2effa971fab618f842951ee6422942c3742ff979b43a8e78ff019456f7a3 |
Hashes for SQLAlchemy_Api_Handler-0.9.4-py2.py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | c8e93d6c7c5e182d5a13b51292ca02f0f81cf0d602db10244e63d59ef35e9d53 |
|
MD5 | 30e87f73ade35b2e2048824860fbedee |
|
BLAKE2b-256 | eb4647327153a0668626e624a0591356cfc4512267fa133a7854260c80302250 |