Flask-Potion is a RESTful API framework for Flask and SQLAlchemy, Peewee or MongoEngine

Overview

Flask-Potion

https://img.shields.io/travis/biosustain/potion/master.svg?style=flat-square https://img.shields.io/coveralls/biosustain/potion/master.svg?style=flat-square https://img.shields.io/pypi/v/Flask-Potion.svg?style=flat-square https://img.shields.io/pypi/l/Flask-Potion.svg?style=flat-square Join the chat at https://gitter.im/biosustain/potion

Flask-Potion

Description

Flask-Potion is a powerful Flask extension for building RESTful JSON APIs. Potion features include validation, model resources and routes, relations, object permissions, filtering, sorting, pagination, signals, and automatic API schema generation.

Potion ships with backends for SQLAlchemy, peewee and MongoEngine models. It is possible to add backends for other data stores, or even to use a subset of Potion without any data store at all.

API client libraries for Python and JavaScript/TypeScript (generic Node as well as AngularJS and Angular) are available.

User's Guide

The user's guide and documentation is published here:

http://potion.readthedocs.org/

Versioning

Potion will use semantic versioning from v1.0.0. Until then, the minor version is used for changes known to be breaking.

Features

  • Powerful API framework both for data-store-linked and plain resources
  • JSON-based and fully self-documenting with JSON Hyper-Schema
  • Backend integrations:
    • Flask-SQLAlchemy
    • Peewee (contributed by Michael Lavers)
    • Flask-MongoEngine
  • Filtering, sorting, pagination, validation, built right in
  • Smart system for handling relations between resources
  • Natural keys for extra simple relation querying
  • Easy-to-use, yet highly flexible, optional permissions system
  • Signals for pre- and post-processing of requests
  • Very customizable — everything is just a resource, route, or schema
  • Access APIs more easily with client libraries for Python and JavaScript/TypeScript

Example (SQLAlchemy)

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_potion import Api, ModelResource, fields
from flask_potion.routes import ItemRoute

app = Flask(__name__)
db = SQLAlchemy(app)
api = Api(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(), nullable=False)

db.create_all()

class UserResource(ModelResource):
    class Meta:
        model = User

    @ItemRoute.GET
    def greeting(self, user) -> fields.String():
        return "Hello, {}!".format(user.name)

api.add_resource(UserResource)

if __name__ == '__main__':
    app.run()

Authors

Potion is written and maintained by Lars Schöning.

Peewee backend support has been contributed by Michael Lavers.

MongoEngine backend support has been contributed by João Cardoso.

See here for the full list of contributors.

Comments
  • Initial support for Blueprints

    Initial support for Blueprints

    All of the tests should pass, and I've tested moving an app from using Potion w/o Blueprints to Blueprints with no apparent adverse effects.

    Note: One change here is that Api.__init__ now joins unnamed routes with _ rather than . (see https://github.com/refgenomics/potion/blob/blueprints/flask_potion/init.py#L159-L162) if the Api is initialized with a Blueprint. This should potentially be simplified to always use _ (. does not work with Blueprints).

    Caveats: I have not experimented with registering the same Blueprint multiple times (and if that has any unintended consequences) or registering multiple Blueprints (which this comment indicates may require a few changes https://github.com/biosustain/potion/blob/master/flask_potion/init.py#L83).

    Closes #12.

    @lyschoening – would appreciate your review and any further suggested changes.

    opened by boydgreenfield 11
  • fix: check to avoid BinaryExpression raising `TypeError: Boolean valu…

    fix: check to avoid BinaryExpression raising `TypeError: Boolean valu…

    fix: check to avoid BinaryExpression raising TypeError: Boolean value of this clause is not defined

    When updating a value to NULL, the expression get_value('location', item, None) != value evaluates to get_value('location', item, None) != None. The result, in case the value in db isn't NULL, is a IS NOT NULL BinaryExpression.

    As documented in here, under such circumstances, using <class 'sqlalchemy.sql.elements.BinaryExpression'> as python operator raises TypeError: Boolean value of this clause is not defined.

    opened by Alain1405 10
  • peewee backend

    peewee backend

    Trying my hand at a peewee backend for potion. The only part I haven't figured out is the relation_add and relation_remove methods. Peewee supports many-to-many relations using a playhouse extension, which is currently implemented. But for one-to-many, for example, the relation_* methods appear to be implemented in a reverse manner to what peewee expects. For example:

    class User(Model):
        parent = ForeignKeyField('self', null=True, related_name='children')
        name = CharField()
    

    You can't do:

    parent = User.create(name='foo')
    child = User.create(name='bar')
    parent.children.add(child)
    

    Instead you would do:

    child.parent = parent
    

    But relation_add/relation_remove only provide the item attribute and not the target attribute. So I'd have to figure out a way to get that attribute via peewee in some way. Haven't found a way to do this yet.

    opened by kolanos 10
  • Fix issue with posting with no content

    Fix issue with posting with no content

    Check if there is no content before aborting the request.

    This fixes issues with posts to endpoints that have no parameters i.e.

    @routes.ItemRoute.POST('/mark_read')
        def mark_read(self, move_task) -> fields.DateTimeString():
            move_task.mark_read()
            return move_task.seen_at
    

    Without this fix, you'd have one of two issues:

    >> http POST :5000/v2/move_tasks/667/mark_read 'Authorization: Bearer '(cat mtoken) 'Content-type: application/json'
    HTTP/1.0 400 BAD REQUEST
    Content-Length: 111
    Content-Type: application/json
    Date: Tue, 16 May 2017 19:57:03 GMT
    Server: Werkzeug/0.12.1 Python/3.6.1
    
    {
        "message": "Failed to decode JSON object: Expecting value: line 1 column 1 (char 0)",
        "status": 400
    }
    
    >> http POST :5000/v2/move_tasks/667/mark_read 'Authorization: Bearer '(cat mtoken)
    HTTP/1.0 415 UNSUPPORTED MEDIA TYPE
    Content-Length: 60
    Content-Type: application/json
    Date: Tue, 16 May 2017 19:57:09 GMT
    Server: Werkzeug/0.12.1 Python/3.6.1
    
    {
        "message": "Unsupported Media Type",
        "status": 415
    }
    
    opened by jas32096 9
  • Use of pattern_properties is not clear

    Use of pattern_properties is not clear

    I want to define an Object with patternProperties, basically to return a schema-free dict.

    Looking at the doc it seems you'd do this with fields.Object(pattern_properties={'.*': MyValueSchema}), but this just returns a dict with ".*" as key.

    What's the correct way of defining an object with patternProperties?

    opened by albertodonato 8
  • Exposed schema endpoints

    Exposed schema endpoints

    Even though I protect the generated API with authentication, the schema endpoints remain open:

    decorators = [jwt_authentication_dec]
    api_blueprint = Blueprint('api', __name__)
    api = Api(api_blueprint, decorators=decorators, default_manager=principals(SQLAlchemyManager))
    

    Any GET to http://example.com/api/schema or http://example.com/api/res/schema return the schema.

    opened by Alain1405 8
  • Support filtering for Uri and ItemUri

    Support filtering for Uri and ItemUri

    Addresses #72. Second commit if you don't want ItemUri filters on by default @lyschoening (I'd lean towards leaving this on for consistency with $id handling and because, well, otherwise users may run into it and think filtering is broken – but up to you, using a custom manager here anyhow)

    opened by boydgreenfield 8
  • Sort instances query stably, if applicable to underlying DB implementation

    Sort instances query stably, if applicable to underlying DB implementation

    ~I'm not 100% thrilled by the naming/implementation here (happy to take suggestions @lyschoening), but~ the current Flask-Potion code can lead to odd bugs for databases that do not guarantee the return order for queries without an ORDER BY clause (e.g., Postgres).

    Specifically, we were seeing issues where we'd get duplicate records in the paginated results. The underlying issue is (depending on one's perspective) either a bug or (under/mis)documentation in Flask-SQLAlchemy's paginate method on the query.

    This PR fixes this for the RelationalManager by ordering by the primary key if no other order by clause is provided.

    Note that it may be necessary to also add the primary key to the order clause in the general _query_order_by call for Postgres. I'll try to investigate this more tomorrow Pacific time.

    opened by boydgreenfield 7
  • Question: pagination not works for me

    Question: pagination not works for me

    I have this resource:

    class Goods(ModelResource):
        class Meta:
            name = 'goods'
            model = dal.Good
            include_id = True
    
        class Schema:
            category = fields.ToOne('good_categories')
    

    If I send GET request to http://localhost:5000/goods, response doesn't contain Links and X-Total-Countheaders.

    in instances.py there is some code like this:

    class PaginationMixin(object):
      def format_response(self, data):
            if not isinstance(data, self._pagination_types): 
                return self.format(data) # always RETURN THIS, break rest of the method
            .... 
    
    opened by KhodeN 7
  • Support `user:self` or `user:$id` or `user:$uri` in `PrincipalsMixin`

    Support `user:self` or `user:$id` or `user:$uri` in `PrincipalsMixin`

    Currently, the PrincipalsMixin supports generating a UserNeed based on a ToOne reference field, e.g., user:owner.

    It doesn't, however, seem to let you restrict access to generate a similar UserNeed for restricting access to a User resource directly.

    Locally, I've hacked a solution that simply supports other field types here. Unfortunately, the downstream checks assume that the field has a resource attribute, which requires adding the resource onto the ItemUri field (whether at init or in the need method calls) or changing them.

    Any thoughts on the most elegant solution @lyschoening? Happy to submit a PR if this is wanted/useful functionality.

    opened by boydgreenfield 6
  • Add basic filters for fields.Datetime()

    Add basic filters for fields.Datetime()

    @lyschoening, it seems that filtering on datetime columns are not possible right now, is that correct? And do you agree that this is a project issue that should be fixed?

    opened by brunsgaard 6
  • Adding a custom attribute to the instances

    Adding a custom attribute to the instances

    How can we define a custom attribute for instances?

    Using this route as example:

        @ItemRoute.GET
        def is_recent(self, book) -> fields.Boolean():
            return datetime.date.today().year <= book.year_published + 10
    

    How can we define is_recent at the instances level such as: http GET :5000/book/1 would return book attributes containing is_recent: True | False as well

    opened by matdrapeau 0
  • Query to only return specific fields set

    Query to only return specific fields set

    In order to reduce the amount of data being transferred from a resource, is it possible to provide a query args to return a set of fields? Sometimes, we don't need all attributes of an object but a couple of them. It would require too many custom routes to expose the different set of attributes we would need. Here a few examples to describe it:

    /users?include_fields=['first_name', 'last_name']
    /users?include_fields=['email']
    /users?include_fields=['city', 'country']
    
    opened by matdrapeau 1
  • example `peewee_simple.py` won't run (`AttributeError: 'Metadata' object has no attribute 'rel'`)

    example `peewee_simple.py` won't run (`AttributeError: 'Metadata' object has no attribute 'rel'`)

    by running the example peewee_simple.py as is, I get

    $ python peewee_simple.py
    Traceback (most recent call last):
      File "peewee_simple.py", line 42, in <module>
        api.add_resource(BookResource)
      File "/home/m/.local/share/virtualenvs/pano-vehicle-version-config-api-JCsed19j/lib/python3.6/site-packages/flask_potion/__init__.py", line 215, in add_resource
        resource.manager = self.default_manager(resource, resource.meta.get('model'))
      File "/home/m/.local/share/virtualenvs/pano-vehicle-version-config-api-JCsed19j/lib/python3.6/site-packages/flask_potion/contrib/peewee/manager.py", line 26, in __init__
        super(PeeweeManager, self).__init__(resource, model)
      File "/home/m/.local/share/virtualenvs/pano-vehicle-version-config-api-JCsed19j/lib/python3.6/site-packages/flask_potion/manager.py", line 27, in __init__
        self._init_model(resource, model, resource.meta)
      File "/home/m/.local/share/virtualenvs/pano-vehicle-version-config-api-JCsed19j/lib/python3.6/site-packages/flask_potion/contrib/peewee/manager.py", line 63, in _init_model
        if column.primary_key or name in model._meta.rel:
    AttributeError: 'Metadata' object has no attribute 'rel'
    
    opened by maxbellec 1
Releases(v0.16.0)
  • v0.16.0(Jan 10, 2019)

    Breaking Changes

    • The timezone is now always included with fields.DateTimeString and defaults to UTC with native datetime objects. (Thanks @albertodonato)

    Features

    • The sort_attribute meta class attribute of a resource can be used to change the default pagination sort order, which otherwise is id_attribute ascending. Descending order is supported. (Thanks @albertodonato and @luord)
    class SpamResource(Resource):
        class Meta:
            model = Spam
            sort_attribute = 'name', True
    

    Bugfixes

    • Fix field.Object(pattern_properties={}) pattern definition
    • Fix JSONSchema of patchable fields. (Thanks @bjornt)
    Source code(tar.gz)
    Source code(zip)
  • v0.15.1(Oct 9, 2018)

    Features

    • Allow setting custom error message for PotionException
    • Allow setting success_code argument with route decorator for a custom HTTP status code

    Bugfixes

    • Fix schema reference for cross resource fields.Inline
    Source code(tar.gz)
    Source code(zip)
  • v0.14.0(Feb 24, 2017)

    Features

    • Improve debug error messages on IntegrityError in SQLAlchemy

    Bugfixes

    • Fix IntegrityError in SQLAlchemy on update, delete not being handled properly

    • Use ID column for stable sort defaults in SQLAlchemy

      This resolves issues with pagination when sorting by a non-unique column.

    Source code(tar.gz)
    Source code(zip)
  • v0.13.0(Jan 26, 2017)

    Breaking changes

    • Fixes Api.decorators not being applied to "/schema"

      This means if you have an authenticated API your "/schema" endpoint is no longer available to unauthenticated users.

    Features

    • Adds POTION_DECORATE_SCHEMA_ENDPOINTS configuration option

      Setting this option to False makes the "/schema" endpoint and "/{resource_name}/schema" endpoints available in an Api protected using Api.decorators.

    • Adds support for user:$id and user:$uri needs with Flask-Principal

    Bugfixes

    • Fixes TypeError when applying PATCH to some SQLAlchemy native values
    • Fixes various inconsistencies in the JSON schemas
    Source code(tar.gz)
    Source code(zip)
  • v0.12.6(May 25, 2016)

  • v0.12.4(Apr 12, 2016)

  • v0.12.3(Mar 16, 2016)

    Features

    • Filters are now inherited (e.g. Email and Uri work like String because they inherits from it)
    • Added filters for DateString, DateTimeString (Thanks, @boydgreenfield)
    • Implemented ItemUri.convert(). This means you can now specify filters for the "$uri" field. For more info, see below. (Thanks, @boydgreenfield)

    Bugfixes

    • Fixes specifying custom filters using Meta.filters

    Enabling filtering by "$uri" in a resource:

            class Meta:
                filters = {
                    '$uri': {
                        None: filters.EqualFilter,
                        'eq': filters.EqualFilter,
                        'ne': filters.NotEqualFilter,
                        'in': filters.InFilter
                    },
                    '*': True
                }
    

    Note that filters needs to correspond to the manager implementation you are using, e.g. flask_potion.contrib.alchemy.filters. If you want to enable the filter in multiple resources, you can use a Meta mixin.

    Source code(tar.gz)
    Source code(zip)
  • v0.12.2(Feb 24, 2016)

    Features

    • Adds fields.UUID field for UUID strings in canonical form
    • Support for PostgreSQL-dialect UUID columns in the SQLAlchemyManager

    (Thanks, @shipperizer for both features)

    Bugfixes

    • id_converter is now always inferred from id_field_class unless it is specified manually.
    Source code(tar.gz)
    Source code(zip)
  • v0.12.1(Feb 8, 2016)

  • v0.12.0(Jan 19, 2016)

    Features

    • Refactored logic for inferring the id attribute and its field class type

    • Support for decimal.Decimal used for Numeric fields by PostgreSQL drivers (Thanks, @brunsgaard)

    • Updated the configuration of fields when used with a FieldSet:

      The io attribute on fields can now have 'c' (create) and 'u' (update) in addition to 'r' and 'w'. This allows for e.g fields that can only be written once on create 'cr' or are generated by the server but can then be updated 'ru'.

    Source code(tar.gz)
    Source code(zip)
  • v0.11.2(Dec 31, 2015)

  • v0.11.1(Dec 2, 2015)

  • v0.11.0(Dec 1, 2015)

    Features

    • Rewrote the filters implementation. They are now class-based and can be extended much more easily. A couple of new built-in filters for dates and strings have been added.
    • Routes are now internally referenced by their "rel" instead of their attribute name on the resource
    • Added Meta.exclude_routes option for excluding routes

    Bugfixes

    • Fixes an issue with peewee 2.7

    Breaking changes

    • Moved all backends from backends.BACKEND_NAME to contrib.BACKEND_NAME
    • fields.sa.InlineModel moved to contrib.alchemy.fields.InlineModel
    • Removed PrincipalsManager and PrincipalsResource. Now need to make own manager using principals(SQLAlchemyManager)
    Source code(tar.gz)
    Source code(zip)
  • v0.10.0(Oct 22, 2015)

  • v0.9.0(Oct 12, 2015)

  • v0.8.1(Oct 7, 2015)

Owner
DTU Biosustain
The Novo Nordisk Foundation Center for Biosustainability
DTU Biosustain
Library for building WebSocket servers and clients in Python

What is websockets? websockets is a library for building WebSocket servers and clients in Python with a focus on correctness and simplicity. Built on

Aymeric Augustin 4.3k Dec 31, 2022
Quiz Web App with Flask and MongoDB as the Databases

quiz-app Quiz Web Application made with flask and mongodb as the Databases Before you run this application, change the inside MONGODB_URI ( in config.

gibran abdillah 7 Dec 14, 2022
APIFlask is a lightweight Python web API framework based on Flask and marshmallow-code projects

APIFlask APIFlask is a lightweight Python web API framework based on Flask and marshmallow-code projects. It's easy to use, highly customizable, ORM/O

Grey Li 705 Jan 04, 2023
Async Python 3.6+ web server/framework | Build fast. Run fast.

Sanic | Build fast. Run fast. Build Docs Package Support Stats Sanic is a Python 3.6+ web server and web framework that's written to go fast. It allow

Sanic Community Organization 16.7k Dec 28, 2022
aiohttp-ratelimiter is a rate limiter for the aiohttp.web framework.

aiohttp-ratelimiter aiohttp-ratelimiter is a rate limiter for the aiohttp.web fr

JGL Technologies 4 Dec 11, 2022
Full duplex RESTful API for your asyncio web apps

TBone TBone makes it easy to develop full-duplex RESTful APIs on top of your asyncio web application or webservice. It uses a nonblocking asynchronous

TBone Framework 37 Aug 07, 2022
Screaming-fast Python 3.5+ HTTP toolkit integrated with pipelining HTTP server based on uvloop and picohttpparser.

Japronto! There is no new project development happening at the moment, but it's not abandoned either. Pull requests and new maintainers are welcome. I

Paweł Piotr Przeradowski 8.6k Dec 29, 2022
Web3.py plugin for using Flashbots' bundle APIs

This library works by injecting a new module in the Web3.py instance, which allows submitting "bundles" of transactions directly to miners. This is done by also creating a middleware which captures c

Georgios Konstantopoulos 294 Jan 04, 2023
The web framework for inventors

Emmett is a full-stack Python web framework designed with simplicity in mind. The aim of Emmett is to be clearly understandable, easy to be learned an

Emmett 796 Dec 26, 2022
An abstract and extensible framework in python for building client SDKs and CLI tools for a RESTful API.

django-rest-client An abstract and extensible framework in python for building client SDKs and CLI tools for a RESTful API. Suitable for APIs made wit

Certego 4 Aug 25, 2022
Fully featured framework for fast, easy and documented API development with Flask

Flask RestPlus IMPORTANT NOTICE: This project has been forked to Flask-RESTX and will be maintained by by the python-restx organization. Flask-RESTPlu

Axel H. 2.7k Jan 04, 2023
A python application to log QSOs directly to QRZ.com from the command line

qrzlogger This script is a QRZ.com command line QSO logger. It does the following: asks the user for a call sign displays available call sign info pul

Michael Clemens 15 Jul 16, 2021
WebSocket and WAMP in Python for Twisted and asyncio

Autobahn|Python WebSocket & WAMP for Python on Twisted and asyncio. Quick Links: Source Code - Documentation - WebSocket Examples - WAMP Examples Comm

Crossbar.io 2.4k Jan 06, 2023
Asita is a web application framework for python based on express-js framework.

Asita is a web application framework for python. It is designed to be easy to use and be more easy for javascript users to use python frameworks because it is based on express-js framework.

Mattéo 4 Nov 16, 2021
A simple todo app using flask and sqlachemy

TODO app This is a simple TODO app made using Flask. Packages used: DoodleCSS Special thanks to Chris McCormick (@mccrmx) :) Flask Flask-SQLAlchemy Fl

Lenin 1 Dec 26, 2021
FPS, fast pluggable server, is a framework designed to compose and run a web-server based on plugins.

FPS, fast pluggable server, is a framework designed to compose and run a web-server based on plugins. It is based on top of fastAPI, uvicorn, typer, and pluggy.

Adrien Delsalle 1 Nov 16, 2021
O SnakeG é um WSGI feito para suprir necessidadades de perfomance e segurança.

SnakeG O SnakeG é um WSGI feito para suprir necessidadades de perfomance e segurança. Veja o que o SnakeG possui: Multiprocessamento de requisições HT

Jaedson Silva 1 Jul 02, 2022
A Simple Kivy Greeting App

SimpleGreetingApp A Simple Kivy Greeting App This is a very simple GUI App that receives a name text input from the user and returns a "Hello" greetin

Mariya 40 Dec 02, 2022
Official mirror of https://gitlab.com/pgjones/quart

Quart Quart is an async Python web microframework. Using Quart you can, render and serve HTML templates, write (RESTful) JSON APIs, serve WebSockets,

Phil Jones 2 Oct 05, 2022
Persistent remote applications for X11; screen sharing for X11, MacOS and MSWindows.

Table of Contents About Installation Usage Help About Xpra is known as "screen for X" : its seamless mode allows you to run X11 programs, usually on a

xpra.org 785 Dec 30, 2022