def create_api_blueprint(self, model=None, collection_name=None, app=None, methods=READONLY_METHODS, url_prefix='/api', exclude_columns=None, include_columns=None, include_methods=None, results_per_page=10, max_results_per_page=100, preprocess=None, postprocess=None, primary_key=None, *args, **kw): if collection_name is None: msg = ('collection_name is not valid.') raise IllegalArgumentError(msg) if exclude_columns is not None and include_columns is not None: msg = ('Cannot simultaneously specify both include columns and' ' exclude columns.') raise IllegalArgumentError(msg) if app is None: app = self.app restapi_ext = app.extensions[self.name] methods = frozenset((m.upper() for m in methods)) no_instance_methods = methods & frozenset(('POST', )) instance_methods = methods & frozenset(('GET', 'PATCH', 'DELETE', 'PUT')) possibly_empty_instance_methods = methods & frozenset(('GET', )) # the base URL of the endpoints on which requests will be made collection_endpoint = '/{0}'.format(collection_name) apiname = APIManager.api_name(collection_name) preprocessors_ = defaultdict(list) postprocessors_ = defaultdict(list) preprocessors_.update(preprocess or {}) postprocessors_.update(postprocess or {}) api_view = self.view_cls.as_view(model=model, collection_name=collection_name,exclude_columns=exclude_columns,\ include_columns=include_columns, include_methods=include_methods,\ results_per_page=results_per_page, max_results_per_page=max_results_per_page, \ preprocess=preprocessors_, postprocess=postprocessors_, primary_key=primary_key,\ db=restapi_ext.db) blueprintname = APIManager._next_blueprint_name(app.blueprints, apiname) blueprint = Blueprint(blueprintname, url_prefix=url_prefix) blueprint.add_route(api_view,collection_endpoint,methods=no_instance_methods) #DELETE, GET, PUT instance_endpoint = '{0}/<instid>'.format(collection_endpoint) blueprint.add_route(api_view,instance_endpoint,methods=instance_methods) return blueprint
def create_api_blueprint(self, model=None, collection_name=None, app=None, methods=READONLY_METHODS, url_prefix='/api', exclude_columns=None, include_columns=None, include_methods=None, results_per_page=10, max_results_per_page=100, preprocess=None, postprocess=None, primary_key=None, *args, **kw): if collection_name is None: msg = ('collection_name is not valid.') raise IllegalArgumentError(msg) if exclude_columns is not None and include_columns is not None: msg = ('Cannot simultaneously specify both include columns and' ' exclude columns.') raise IllegalArgumentError(msg) if app is None: app = self.app restapi_ext = app.extensions[self.name] methods = frozenset((m.upper() for m in methods)) no_instance_methods = methods & frozenset(('POST', )) instance_methods = methods & frozenset( ('GET', 'PATCH', 'DELETE', 'PUT')) possibly_empty_instance_methods = methods & frozenset(('GET', )) # the base URL of the endpoints on which requests will be made collection_endpoint = '/{0}'.format(collection_name) apiname = APIManager.api_name(collection_name) preprocessors_ = defaultdict(list) postprocessors_ = defaultdict(list) preprocessors_.update(preprocess or {}) postprocessors_.update(postprocess or {}) api_view = self.view_cls.as_view(model=model, collection_name=collection_name, exclude_columns=exclude_columns, include_columns=include_columns, include_methods=include_methods, results_per_page=results_per_page, max_results_per_page=max_results_per_page, preprocess=preprocessors_, postprocess=postprocessors_, primary_key=primary_key, db=restapi_ext.db) blueprintname = APIManager._next_blueprint_name( app.blueprints, apiname) blueprint = Blueprint(blueprintname, url_prefix=url_prefix) blueprint.add_route(api_view, collection_endpoint, methods=no_instance_methods) #DELETE, GET, PUT instance_endpoint = '{0}/<instid>'.format(collection_endpoint) blueprint.add_route(api_view, instance_endpoint, methods=instance_methods) return blueprint
import os import random import string from gatco.response import json from gatco import Blueprint import aiofiles from application.server import app upload = Blueprint('image', url_prefix='/image') @upload.route('/') async def bp_root(request): return json({'image': 'blueprint'}) @upload.route('/upload', methods=['POST']) async def imgupload(request): ret = None url = app.config['IMAGE_SERVICE_URL'] fsroot = app.config['FS_ROOT'] if request.method == 'POST': file = request.files.get('image', None) if file: rand = ''.join(random.choice(string.digits) for _ in range(5)) file_name = os.path.splitext(file.name)[0] extname = os.path.splitext(file.name)[1] newfilename = file_name + "-" + rand + extname
from gatco.response import json from gatco import Blueprint from jinja2 import Environment, PackageLoader from goblin.extensions import jinja from goblin.server import app admin = Blueprint('admin', url_prefix='/admin') jinja.add_loader("admin", PackageLoader("goblin.admin", 'templates')) @admin.route('/') async def index(request): return jinja.render('admin/index.html', request) @admin.route('/login') async def login(request): return json({'my': 'login'}) @admin.route('/logout') async def logout(request): return json({'my': 'logout'})
from sqlalchemy.sql.expression import except_ import time from datetime import datetime from math import floor from application.client import HTTPClient from sqlalchemy import or_, and_, desc from application.extensions import auth import ujson # import xlrender # import xlrenderpy as xlrender from openpyxl import Workbook from openpyxl.styles import PatternFill, Border, Side, Alignment, Protection, Font from gatco import Blueprint exportbp = Blueprint('exportbp', url_prefix='/export') @exportbp.route('/me') async def me(request): return json({'my': 'blueprint'}) # @app.route('/exportexcel/test', methods=['GET']) # async def get_token(request): # filename = "test.xlsx" # deffile = "sample.json" # template = "sample.xlsx" # render = xlrender.xlrender(template, deffile) # data = { # "data": []
def create_api_blueprint(self, model, app=None, methods=READONLY_METHODS, url_prefix='/api', collection_name=None, allow_patch_many=False, allow_delete_many=False, allow_functions=False, exclude_columns=None, include_columns=None, include_methods=None, validation_exceptions=None, results_per_page=10, max_results_per_page=100, post_form_preprocessor=None, preprocess=None, postprocess=None, primary_key=None, serializer=None, deserializer=None): """Creates and returns a ReSTful API interface as a blueprint, but does not register it on any :class:`flask.Flask` application. The endpoints for the API for ``model`` will be available at ``<url_prefix>/<collection_name>``. If `collection_name` is ``None``, the lowercase name of the provided model class will be used instead, as accessed by ``model.__tablename__``. (If any black magic was performed on ``model.__tablename__``, this will be reflected in the endpoint URL.) For more information, see :ref:`collectionname`. This function must be called at most once for each model for which you wish to create a ReSTful API. Its behavior (for now) is undefined if called more than once. This function returns the :class:`flask.Blueprint` object which handles the endpoints for the model. The returned :class:`~flask.Blueprint` has already been registered with the :class:`~flask.Flask` application object specified in the constructor of this class, so you do *not* need to register it yourself. `model` is the SQLAlchemy model class for which a ReSTful interface will be created. Note this must be a class, not an instance of a class. `app` is the :class:`Flask` object on which we expect the blueprint created in this method to be eventually registered. If not specified, the Flask application specified in the constructor of this class is used. `methods` specify the HTTP methods which will be made available on the ReSTful API for the specified model, subject to the following caveats: * If :http:method:`get` is in this list, the API will allow getting a single instance of the model, getting all instances of the model, and searching the model using search parameters. * If :http:method:`patch` is in this list, the API will allow updating a single instance of the model, updating all instances of the model, and updating a subset of all instances of the model specified using search parameters. * If :http:method:`delete` is in this list, the API will allow deletion of a single instance of the model per request. * If :http:method:`post` is in this list, the API will allow posting a new instance of the model per request. The default set of methods provides a read-only interface (that is, only :http:method:`get` requests are allowed). `collection_name` is the name of the collection specified by the given model class to be used in the URL for the ReSTful API created. If this is not specified, the lowercase name of the model will be used. `url_prefix` the URL prefix at which this API will be accessible. If `allow_patch_many` is ``True``, then requests to :http:patch:`/api/<collection_name>?q=<searchjson>` will attempt to patch the attributes on each of the instances of the model which match the specified search query. This is ``False`` by default. For information on the search query parameter ``q``, see :ref:`searchformat`. If `allow_delete_many` is ``True``, then requests to :http:delete:`/api/<collection_name>?q=<searchjson>` will attempt to delete each instance of the model that matches the specified search query. This is ``False`` by default. For information on the search query parameter ``q``, see :ref:`searchformat`. `validation_exceptions` is the tuple of possible exceptions raised by validation of your database models. If this is specified, validation errors will be captured and forwarded to the client in JSON format. For more information on how to use validation, see :ref:`validation`. If `allow_functions` is ``True``, then requests to :http:get:`/api/eval/<collection_name>` will return the result of evaluating SQL functions specified in the body of the request. For information on the request format, see :ref:`functionevaluation`. This if ``False`` by default. Warning: you must not create an API for a model whose name is ``'eval'`` if you set this argument to ``True``. If either `include_columns` or `exclude_columns` is not ``None``, exactly one of them must be specified. If both are not ``None``, then this function will raise a :exc:`IllegalArgumentError`. `exclude_columns` must be an iterable of strings specifying the columns of `model` which will *not* be present in the JSON representation of the model provided in response to :http:method:`get` requests. Similarly, `include_columns` specifies the *only* columns which will be present in the returned dictionary. In other words, `exclude_columns` is a blacklist and `include_columns` is a whitelist; you can only use one of them per API endpoint. If either `include_columns` or `exclude_columns` contains a string which does not name a column in `model`, it will be ignored. If you attempt to either exclude a primary key field or not include a primary key field for :http:method:`post` requests, this method will raise an :exc:`IllegalArgumentError`. If `include_columns` is an iterable of length zero (like the empty tuple or the empty list), then the returned dictionary will be empty. If `include_columns` is ``None``, then the returned dictionary will include all columns not excluded by `exclude_columns`. If `include_methods` is an iterable of strings, the methods with names corresponding to those in this list will be called and their output included in the response. See :ref:`includes` for information on specifying included or excluded columns on fields of related models. `results_per_page` is a positive integer which represents the default number of results which are returned per page. Requests made by clients may override this default by specifying ``results_per_page`` as a query argument. `max_results_per_page` is a positive integer which represents the maximum number of results which are returned per page. This is a "hard" upper bound in the sense that even if a client specifies that greater than `max_results_per_page` should be returned, only `max_results_per_page` results will be returned. For more information, see :ref:`serverpagination`. .. deprecated:: 0.9.2 The `post_form_preprocessor` keyword argument is deprecated in version 0.9.2. It will be removed in version 1.0. Replace code that looks like this:: manager.create_api(Person, post_form_preprocessor=foo) with code that looks like this:: manager.create_api(Person, preprocess=dict(POST=[foo])) See :ref:`processors` for more information and examples. `post_form_preprocessor` is a callback function which takes POST input parameters loaded from JSON and enhances them with other key/value pairs. The example use of this is when your ``model`` requires to store user identity and for security reasons the identity is not read from the post parameters (where malicious user can tamper with them) but from the session. `preprocess` is a dictionary mapping strings to lists of functions. Each key is the name of an HTTP method (for example, ``'GET'`` or ``'POST'``). Each value is a list of functions, each of which will be called before any other code is executed when this API receives the corresponding HTTP request. The functions will be called in the order given here. The `postprocess` keyword argument is essentially the same, except the given functions are called after all other code. For more information on preprocess and postprocess, see :ref:`processors`. `primary_key` is a string specifying the name of the column of `model` to use as the primary key for the purposes of creating URLs. If the `model` has exactly one primary key, there is no need to provide a value for this. If `model` has two or more primary keys, you must specify which one to use. `serializer` and `deserializer` are custom serialization functions. The former function must take a single argument representing the instance of the model to serialize, and must return a dictionary representation of that instance. The latter function must take a single argument representing the dictionary representation of an instance of the model and must return an instance of `model` that has those attributes. For more information, see :ref:`serialization`. """ if exclude_columns is not None and include_columns is not None: msg = ('Cannot simultaneously specify both include columns and' ' exclude columns.') raise IllegalArgumentError(msg) # If no Flask application is specified, use the one (we assume) was # specified in the constructor. if app is None: app = self.app restlessinfo = app.extensions['restapi'] if collection_name is None: collection_name = model.__tablename__ # convert all method names to upper case methods = frozenset((m.upper() for m in methods)) # sets of methods used for different types of endpoints no_instance_methods = methods & frozenset(('POST', )) instance_methods = \ methods & frozenset(('GET', 'PATCH', 'DELETE', 'PUT')) possibly_empty_instance_methods = methods & frozenset(('GET', )) if allow_patch_many and ('PATCH' in methods or 'PUT' in methods): possibly_empty_instance_methods |= frozenset(('PATCH', 'PUT')) if allow_delete_many and 'DELETE' in methods: possibly_empty_instance_methods |= frozenset(('DELETE', )) # Check that primary_key is included for no_instance_methods if no_instance_methods: pk_name = primary_key or primary_key_name(model) if (include_columns and pk_name not in include_columns or exclude_columns and pk_name in exclude_columns): msg = ('The primary key must be included for APIs with POST.') raise IllegalArgumentError(msg) # the base URL of the endpoints on which requests will be made collection_endpoint = '/{0}'.format(collection_name) # the name of the API, for use in creating the view and the blueprint apiname = APIManager.api_name(collection_name) # Prepend the universal preprocess and postprocess specified in # the constructor of this class. preprocessors_ = defaultdict(list) postprocessors_ = defaultdict(list) preprocessors_.update(preprocess or {}) postprocessors_.update(postprocess or {}) for key, value in restlessinfo.universal_preprocess.items(): preprocessors_[key] = value + preprocessors_[key] for key, value in restlessinfo.universal_postprocess.items(): postprocessors_[key] = value + postprocessors_[key] # the view function for the API for this model #api_view = API.as_view(apiname, restlessinfo.session, model, # exclude_columns, include_columns, # include_methods, validation_exceptions, # results_per_page, max_results_per_page, # post_form_preprocessor, preprocessors_, # postprocessors_, primary_key, serializer, # deserializer) api_view = API.as_view(restlessinfo.session, model, exclude_columns, include_columns, include_methods, validation_exceptions, results_per_page, max_results_per_page, post_form_preprocessor, preprocessors_, postprocessors_, primary_key, serializer, deserializer) # suffix an integer to apiname according to already existing blueprints blueprintname = APIManager._next_blueprint_name( app.blueprints, apiname) # add the URL rules to the blueprint: the first is for methods on the # collection only, the second is for methods which may or may not # specify an instance, the third is for methods which must specify an # instance # TODO what should the second argument here be? # TODO should the url_prefix be specified here or in register_blueprint blueprint = Blueprint(blueprintname, url_prefix=url_prefix) # For example, /api/person. #POST --create POST item blueprint.add_route(api_view, collection_endpoint, methods=no_instance_methods) #blueprint.add_url_rule(collection_endpoint, # methods=no_instance_methods, view_func=api_view) # For example, /api/person/1. #GET #instance_endpoint = '{0}/<instid>/<relationname>/<relationinstid>'.format(collection_endpoint) #blueprint.add_route(api_view,instance_endpoint,methods=possibly_empty_instance_methods) #blueprint.add_url_rule(collection_endpoint, # defaults={'instid': None, 'relationname': None, # 'relationinstid': None}, # methods=possibly_empty_instance_methods, # view_func=api_view) # the per-instance endpoints will allow both integer and string primary # key accesses # For example, /api/person/1. #DELETE, GET, PUT instance_endpoint = '{0}/<instid>'.format(collection_endpoint) blueprint.add_route(api_view, instance_endpoint, methods=instance_methods) #blueprint.add_url_rule(instance_endpoint, methods=instance_methods, # defaults={'relationname': None, # 'relationinstid': None}, # view_func=api_view) # add endpoints which expose related models relation_endpoint = '{0}/<relationname>'.format(instance_endpoint) relation_instance_endpoint = \ '{0}/<relationinstid>'.format(relation_endpoint) # For example, /api/person/1/computers. #blueprint.add_url_rule(relation_endpoint, # methods=possibly_empty_instance_methods, # defaults={'relationinstid': None}, # view_func=api_view) # For example, /api/person/1/computers/2. #blueprint.add_url_rule(relation_instance_endpoint, # methods=instance_methods, # view_func=api_view) blueprint.add_route(api_view, relation_endpoint, methods=possibly_empty_instance_methods) blueprint.add_route(api_view, relation_instance_endpoint, methods=instance_methods) # if function evaluation is allowed, add an endpoint at /api/eval/... # which responds only to GET requests and responds with the result of # evaluating functions on all instances of the specified model if allow_functions: eval_api_name = apiname + 'eval' eval_api_view = FunctionAPI.as_view(eval_api_name, restlessinfo.session, model) eval_endpoint = '/eval' + collection_endpoint blueprint.add_url_rule(eval_endpoint, methods=['GET'], view_func=eval_api_view) # Finally, record that this APIManager instance has created an API for # the specified model. self.created_apis_for[model] = APIInfo(collection_name, blueprint.name) return blueprint