def test_blueprint_response_schema(self, app, openapi_version, schemas):
        """Check response schema is correctly documented.

        More specifically, check that:
        - plural response is documented as array in the spec
        - schema is document in the right place w.r.t. OpenAPI version
        """
        app.config['OPENAPI_VERSION'] = openapi_version
        api = Api(app)
        blp = Blueprint('test', 'test', url_prefix='/test')

        @blp.route('/schema_many_false')
        @blp.response(schemas.DocSchema(many=False))
        def many_false():
            pass

        @blp.route('/schema_many_true')
        @blp.response(schemas.DocSchema(many=True))
        def many_true():
            pass

        api.register_blueprint(blp)

        paths = api.spec.to_dict()['paths']

        schema_ref = build_ref(api.spec, 'schema', 'Doc')

        response = paths['/test/schema_many_false']['get']['responses']['200']
        if openapi_version == '2.0':
            assert response['schema'] == schema_ref
        else:
            assert (response['content']['application/json']['schema'] ==
                    schema_ref)

        response = paths['/test/schema_many_true']['get']['responses']['200']
        if openapi_version == '2.0':
            assert response['schema']['items'] == schema_ref
        else:
            assert (response['content']['application/json']['schema']['items']
                    == schema_ref)
示例#2
0
    def test_blueprint_doc_info_from_docstring(self, app):
        api = Api(app)
        blp = Blueprint('test', __name__, url_prefix='/test')

        @blp.route('/')
        class Resource(MethodView):
            def get(self):
                """
                Docstring get summary.
                """

            def put(self):
                """
                Docstring put summary.

                Docstring put description
                """

            @blp.doc(
                summary='Decorator patch summary',
                description='Decorator patch description',
            )
            def patch(self):
                """
                Docstring patch summary.

                Docstring patch description
                """

        api.register_blueprint(blp)
        spec = api.spec.to_dict()
        path = spec['paths']['/test/']

        assert path['get']['summary'] == 'Docstring get summary.'
        assert 'description' not in path['get']
        assert path['put']['summary'] == 'Docstring put summary.'
        assert path['put']['description'] == 'Docstring put description'
        # @doc decorator overrides docstring
        assert path['patch']['summary'] == 'Decorator patch summary'
        assert path['patch']['description'] == 'Decorator patch description'
    def test_blueprint_arguments_location(self, app, schemas, location_map,
                                          openapi_version):
        app.config['OPENAPI_VERSION'] = openapi_version
        api = Api(app)
        blp = Blueprint('test', __name__, url_prefix='/test')
        location, openapi_location = location_map

        if location is not None:

            @blp.route('/')
            @blp.arguments(schemas.DocSchema, location=location)
            def func():
                """Dummy view func"""
        else:

            @blp.route('/')
            @blp.arguments(schemas.DocSchema)
            def func():
                """Dummy view func"""

        location = location or 'json'

        api.register_blueprint(blp)
        spec = api.spec.to_dict()
        get = spec['paths']['/test/']['get']
        if (openapi_version == '3.0.2'
                and location in REQUEST_BODY_CONTENT_TYPE):
            assert 'parameters' not in get
            assert 'requestBody' in get
            assert len(get['requestBody']['content']) == 1
            assert REQUEST_BODY_CONTENT_TYPE[location] in get['requestBody'][
                'content']
        else:
            loc = get['parameters'][0]['in']
            assert loc == openapi_location
            assert 'requestBody' not in get
            if location in REQUEST_BODY_CONTENT_TYPE and location != 'json':
                assert get['consumes'] == [REQUEST_BODY_CONTENT_TYPE[location]]
            else:
                assert 'consumes' not in get
    def test_etag_verify_check_etag_exception(
            self, app, method, debug, testing):
        app.config['DEBUG'] = debug
        app.config['TESTING'] = testing
        blp = Blueprint('test', __name__)

        with NoLoggingContext(app):
            with app.test_request_context('/', method=method):
                if (debug or testing) and method in ['PUT', 'PATCH', 'DELETE']:
                    with pytest.raises(
                            CheckEtagNotCalledError,
                            match='ETag not checked in endpoint'
                    ):
                        blp._verify_check_etag()
                else:
                    blp._verify_check_etag()
示例#5
0
    def test_blueprint_path_parameters(self, app, openapi_version):
        """Check auto and manual param docs are merged"""
        app.config['OPENAPI_VERSION'] = openapi_version
        api = Api(app)
        blp = Blueprint('test', __name__, url_prefix='/test')

        @blp.route('/<int:item_id>')
        @blp.doc(parameters=[{
            'name': 'item_id',
            'in': 'path',
            'description': 'Item ID'
        }])
        def get(item_id):
            pass

        api.register_blueprint(blp)
        spec = api.spec.to_dict()
        params = spec['paths']['/test/{item_id}']['get']['parameters']
        assert len(params) == 1
        if openapi_version == '2.0':
            assert params == [{
                'name': 'item_id',
                'in': 'path',
                'required': True,
                'description': 'Item ID',
                'format': 'int32',
                'type': 'integer'
            }]
        else:
            assert params == [{
                'name': 'item_id',
                'in': 'path',
                'required': True,
                'description': 'Item ID',
                'schema': {
                    'format': 'int32',
                    'type': 'integer'
                }
            }]
示例#6
0
    def test_blueprint_response_examples(self, app, openapi_version):
        app.config['OPENAPI_VERSION'] = openapi_version
        api = Api(app)
        blp = Blueprint('test', 'test', url_prefix='/test')

        examples = {
            'example 1': {'summary': 'Example 1', 'value': {'name': 'One'}},
            'example 2': {'summary': 'Example 2', 'value': {'name': 'Two'}},
        }

        @blp.route('/')
        @blp.response(examples=examples)
        def func():
            pass

        api.register_blueprint(blp)

        get = api.spec.to_dict()['paths']['/test/']['get']
        assert (
            get['responses']['200']['content']['application/json']['examples']
            == examples
        )
示例#7
0
    def test_blueprint_response_example(self, app, openapi_version):
        app.config['OPENAPI_VERSION'] = openapi_version
        api = Api(app)
        blp = Blueprint('test', 'test', url_prefix='/test')

        example = {'name': 'One'}

        @blp.route('/')
        @blp.response(example=example)
        def func():
            pass

        api.register_blueprint(blp)

        get = api.spec.to_dict()['paths']['/test/']['get']
        if openapi_version == '2.0':
            assert get['responses']['200']['examples']['application/json'] == example
        else:
            assert (
                get['responses']['200']['content']['application/json']['example']
                == example
            )
示例#8
0
    def test_blueprint_doc_merged_after_prepare_doc(self, app):
        app.config['OPENAPI_VERSION'] = '3.0.2'
        api = Api(app)
        blp = Blueprint('test', __name__, url_prefix='/test')

        doc_example = {
            'content': {
                'application/json': {
                    'example': {
                        'test': 123
                    }
                }
            }
        }

        class ItemSchema(ma.Schema):
            test = ma.fields.Int()

        @blp.route('/')
        class Resource(MethodView):
            @blp.doc(**{'requestBody': doc_example})
            @blp.doc(**{'responses': {'200': doc_example}})
            @blp.arguments(ItemSchema)
            @blp.response(ItemSchema)
            def get(self):
                pass

        api.register_blueprint(blp)
        spec = api.spec.to_dict()
        get = spec['paths']['/test/']['get']
        print(get)
        assert get['requestBody']['content']['application/json'][
            'example'] == {
                'test': 123
            }
        assert get['responses']['200']['content']['application/json'][
            'example'] == {
                'test': 123
            }
示例#9
0
    def test_api_register_field(self, app, view_type, mapping):
        api = Api(app)
        blp = Blueprint('test', 'test', url_prefix='/test')

        class CustomField(ma.fields.Field):
            pass

        api.register_field(CustomField, *mapping)

        class Document(ma.Schema):
            field = CustomField()

        if view_type == 'function':
            @blp.route('/')
            @blp.arguments(Document)
            def test_func(args):
                return jsonify(None)
        else:
            @blp.route('/')
            class TestMethod(MethodView):
                @blp.arguments(Document)
                def get(self, args):
                    return jsonify(None)

        api.register_blueprint(blp)
        spec = api.spec.to_dict()

        if len(mapping) == 2:
            properties = {'field': {'type': 'custom string'}}
            # If mapping format is None, it does not appear in the spec
            if mapping[1] is not None:
                properties['field']['format'] = mapping[1]
        else:
            properties = {'field': {'type': 'integer', 'format': 'int32'}}

        assert (spec['paths']['/test/']['get']['parameters'] ==
                [{'in': 'body', 'required': True, 'name': 'body',
                  'schema': {'properties': properties, 'type': 'object'}, }])
示例#10
0
    def test_api_register_converter(self, app, view_type, custom_format, name):
        api = Api(app)
        blp = Blueprint('test', 'test', url_prefix='/test')

        class CustomConverter(BaseConverter):
            pass

        app.url_map.converters['custom_str'] = CustomConverter
        api.register_converter(
            CustomConverter, 'custom string', custom_format, name=name)

        if view_type == 'function':
            @blp.route('/<custom_str:val>')
            def test_func(val):
                return jsonify(val)
        else:
            @blp.route('/<custom_str:val>')
            class TestMethod(MethodView):
                def get(self, val):
                    return jsonify(val)

        api.register_blueprint(blp)
        spec = api.spec.to_dict()

        # If custom_format is None (default), it does not appear in the spec
        if custom_format is not None:
            parameters = [{'in': 'path', 'name': 'val', 'required': True,
                           'type': 'custom string', 'format': 'custom'}]
        else:
            parameters = [{'in': 'path', 'name': 'val', 'required': True,
                           'type': 'custom string'}]
        assert spec['paths']['/test/{val}']['get']['parameters'] == parameters

        # Converter is registered in the app iff name it not None
        if name is not None:
            assert api._app.url_map.converters[name] == CustomConverter
        else:
            assert name not in api._app.url_map.converters
    def test_blueprint_doc_method_view(self, app):
        api = Api(app)
        blp = Blueprint('test', __name__, url_prefix='/test')

        @blp.route('/')
        class Resource(MethodView):
            @blp.doc(summary='Dummy put', description='Do dummy put')
            def put(self):
                pass

            @blp.doc(summary='Dummy patch', description='Do dummy patch')
            def patch(self):
                pass

        api.register_blueprint(blp)
        spec = api.spec.to_dict()
        path = spec['paths']['/test/']
        for method in (
                'put',
                'patch',
        ):
            assert path[method]['summary'] == 'Dummy {}'.format(method)
            assert path[method]['description'] == 'Do dummy {}'.format(method)
示例#12
0
    def test_blueprint_arguments_location(
        self, app, schemas, location_map, openapi_version
    ):
        app.config['OPENAPI_VERSION'] = openapi_version
        api = Api(app)
        blp = Blueprint('test', __name__, url_prefix='/test')
        location, openapi_location = location_map

        if location is not None:

            @blp.route('/')
            @blp.arguments(schemas.DocSchema, location=location)
            def func():
                """
                Dummy view func.
                """

        else:

            @blp.route('/')
            @blp.arguments(schemas.DocSchema)
            def func():
                """
                Dummy view func.
                """

        api.register_blueprint(blp)
        spec = api.spec.to_dict()
        get = spec['paths']['/test/']['get']
        if openapi_location not in ('body', 'formData') or openapi_version == '2.0':
            loc = get['parameters'][0]['in']
            assert loc == openapi_location
            assert 'requestBody' not in get
        else:
            # In OpenAPI v3, 'body' parameter is in 'requestBody'
            assert 'parameters' not in get
            assert 'requestBody' in get
示例#13
0
def pagination_blueprint(collection, schemas, as_method_view, custom_params):
    """Return a basic API sample with pagination"""

    DocSchema = schemas.DocSchema

    blp = Blueprint('test', __name__, url_prefix='/test')

    if custom_params:
        page, page_size, max_page_size = CUSTOM_PAGINATION_PARAMS
    else:
        page, page_size, max_page_size = None, None, None

    if as_method_view:

        @blp.route('/')
        class Resource(MethodView):
            @blp.response(DocSchema(many=True))
            @blp.paginate(page=page,
                          page_size=page_size,
                          max_page_size=max_page_size)
            def get(self, pagination_parameters):
                pagination_parameters.item_count = len(collection.items)
                return collection.items[pagination_parameters.first_item:
                                        pagination_parameters.last_item + 1]
    else:

        @blp.route('/')
        @blp.response(DocSchema(many=True))
        @blp.paginate(page=page,
                      page_size=page_size,
                      max_page_size=max_page_size)
        def get_resources(pagination_parameters):
            pagination_parameters.item_count = len(collection.items)
            return collection.items[pagination_parameters.first_item:
                                    pagination_parameters.last_item + 1]

    return blp
示例#14
0
    def test_api_register_converter(self, app, view_type, custom_format,
                                    openapi_version):
        api = Api(app)
        blp = Blueprint('test', 'test', url_prefix='/test')

        class CustomConverter(BaseConverter):
            pass

        app.url_map.converters['custom_str'] = CustomConverter
        api.register_converter(CustomConverter, 'custom string', custom_format)

        if view_type == 'function':

            @blp.route('/<custom_str:val>')
            def test_func(val):
                return jsonify(val)

        else:

            @blp.route('/<custom_str:val>')
            class TestMethod(MethodView):
                def get(self, val):
                    return jsonify(val)

        api.register_blueprint(blp)
        spec = api.spec.to_dict()

        schema = {'type': 'custom string'}
        # If custom_format is None (default), it does not appear in the spec
        if custom_format is not None:
            schema['format'] = 'custom'
        parameter = {'in': 'path', 'name': 'val', 'required': True}
        if 'openapi_version' == '2.0':
            parameter.update(schema)
        else:
            parameter['schema'] = schema
        assert spec['paths']['/test/{val}']['parameters'] == [parameter]
    def test_blueprint_route_path_parameter_default(self, app, as_method_view):
        api = Api(app)
        blp = Blueprint('test', __name__, url_prefix='/test')

        if as_method_view:

            @blp.route('/<int:user_id>')
            @blp.route('/', defaults={'user_id': 1})
            class Resource(MethodView):
                def get(self, user_id):
                    pass

        else:

            @blp.route('/<int:user_id>')
            @blp.route('/', defaults={'user_id': 1})
            def func(user_id):
                pass

        api.register_blueprint(blp)
        paths = api.spec.to_dict()['paths']

        assert 'parameters' not in paths['/test/']
        assert paths['/test/{user_id}']['parameters'][0]['name'] == 'user_id'
    def test_blueprint_response_tuple(self, app):
        api = Api(app)
        blp = Blueprint('test', __name__, url_prefix='/test')
        client = app.test_client()

        @blp.route('/response')
        @blp.response()
        def func_response():
            return {}

        @blp.route('/response_code_int')
        @blp.response()
        def func_response_code_int():
            return {}, 201

        @blp.route('/response_code_str')
        @blp.response()
        def func_response_code_str():
            return {}, '201 CREATED'

        @blp.route('/response_headers')
        @blp.response()
        def func_response_headers():
            return {}, {'X-header': 'test'}

        @blp.route('/response_code_int_headers')
        @blp.response()
        def func_response_code_int_headers():
            return {}, 201, {'X-header': 'test'}

        @blp.route('/response_code_str_headers')
        @blp.response()
        def func_response_code_str_headers():
            return {}, '201 CREATED', {'X-header': 'test'}

        @blp.route('/response_wrong_tuple')
        @blp.response()
        def func_response_wrong_tuple():
            return {}, 201, {'X-header': 'test'}, 'extra'

        @blp.route('/response_tuple_subclass')
        @blp.response()
        def func_response_tuple_subclass():
            class MyTuple(tuple):
                pass

            return MyTuple((1, 2))

        api.register_blueprint(blp)

        response = client.get('/test/response')
        assert response.status_code == 200
        assert response.json == {}
        response = client.get('/test/response_code_int')
        assert response.status_code == 201
        assert response.status == '201 CREATED'
        assert response.json == {}
        response = client.get('/test/response_code_str')
        assert response.status_code == 201
        assert response.status == '201 CREATED'
        assert response.json == {}
        response = client.get('/test/response_headers')
        assert response.status_code == 200
        assert response.json == {}
        assert response.headers['X-header'] == 'test'
        response = client.get('/test/response_code_int_headers')
        assert response.status_code == 201
        assert response.status == '201 CREATED'
        assert response.json == {}
        assert response.headers['X-header'] == 'test'
        response = client.get('/test/response_code_str_headers')
        assert response.status_code == 201
        assert response.status == '201 CREATED'
        assert response.json == {}
        assert response.headers['X-header'] == 'test'
        response = client.get('/test/response_wrong_tuple')
        assert response.status_code == 500
        response = client.get('/test/response_tuple_subclass')
        assert response.status_code == 200
        assert response.json == [1, 2]
示例#17
0
文件: user.py 项目: sheenamt/batchman
from flask import jsonify, current_app
from flask.views import MethodView
from flask_rest_api import Blueprint, abort

from app import db
from app.auth import get_jwt_identity, get_jwt_groups

UserApi = Blueprint('UserApi',
                    __name__,
                    description='Endpoints for batchman user management.')


@UserApi.route('/profile')
class Profile(MethodView):
    def get(self):
        defined_workgroups = current_app.config["WORKGROUPS"].keys()
        user_groups = get_jwt_groups()
        intersection = list(set(defined_workgroups) & set(user_groups))
        workgroups = map(
            lambda g: {
                "display_name":
                current_app.config["WORKGROUPS"][g].get("DISPLAY_NAME", g),
                "name":
                g,
                "default_work_dir":
                current_app.config["WORKGROUPS"][g].get(
                    "NEXTFLOW_S3_WORK_DIR", ""),
                "default_profile":
                current_app.config["WORKGROUPS"][g].get(
                    "NEXTFLOW_DEFAULT_PROFILE", ""),
            }, intersection)
示例#18
0
def app_with_etag(request, collection, schemas, app):
    """Return a basic API sample with ETag"""

    as_method_view = request.param
    DocSchema = schemas.DocSchema
    DocEtagSchema = schemas.DocEtagSchema
    blp = Blueprint('test', __name__, url_prefix='/test')

    if as_method_view:
        @blp.route('/')
        class Resource(MethodView):

            @blp.etag(DocEtagSchema(many=True))
            @blp.response(
                DocSchema(many=True))
            def get(self):
                return collection.items

            @blp.etag(DocEtagSchema)
            @blp.arguments(DocSchema)
            @blp.response(DocSchema, code=201)
            def post(self, new_item):
                return collection.post(new_item)

        @blp.route('/<int:item_id>')
        class ResourceById(MethodView):

            def _get_item(self, item_id):
                try:
                    return collection.get_by_id(item_id)
                except ItemNotFound:
                    abort(404)

            @blp.etag(DocEtagSchema)
            @blp.response(DocSchema)
            def get(self, item_id):
                return self._get_item(item_id)

            @blp.etag(DocEtagSchema)
            @blp.arguments(DocSchema)
            @blp.response(DocSchema)
            def put(self, new_item, item_id):
                item = self._get_item(item_id)
                blp.check_etag(item, DocEtagSchema)
                return collection.put(item_id, new_item)

            @blp.etag(DocEtagSchema)
            @blp.response(code=204)
            def delete(self, item_id):
                item = self._get_item(item_id)
                blp.check_etag(item, DocEtagSchema)
                del collection.items[collection.items.index(item)]

    else:
        @blp.route('/')
        @blp.etag(DocEtagSchema(many=True))
        @blp.response(DocSchema(many=True))
        def get_resources():
            return collection.items

        @blp.route('/', methods=('POST',))
        @blp.etag(DocEtagSchema)
        @blp.arguments(DocSchema)
        @blp.response(DocSchema, code=201)
        def post_resource(new_item):
            return collection.post(new_item)

        def _get_item(item_id):
            try:
                return collection.get_by_id(item_id)
            except ItemNotFound:
                abort(404)

        @blp.route('/<int:item_id>')
        @blp.etag(DocEtagSchema)
        @blp.response(DocSchema)
        def get_resource(item_id):
            return _get_item(item_id)

        @blp.route('/<int:item_id>', methods=('PUT',))
        @blp.etag(DocEtagSchema)
        @blp.arguments(DocSchema)
        @blp.response(DocSchema)
        def put_resource(new_item, item_id):
            item = _get_item(item_id)
            blp.check_etag(item)
            return collection.put(item_id, new_item)

        @blp.route('/<int:item_id>', methods=('DELETE',))
        @blp.etag(DocEtagSchema)
        @blp.response(code=204)
        def delete_resource(item_id):
            item = _get_item(item_id)
            blp.check_etag(item)
            del collection.items[collection.items.index(item)]

    api = Api(app)
    api.register_blueprint(blp)

    return app
示例#19
0
from flask_login import logout_user
from phonenumbers import NumberParseException

from .schemas import CheckUserIdentificationParameters
from .schemas import CreateAuthClientParameters
from .schemas import RegisterClientParameters
from .schemas import ResetPasswordParameters
from app.extensions import db
from app.resources.users.models import User
from app.services.tencent.id_ocr import tencent_ocr
from flask_rest_api import Blueprint

log = logging.getLogger(__name__)

bp = Blueprint('auth',
               'auth',
               url_prefix='/auth',
               description='Authentication Related API')


@bp.route('/phone_exist/<phone_num>')
class PhoneExist(MethodView):
    """
    Check if phone number is registered.
    """
    @bp.response(code=200)
    @bp.response(code=404, description='Validation Error')
    def get(self, phone_num):
        user = User.query.filter_by(username=phone_num).first()

        log.debug('checking if user <%s> exists', phone_num)
示例#20
0
def create_app_mock(config_cls=None):
    """Return a basic API sample"""
    class AlbumSchema(ma.Schema):
        """Album resource schema"""
        class Meta:
            """Album schema Meta properties"""
            strict = True

        id = ma.fields.Integer()
        name = ma.fields.String()

        # Smart hyperlinking, hateoas style !
        _links = ma_hateoas.Hyperlinks(
            schema={
                'self':
                ma_hateoas.UrlFor(endpoint='albums.AlbumResourceById',
                                  album_id='<id>'),
                'collection':
                ma_hateoas.UrlFor(endpoint='albums.AlbumResources')
            })
        _embedded = ma_hateoas.Hyperlinks(
            schema={
                'songs': {
                    '_links': {
                        'collection':
                        ma_hateoas.UrlFor(endpoint='songs.SongResources',
                                          album_id='<id>')
                    }
                }
            })

    blp_albums = Blueprint('albums', __name__, url_prefix='/albums')

    @blp_albums.route('/')
    class AlbumResources(MethodView):
        """Album resources endpoints"""
        @blp_albums.arguments(AlbumSchema, location='query')
        @blp_albums.response(AlbumSchema(many=True))
        @blp_albums.paginate(Page)
        def get(self, args):
            """Return a list of resources"""
            album_datas = [{
                'id': 0,
                'name': 'Freak Out!'
            }, {
                'id': 1,
                'name': 'Absolutely Free'
            }]
            return album_datas

        @blp_albums.arguments(AlbumSchema)
        @blp_albums.response(AlbumSchema, code=201)
        def post(self, new_item):
            """Create and return a resource"""
            return new_item

    @blp_albums.route('/<int:album_id>')
    class AlbumResourceById(MethodView):
        """Album resource endpoints"""
        @blp_albums.response(AlbumSchema)
        def get(self, album_id):
            """Return a resource from its ID"""
            album_data = {'id': album_id, 'name': 'Freak Out!'}
            return album_data

    class SongSchema(ma.Schema):
        """Song resource schema"""
        class Meta:
            """Song schema Meta properties"""
            strict = True

        id = ma.fields.Integer()
        name = ma.fields.String()
        album_id = ma.fields.Integer()

        # Smart hyperlinking, hateoas style !
        _links = ma_hateoas.Hyperlinks({
            'self':
            ma_hateoas.UrlFor(endpoint='songs.SongResourceById',
                              song_id='<id>'),
            'collection':
            ma_hateoas.UrlFor(endpoint='songs.SongResources'),
            'parent':
            ma_hateoas.UrlFor(endpoint='albums.AlbumResourceById',
                              album_id='<album_id>')
        })

    blp_songs = Blueprint('songs', __name__, url_prefix='/songs')

    @blp_songs.route('/')
    class SongResources(MethodView):
        """Song resources endpoints"""
        @blp_songs.arguments(SongSchema, location='query')
        @blp_songs.response(SongSchema(many=True))
        @blp_songs.paginate(Page)
        def get(self, args):
            """Return a list of resources"""
            song_datas = [{
                'id': 0,
                'name': 'Hungry Freaks Daddy',
                'album_id': 0
            }, {
                'id': 1,
                'name': 'I Ain\'t Got No Heart',
                'album_id': 0
            }]
            return song_datas

        @blp_songs.arguments(SongSchema)
        @blp_songs.response(SongSchema, code=201)
        def post(self, new_item):
            """Create and return a resource"""
            return new_item

    @blp_songs.route('/<int:song_id>')
    class SongResourceById(MethodView):
        """Song resource endpoints"""
        @blp_songs.response(SongSchema)
        def get(self, song_id):
            """Return a resource from its ID"""
            song_data = {
                'id': song_id,
                'name': 'Hungry Freaks Daddy',
                'album_id': 0
            }
            return song_data

    app = Flask('API Test')
    app.response_class = JSONResponse
    if config_cls:
        app.config.from_object(config_cls)
    api = Api(app)
    api.register_blueprint(blp_albums)
    api.register_blueprint(blp_songs)

    return app
示例#21
0
    pets = f.Nested("PetSchemaLite", many=True, exclude=("human", ))
    not_allowed = f.String(load_only=True)  # disallowed for create


class PetSchemaLite(Schema):
    id = f.Integer(dump_only=True)  # not editable
    genus = f.String()
    species = f.String()
    human = f.Nested(HumanSchema, exclude=("pets", ))


class PetSchema(PetSchemaLite):
    edible = f.Boolean()


pet_blp = Blueprint("pets", "pets", url_prefix="/pet")


@pet_blp.route("")
class PetCollection(CollectionView):
    model = Pet
    prefetch = [Pet.human, (Pet.human, Human.cars)]  # joinedload
    access_checks_enabled = False

    create_enabled = True
    list_enabled = True

    def get(self):
        query = super().get()

        # check prefetch worked
示例#22
0
from flask_jwt_extended import (
    create_access_token,
    create_refresh_token,
    get_jwt_identity,
    jwt_refresh_token_required,
    set_access_cookies,
    set_refresh_cookies,
    unset_jwt_cookies
)
from flask_rest_api import Blueprint, abort
from flask_security.utils import verify_password, hash_password

from ..models.auth import User
from ..schemas.auth import LoginSchema, RefreshSchema, TokenSchema, UserSchema

blueprint = Blueprint('auth', 'auth')


@blueprint.route('/login', endpoint='auth_login')
class AuthLoginAPI(MethodView):
    @blueprint.response(LoginSchema)
    @blueprint.arguments(TokenSchema)
    def post(self, args):
        """Authenticates and generates a token"""
        email = args.get('email', None)
        password = args.get('password', None)
        if email is None:
            abort(403, message='Email not provided')
        try:
            user = User.get(email=email)
        except User.DoesNotExist:
    def test_blueprint_pagination_response_tuple(self, app):
        api = Api(app)
        blp = Blueprint('test', __name__, url_prefix='/test')
        client = app.test_client()

        @blp.route('/response')
        @blp.response()
        @blp.paginate(Page)
        def func_response():
            return [1, 2]

        @blp.route('/response_code')
        @blp.response()
        @blp.paginate(Page)
        def func_response_code():
            return [1, 2], 201

        @blp.route('/response_headers')
        @blp.response()
        @blp.paginate(Page)
        def func_response_headers():
            return [1, 2], {'X-header': 'test'}

        @blp.route('/response_code_headers')
        @blp.response()
        @blp.paginate(Page)
        def func_response_code_headers():
            return [1, 2], 201, {'X-header': 'test'}

        @blp.route('/response_wrong_tuple')
        @blp.response()
        @blp.paginate(Page)
        def func_response_wrong_tuple():
            return [1, 2], 201, {'X-header': 'test'}, 'extra'

        @blp.route('/response_tuple_subclass')
        @blp.response()
        @blp.paginate(Page)
        def func_response_tuple_subclass():
            class MyTuple(tuple):
                pass

            return MyTuple((1, 2))

        api.register_blueprint(blp)

        response = client.get('/test/response')
        assert response.status_code == 200
        assert response.json == [1, 2]
        response = client.get('/test/response_code')
        assert response.status_code == 201
        assert response.json == [1, 2]
        response = client.get('/test/response_headers')
        assert response.status_code == 200
        assert response.json == [1, 2]
        assert response.headers['X-header'] == 'test'
        response = client.get('/test/response_code_headers')
        assert response.status_code == 201
        assert response.json == [1, 2]
        assert response.headers['X-header'] == 'test'
        response = client.get('/test/response_wrong_tuple')
        assert response.status_code == 500
        response = client.get('/test/response_tuple_subclass')
        assert response.status_code == 200
        assert response.json == [1, 2]
def explicit_data_no_schema_etag_blueprint(collection, schemas):
    """Blueprint with explicit ETag computation, no schema

    ETag computed without schema from arbitrary data

    We're using item['db_field'] for ETag data as a dummy example.
    """

    DocSchema = schemas.DocSchema

    blp = Blueprint('test', __name__, url_prefix='/test')

    @blp.route('/')
    class Resource(MethodView):

        @blp.etag
        @blp.response(DocSchema(many=True))
        @blp.paginate()
        def get(self, pagination_parameters):
            pagination_parameters.item_count = len(collection.items)
            # It is better to rely on automatic ETag here, as it includes
            # pagination metadata.
            return collection.items[
                pagination_parameters.first_item:
                pagination_parameters.last_item + 1
            ]

        @blp.etag
        @blp.arguments(DocSchema)
        @blp.response(DocSchema)
        def post(self, new_item):
            # Compute ETag using arbitrary data and no schema
            blp.set_etag(new_item['db_field'])
            return collection.post(new_item)

    @blp.route('/<int:item_id>')
    class ResourceById(MethodView):

        def _get_item(self, item_id):
            try:
                return collection.get_by_id(item_id)
            except ItemNotFound:
                abort(404)

        @blp.etag
        @blp.response(DocSchema)
        def get(self, item_id):
            item = self._get_item(item_id)
            # Compute ETag using arbitrary data and no schema
            blp.set_etag(item['db_field'])
            return item

        @blp.etag
        @blp.arguments(DocSchema)
        @blp.response(DocSchema)
        def put(self, new_item, item_id):
            item = self._get_item(item_id)
            # Check ETag is a manual action, no shema used
            blp.check_etag(item['db_field'])
            new_item = collection.put(item_id, new_item)
            # Compute ETag using arbitrary data and no schema
            blp.set_etag(new_item['db_field'])
            return new_item

        @blp.etag
        @blp.response(code=204)
        def delete(self, item_id):
            item = self._get_item(item_id)
            # Check ETag is a manual action, no shema used
            blp.check_etag(item['db_field'])
            collection.delete(item_id)

    return blp
示例#25
0
    def test_etag_check_etag(self, app, schemas, etag_disabled):
        app.config['ETAG_DISABLED'] = etag_disabled
        blp = Blueprint('test', __name__)
        etag_schema = schemas.DocEtagSchema
        old_item = {'item_id': 1, 'db_field': 0}
        new_item = {'item_id': 1, 'db_field': 1}
        old_etag = blp._generate_etag(old_item)
        old_etag_with_schema = blp._generate_etag(old_item, etag_schema)

        with app.test_request_context('/', headers={'If-Match': old_etag}):
            blp.check_etag(old_item)
            if not etag_disabled:
                with pytest.raises(PreconditionFailed):
                    blp.check_etag(new_item)
            else:
                blp.check_etag(new_item)
        with app.test_request_context(
                '/', headers={'If-Match': old_etag_with_schema}):
            blp.check_etag(old_item, etag_schema)
            if not etag_disabled:
                with pytest.raises(PreconditionFailed):
                    blp.check_etag(new_item, etag_schema)
            else:
                blp.check_etag(new_item)
def implicit_data_explicit_schema_etag_blueprint(collection, schemas):
    """Blueprint with implicit ETag computation, explicit schema

    ETag computed automatically with specific ETag schema
    """

    DocSchema = schemas.DocSchema
    DocEtagSchema = schemas.DocEtagSchema

    blp = Blueprint('test', __name__, url_prefix='/test')

    @blp.route('/')
    class Resource(MethodView):

        @blp.etag(DocEtagSchema(many=True))
        @blp.response(DocSchema(many=True))
        @blp.paginate()
        def get(self, pagination_parameters):
            pagination_parameters.item_count = len(collection.items)
            return collection.items[
                pagination_parameters.first_item:
                pagination_parameters.last_item + 1
            ]

        @blp.etag(DocEtagSchema)
        @blp.arguments(DocSchema)
        @blp.response(DocSchema)
        def post(self, new_item):
            return collection.post(new_item)

    @blp.route('/<int:item_id>')
    class ResourceById(MethodView):

        def _get_item(self, item_id):
            try:
                return collection.get_by_id(item_id)
            except ItemNotFound:
                abort(404)

        @blp.etag(DocEtagSchema)
        @blp.response(DocSchema)
        def get(self, item_id):
            item = self._get_item(item_id)
            return item

        @blp.etag(DocEtagSchema)
        @blp.arguments(DocSchema)
        @blp.response(DocSchema)
        def put(self, new_item, item_id):
            item = self._get_item(item_id)
            # Check ETag is a manual action, ETag schema is used
            blp.check_etag(item)
            new_item = collection.put(item_id, new_item)
            return new_item

        @blp.etag(DocEtagSchema)
        @blp.response(code=204)
        def delete(self, item_id):
            item = self._get_item(item_id)
            # Check ETag is a manual action, ETag schema is used
            blp.check_etag(item)
            collection.delete(item_id)

    return blp
示例#27
0
    def test_etag_set_etag(self, app, schemas, etag_disabled):
        app.config['ETAG_DISABLED'] = etag_disabled
        blp = Blueprint('test', __name__)
        etag_schema = schemas.DocEtagSchema
        item = {'item_id': 1, 'db_field': 0}
        etag = blp._generate_etag(item)
        etag_with_schema = blp._generate_etag(item, etag_schema)

        with app.test_request_context('/'):
            blp.set_etag(item)
            if not etag_disabled:
                assert _get_etag_ctx()['etag'] == etag
                del _get_etag_ctx()['etag']
            else:
                assert 'etag' not in _get_etag_ctx()
        with app.test_request_context(
                '/', headers={'If-None-Match': etag}):
            if not etag_disabled:
                with pytest.raises(NotModified):
                    blp.set_etag(item)
            else:
                blp.set_etag(item)
                assert 'etag' not in _get_etag_ctx()
        with app.test_request_context(
                '/', headers={'If-None-Match': etag_with_schema}):
            if not etag_disabled:
                with pytest.raises(NotModified):
                    blp.set_etag(item, etag_schema)
            else:
                blp.set_etag(item, etag_schema)
                assert 'etag' not in _get_etag_ctx()
        with app.test_request_context(
                '/', headers={'If-None-Match': 'dummy'}):
            if not etag_disabled:
                blp.set_etag(item)
                assert _get_etag_ctx()['etag'] == etag
                del _get_etag_ctx()['etag']
                blp.set_etag(item, etag_schema)
                assert _get_etag_ctx()['etag'] == etag_with_schema
                del _get_etag_ctx()['etag']
            else:
                blp.set_etag(item)
                assert 'etag' not in _get_etag_ctx()
                blp.set_etag(item, etag_schema)
                assert 'etag' not in _get_etag_ctx()
示例#28
0
from flask_rest_api import Blueprint, abort
from flask_security.utils import hash_password

from ..models.auth import User
from ..schemas.auth import UserSchema
from ..schemas.paging import PageInSchema, PageOutSchema, paginate
from .methodviews import ProtectedMethodView

blueprint = Blueprint('user', 'user')


@blueprint.route('', endpoint='users')
class UserListAPI(ProtectedMethodView):
    @blueprint.arguments(PageInSchema(), location='headers')
    @blueprint.response(PageOutSchema(UserSchema))
    def get(self, pagination):
        """List users"""
        return paginate(User.select(), pagination)

    @blueprint.arguments(UserSchema)
    @blueprint.response(UserSchema)
    def post(self, args):
        """Create user"""
        user = User(**args)
        user.password = hash_password(user.password)
        user.save()
        return user


@blueprint.route('/<user_id>', endpoint='user')
class UserAPI(ProtectedMethodView):
示例#29
0
from http import HTTPStatus
from flask import request, g
from werkzeug.wrappers import Response
from app.models.Pair import PairModel, PairSchema
from app.shared.ipLimitIntercept import IpLimitIntercept
import json

from flask_rest_api import Blueprint
pair_api = Blueprint('pair_api', __name__, url_prefix="/pair")

pair_schema = PairSchema()


@pair_api.route('/', methods=['POST'])
@IpLimitIntercept.ip_limit_intercept
def create(*args, **kwargs):
    """
    Create Pair Function
    """
    req_data = request.get_json()
    data = pair_schema.load(req_data)
    
    error = None
    if error:
        return custom_response(error, HTTPStatus.BAD_REQUEST)

    # check if user already exist in the db
    pair_in_db = PairModel.get_one_pair(data)
    if pair_in_db:
        message = {'error': 'ERR_PAIR_ALREADY_EXISTED'}
        return custom_response(message, HTTPStatus.BAD_REQUEST)
示例#30
0
from . import utils

pages = FlaskBlueprint('pages', __name__)


# https://github.com/Nobatek/flask-rest-api/issues/51
class Api(_Api):
    def handle_http_exception(self, error):
        # Don't serialize redirects
        if isinstance(error, RoutingException):
            return error
        return super().handle_http_exception(error)


api_class = Api()
api = Blueprint("api", __name__, description="All API.")
api_datapoint = Blueprint("DataPoints",
                          __name__,
                          description="CRUD datapoint(s)")
api_metric = Blueprint("Metrics", __name__, description="CRUD metric(s)")

# Make sure all pages show our version.
render_template = partial(_render_template, version=__version__)


@api_class.definition("Metrics")
class MetricSchema(ModelSchema):
    class Meta:
        model = orm.Metric