API¶
Base¶
-
class
flask_occam.plugin.
Occam
(app=None, db=None)¶ Flask extension class for module, which sets up all flask-related capabilities provided by the module. This object can be initialized directly:
from flask import Flask from flask_occam import Occam app = Flask(__name__) occam = Occam(app)
Or lazily via factory pattern:
occam = Occam() app = Flask(__name__) occam.init_app(app)
For additional functionality, it is recommended that the extension be linked to the Flask-SQLAlchemy extension tied to the application:
from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() occam = Occam(db) app = Flask(__name__) db.init_app(app) occam.init_app(app)
-
init_app
(app, db=None)¶ Initialize application via lazy factory pattern.
- Args:
- app (Flask): Flask application. db (SQAlchemy): Flask SQLAlchemy extension.
-
init_db
(db)¶ Initialize database model extensions.
- Args:
- db (SQAlchemy): Flask SQLAlchemy extension.
-
-
class
flask_occam.plugin.
DataLoader
(model=None)¶ Helper for loading data into application via config file. Using the following model definition as an example:
class Item(db.Model): __tablename__ = 'item' # basic id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(255), nullable=False, unique=True, index=True) archived = db.Column(db.Boolean, default=False)
You can seed data from the following config file:
- name: item 1 archived: True - name: item 2 archived: False
Into the application using:
# via model directly User.seed('config.yml') # via db db.seed.users('config.yml')
Additionally, this class supports defining multiple types of models in config files. If you want to load multiple types of models via config, you can use the following syntax in your config:
Item: - name: item 1 archived: True User: - name: test user email: email@email.com
And load the data in your application via:
db.seed('config.yml')
Databse Mixins¶
-
class
flask_occam.mixins.
ModelMixin
¶ Example database mixin to be used in extension.
-
classmethod
all
(limit=None, offset=0)¶ Return all data with specified limit and offset
-
commit
()¶ Commit change using session and return item.
-
classmethod
count
()¶ Return total number of items in database.
-
classmethod
create
(*args, **kwargs)¶ Create new record using specified arguments.
-
delete
()¶ Delete current model object.
-
classmethod
find
(limit=None, offset=0, **filters)¶ Search database with specified limit, offset, and filter criteria.
-
classmethod
get
(*args, **filters)¶ Get single item using filter_by query.
-
json
()¶ Return dictionary with model properties. This method should be overriden by models to account for model-specific nuances in what to include in return payloads.
-
classmethod
load
(data, action=None)¶ Helper for loading data into application via config file. Using the following model definition as an example:
class Item(db.Model): __tablename__ = 'item' # basic id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(255), nullable=False, unique=True, index=True) archived = db.Column(db.Boolean, default=False)
You can seed data from the following config file:
- name: item 1 archived: True - name: item 2 archived: False
Into the application using:
# via model directly User.seed('config.yml') # via db db.seed.users('config.yml')
- Arguments:
data (str): File handle or path to config file. action (callable): Function to call on each loaded item.
Takes single created item as input.
-
update
(*args, **kwargs)¶ Update current item with specified data.
-
classmethod
upsert
(*args, **kwargs)¶ Upsert specified data into database. If the data doesn’t exist in the database, it will be created, otherwise, the record will be updated. This method automatically detects unique keys by which to query the database for existing records.
Note
The performance of this could be improved by doing bulk operations for querying and the create/update process.
-
classmethod
Handlers¶
-
class
flask_occam.handlers.
ActionHandler
¶ Handler for urls like
/model/:action
, where <action> represents a POST request. This allows developers to define individual methods for performing model-specific actions instead of needing to manage that complexity in the get/put/post methods.-
post
(**kwargs)¶ Overwrite post endpoint for handler.
- Args:
- ident (int): Identifier for model. action (str): String for action to perform.
-
-
class
flask_occam.handlers.
QueryHandler
¶ Handler for urls like
/model/:query
, where <query> represents a GET request. This allows developers to define individual methods for performing model-specific queries instead of needing to manage that complexity in the get/put/post methods.-
get
(**kwargs)¶ Overwrite get endpoint for handler.
- Args:
- ident (int): Identifier for model. query (str): String for query to perform.
-
Converters¶
-
class
flask_occam.converters.
ModelConverter
(map, model)¶ For url inputs containing a model identifier, look up the model and return the object.
This method simplifies a lot of the boilerplate needed to do model look ups in REST apis.
Examples:
@app.route('/users/<id(User):user>') def get_user(user): return jsonify(user.json())
In addition, this class can be inherited and used for other custom parameter url converters. For instance, here is how you might use it to create a name converter:
class NameConverter(ModelConverter): __param__ = 'name' app.url_map.converters['name'] = NameConverter # ... handlers ... @app.route('/users/<name(User):user>') def get_user(user): return jsonify(user.json())
Decorators¶
-
class
flask_occam.decorators.
log
(msg, level=None)¶ Decorator for adding default logging functionality to api methods.
-
classmethod
critical
(msg)¶ Log provided message with level CRITICAL.
-
classmethod
debug
(msg)¶ Log provided message with level DEBUG.
-
classmethod
error
(msg)¶ Log provided message with level ERROR.
-
classmethod
info
(msg)¶ Log provided message with level INFO.
-
classmethod
warning
(msg)¶ Log provided message with level WARNING.
-
classmethod
-
flask_occam.decorators.
paginate
(**options)¶ Automatically force request pagination for endpoints that shouldn’t return all items in the database directly. If this decorator is used,
limit
andoffset
request arguments are automatically included in the request. The burden is then on developers to do something with thoselimit
andoffset
arguments. An example request header set by this decorator is as follows:Link: <https://localhost/items?limit=50&offset=50>; rel="next", <https://localhost/items?limit=50&offset=500>; rel="last"
- Args:
limit (int): Number of entries to limit a query by. total (int, callable): Number or callable for determining
the total number of records that can be returned for the request. This is used in determining the pagination header.
-
flask_occam.decorators.
transactional
(func)¶ Decorator for wrapping transactional support around a request handler or API method. By wrapping a method in
@transactional
, any exception thrown will force a session rollback. Otherwise, the session will be committed.
-
class
flask_occam.decorators.
validate
(*args, **kwargs)¶ Validate payload data inputted to request handler or API method. This decorator can take any arbitrary data structure and determine rules to validate inputs with. It can be run within the context of a flask request, or for an api method directly. See the examples below for details.
Note
In a request context, a
ValidationError
will be thrown (HTTP 422 Unprocessable Entity). Outside of a request, aValueError
will be raised.Examples:
Using types with API method:
@validate( email=str, password=str ) def login(email, password): return
Using nested types (mixing types and validators):
from wtforms import validators @blueprint.route('/login', methods=['POST']) @validate( data=dict( email=validators.Email(), password=str ) ) def login(): return
With pre-defined validation object:
from wtforms import validators, Form, BooleanField from wtforms import StringField, PasswordField class LoginValidator(Form): email = StringField('Email Address', [ validators.DataRequired(), validators.Email(), ]) password = PasswordField('Password', [ validators.DataRequired(), validators.Length(min=4, max=25) ]) @blueprint.route('/login', methods=['POST']) @validate(LoginForm) def login(): return
Logic specified into decorator:
@blueprint.route('/login', methods=['POST']) @validate( email = StringField('Email Address', [ validators.DataRequired(), validators.Email(), ]) password = PasswordField('Password', [ validators.DataRequired(), validators.Length(min=4, max=25) ]) ) def login(): return
-
classmethod
optional
(*args, **kwargs)¶ Force all specified parameters to be wrapped with optional() declaration.
-
classmethod