Example #1
0
def minimal_app(**config):
    app = Flask(__name__)
    app.wsgi_app = ProxyFix(app.wsgi_app)
    cors = CORS(app)
    cross_origin()

    @app.errorhandler(404)
    def page_not_found(e):
        # note that we set the 404 status explicitly
        return render_template('404.html'), 404

    configuration.init_app(app, **config)

    return app
Example #2
0
 def decorator(fn):
     cors_fn = flask_cors.cross_origin(automatic_options=False, *args, **kwargs)
     if inspect.isclass(fn):
         apply_function_to_members(fn, cors_fn)
     else:
         return cors_fn(fn)
     return fn
Example #3
0
        def decorator(func):
            endpoint = ns.endpoint_for(operation)
            endpoint_path = graph.build_route_path(path, ns.prefix)

            if enable_cors:
                func = cross_origin(supports_credentials=True)(func)

            if enable_basic_auth or ns.enable_basic_auth:
                func = graph.basic_auth.required(func)

            if enable_context_logger and ns.controller is not None:
                func = context_logger(
                    graph.request_context,
                    func,
                    parent=ns.controller,
                )

            # set the opaque component data_func to look at the flask request context
            func = graph.opaque.initialize(graph.request_context)(func)

            if graph.route_metrics.enabled:
                func = graph.route_metrics(endpoint)(func)

            # keep audit decoration last (before registering the route) so that
            # errors raised by other decorators are captured in the audit trail
            if enable_audit:
                func = graph.audit(func)

            graph.app.route(
                endpoint_path,
                endpoint=endpoint,
                methods=[operation.value.method],
            )(func)
            return func
Example #4
0
def main():
    parser = argparse.ArgumentParser(
        description='Meta Reverse Image Search API')
    parser.add_argument('-p',
                        '--port',
                        type=int,
                        default=5000,
                        help='port number')
    parser.add_argument('-d',
                        '--debug',
                        action='store_true',
                        help='enable debug mode')
    parser.add_argument('-c',
                        '--cors',
                        action='store_true',
                        default=False,
                        help="enable cross-origin requests")
    args = parser.parse_args()

    if args.debug:
        app.debug = True

    if args.cors:
        CORS(app, resources=r'/search/*')
        app.config['CORS_HEADERS'] = 'Content-Type'

        global search
        search = cross_origin(search)
        print(" * Running with CORS enabled")

    port = int(os.environ.get("PORT", 5000))
    app.run(host='0.0.0.0', port=port)
Example #5
0
class StreamNode(Resource):

    decorators = [cross_origin(origin='*')]

    def get(self, id):
        comp.run_dotbot_node()
        return Response(comp.read_run_proc(id), mimetype='text/event-stream')
        def decorator(func):
            endpoint = ns.endpoint_for(operation)
            endpoint_path = graph.build_route_path(path, ns.prefix)

            if enable_cors:
                func = cross_origin(supports_credentials=True)(func)

            if enable_basic_auth or ns.enable_basic_auth:
                func = graph.basic_auth.required(func)

            if enable_context_logger and ns.controller is not None:
                func = context_logger(
                    graph.request_context,
                    func,
                    parent=ns.controller,
                )

            # set the opaque component data_func to look at the flask request context
            func = graph.opaque.initialize(graph.request_context)(func)

            if graph.route_metrics.enabled:
                func = graph.route_metrics(endpoint)(func)

            # keep audit decoration last (before registering the route) so that
            # errors raised by other decorators are captured in the audit trail
            if enable_audit:
                func = graph.audit(func)

            graph.app.route(
                endpoint_path,
                endpoint=endpoint,
                methods=[operation.value.method],
            )(func)
            return func
Example #7
0
 def inner(*args, **kwargs):
     if not app.config.get('CORS_HOSTS'):
         return fun(*args, **kwargs)
     return cross_origin(
         headers=['Authorization', 'Content-Type'],
         supports_credentials=True,
         origins=app.config['CORS_HOSTS'],
     )(fun)(*args, **kwargs)
Example #8
0
class RefreshJwtApi(BaseResource):
    decorators = [cross_origin(), jwt_refresh_token_required]

    def post(self):
        current_user = get_jwt_identity()
        result = dict(
            access_token=create_access_token(identity=current_user))
        return self.response(result)
Example #9
0
class OnlineStatusApi(BaseResource):
    decorators = [cross_origin(), jwt_required]

    def get(self):
        users = User.get_online_users()
        if users:
            return self.response(users)
        result = dict(count=0, results=[])
        return self.response(result)
Example #10
0
class PrivateAPIEndpoint(MethodView):
    # make converter run after every request handler method returns
    decorators = [
        json_converter, requires_auth,
        cross_origin(headers=['Content-Type', 'Authorization'])
    ]

    def __init__(self, *args, **kwargs):
        super(PrivateAPIEndpoint, self).__init__(*args, **kwargs)
        self.logger = current_app.logger
Example #11
0
class RosKill(Resource):

    decorators = [
        cross_origin(origin="*", headers=["content-type", "autorization"])
    ]

    def post(self):
        json_data = request.get_json(force=True)
        print("killing Node " + str(json_data["nodeId"]))
        return jsonify({'response': 'killed ok'})
Example #12
0
class GetCoreAddress(Resource):

    decorators = [
        cross_origin(origin="*", headers=["content-type", "autorization"])
    ]

    def post(self):
        json_data = request.get_json(force=True)
        print("received core is active on" + json_data["coreAddress"])
        return "ok"
    def cors(self, func=None, *args, **kwargs):
        """Helper method for defining CORS on specific endpoints."""
        if func is None:
            return partial(self.cors, *args, **kwargs)

        methods = sorted({
            m.upper()
            for m in kwargs.pop("methods", ["GET"]) + ["OPTIONS", "HEAD"]
        })
        return cross_origin(methods=methods, *args, **kwargs)(func)
Example #14
0
def route_authorization(
    self,
    route: str,
    roles: List[str],
    methods: List[str] = ['GET']
):
    return composed(
        self.route(route, methods=methods),
        cross_origin(supports_credentials=True),
        roles_required(roles=['USER'])
    )
Example #15
0
class HBRProcess(Resource):
    decorators = [cross_origin(origin="*", headers=["content-type", "autorization"], methods=['GET', 'PUT'])]

    def post(self):
        parser = reqparse.RequestParser()
        parser.add_argument('cmd')
        args = parser.parse_args()

        cmd = args['cmd'].split()
        proc = run_shell.delay(cmd)
        return 'ok'
Example #16
0
class Roscore(Resource):

    decorators = [
        cross_origin(origin="*", headers=["content-type", "autorization"])
    ]

    def get(self):
        return jsonify({'response': 'get roscore ok'})

    def post(self):
        return jsonify({'response': 'post roscore ok'})

    def put(self):
        return jsonify({'response': 'put roscore ok'})
Example #17
0
class Robot(Resource):
    decorators = [
        cross_origin(origin="*",
                     headers=["content-type", "autorization"],
                     methods=['GET', 'PUT'])
    ]

    def get(self):
        return jsonify({
            'name': current_app.config["DOTBOT_NAME"],
            'master': current_app.config["ROS_MASTER_URI"],
            'ip': current_app.config["ROS_IP"],
            "macaddress": getMAC('wlan0'),
            "model": current_app.config["MODEL_HB"]
        })
Example #18
0
class RobotSketch(Resource):

    decorators = [cross_origin(origin='*')]

    def put(self):
        parser = reqparse.RequestParser()
        parser.add_argument('code')
        args = parser.parse_args()
        '''
        node_id = 1
        file_id = 1
    	f = File.query.get_or_404(file_id)

    	f.code = args['code']
    	f.last_edit = datetime.utcnow()
    	db.session.add(f)
    	f.save()
        db.session.commit()

    	n = Node.query.get_or_404(node_id)
    	comp.run(n)
        print 'node running'
        '''
        of = open(
            '/opt/virtualenvs/ros/project/dotbot_ws/src/dotbot_app/dotbot_ros_skeleton/node.py',
            "w")
        of.write(args['code'])
        of.close()
        return jsonify({'response': 'ok'})

    def get(self):
        print 'getting streaming'
        node_id = 1
        return redirect(url_for("api.stream", id=1))

    def options(self):
        pass

    def delete(self):
        print 'delete me'
        parser = reqparse.RequestParser()
        parser.add_argument('node')
        args = parser.parse_args()
        env = comp.env()
        env["ROS_NAMESPACE"] = ''
        killproc = subprocess.Popen(['rosnode', 'kill', args.node], env=env)
        killproc.wait()
        return jsonify({'response': 'ok'})
Example #19
0
class Rosfile(Resource):

    decorators = [
        cross_origin(origin="*", headers=["content-type", "autorization"])
    ]

    def post(self):
        json_data = request.get_json(force=True)
        filecontent = json_data["filecontent"]
        print(filecontent)
        filename = json_data["filename"]
        print(filename)
        return jsonify({'response': 'ok'})

    def put(self):
        return jsonify({'response': 'ok'})
Example #20
0
class Rosnode(Resource):

    decorators = [
        cross_origin(origin="*", headers=["content-type", "autorization"])
    ]

    def post(self):
        json_data = request.get_json(force=True)
        node = json_data["node"]
        files = json_data["files"]
        print(node)
        print(files)
        return jsonify({'response': 'node uploaded ok'})

    def put(self):
        return jsonify({'response': 'ok'})
Example #21
0
class ManageRobot(Resource):
    decorators = [cross_origin(origin='*')]

    def post(self):
        parser = reqparse.RequestParser()
        parser.add_argument('command')
        args = parser.parse_args()
        print 'test'
        if args["command"] == 'poweroff':
            subprocess.Popen(['poweroff'])
            return jsonify({'response': "ok"})
        elif args["command"] == 'reboot':
            subprocess.Popen(['reboot'])
            return jsonify({'response': "ok"})
        else:
            return jsonify({'response': "command not found"})
Example #22
0
class DecoratedGraphQLView(GraphQLView):
    methods = ["GET", "POST", "PUT", "DELETE", "OPTIONS"]

    decorators = (flask_cors.cross_origin(
        origins=[
            item.strip()
            for item in os.getenv("ALLOWED_CORS_ORIGINS", "*").split(",")
        ],
        expose_headers=["Content-Type"],
        support_credentials=True,
    ), )

    def dispatch_request(self):
        request_method = request.method.lower()
        if request_method == "options":
            return Response(status=HTTPStatus.NO_CONTENT)
        return super().dispatch_request()
Example #23
0
class DownloadProductApi(BaseResource):
    decorators = [cross_origin(), jwt_required]

    def get(self):
        si = StringIO()
        cw = csv.writer(si)
        cw.writerow(['id', 'name', 'description', 'phone', 'email'])
        users = Product.query.order_by(desc(Product.created_at)).all()
        for obj in users:
            cw.writerow(
                [obj.id, obj.name, obj.description, obj.phone, obj.email])
        output = make_response(si.getvalue())
        output.headers["Content-Disposition"] = "attachment; " \
                                                "filename={}_{}.csv" \
            .format("all_products", datetime.now())
        output.headers["Content-type"] = "text/csv"
        si.close()
        return output
Example #24
0
class StatusApi(BaseResource):
    decorators = [cross_origin(), jwt_required]

    def get(self, status_id: int = None):
        page = request.args.get('page')
        if status_id:
            result = Status.get_by_id(status_id)
            return self.response(**result)
        statuses = Status.get_all_data(int(page) if page else None)
        return self.response(statuses)

    @validate(['name'])
    def post(self):
        if not request.is_json:
            result = dict(message='Content type not json')
            return self.response(result, 400)
        status = Status(**request.json)
        status.create()
        result = dict(message="Successfully Saved!")
        return self.response(result, 201)

    def put(self, status_id=None):
        status = Status.get_by_id(status_id)
        if not status:
            result = dict(message="Id not found")
            return self.response(result, 404)
        updated = Status.update(status_id, **request.json)
        if not updated:
            result = dict(message="Did not update order status.")
            return self.response(result, 400)
        result = dict(message="Successfully Updated!")
        return self.response(result, 201)

    def delete(self, status_id=None):
        status = Status.get_by_id(status_id)
        if not status:
            result = dict(message="Id not found")
            return self.response(result, 404)
        result = status.delete()
        if result:
            result = dict(message="Successfully deleted {}".format(status_id))
            return self.response(result)
        result = dict(message="{} Not deleted".format(status_id))
        return self.response(result, 400)
Example #25
0
def main():
    parser = argparse.ArgumentParser(description='Meta Reverse Image Search API')
    parser.add_argument('-p', '--port', type=int, default=5000, help='port number')
    parser.add_argument('-d','--debug', action='store_true', help='enable debug mode')
    parser.add_argument('-c','--cors', action='store_true', default=False, help="enable cross-origin requests")
    args = parser.parse_args()

    if args.debug:
        app.debug = True

    if args.cors:
        CORS(app, resources=r'/search/*')
        app.config['CORS_HEADERS'] = 'Content-Type'

        global search
        search = cross_origin(search)
        print(" * Running with CORS enabled")


    app.run(host='0.0.0.0', port=args.port)
Example #26
0
        def decorator(func):
            endpoint = ns.endpoint_for(operation)
            endpoint_path = graph.build_route_path(path, ns.prefix)

            if enable_cors:
                func = cross_origin(supports_credentials=True)(func)

            if enable_basic_auth or ns.enable_basic_auth:
                func = graph.basic_auth.required(func)

            if enable_context_logger and ns.controller is not None:
                func = context_logger(
                    graph.request_context,
                    func,
                    parent=ns.controller,
                )

            # set the opaque component data_func to look at the flask request context
            func = graph.opaque.initialize(graph.request_context)(func)

            if enable_metrics or ns.enable_metrics:
                from microcosm_flask.metrics import StatusCodeClassifier
                tags = [f"endpoint:{endpoint}", "backend_type:microcosm_flask"]
                func = graph.metrics_counting(
                    "route",
                    tags=tags,
                    classifier_cls=StatusCodeClassifier,
                )(func)
                func = graph.metrics_timing("route", tags=tags)(func)

            # keep audit decoration last (before registering the route) so that
            # errors raised by other decorators are captured in the audit trail
            if enable_audit:
                func = graph.audit(func)

            graph.app.route(
                endpoint_path,
                endpoint=endpoint,
                methods=[operation.value.method],
            )(func)
            return func
Example #27
0
class GenerateJwtApi(BaseResource):
    decorators = [cross_origin()]
    schema = AuthSchema()

    @content_type(['application/json'])
    @validator(['email', 'password'])
    def post(self):
        email = request.json.get('email')
        password = request.json.get('password')
        if not request.is_json:
            result = dict(message="Missing JSON in request")
            return self.response(result, 400)
        user = User.get_user_by_email(email)
        if user:
            if password_helper.check_password_hash(user.password, password):
                app.logger.info(
                    "Logged in user with the email {0}".format(email))
                access_token = create_access_token(
                    identity=email,
                    expires_delta=False
                )
                refresh_token = create_refresh_token(identity=email)
                result = dict(
                    access_token=access_token,
                    refresh_token=refresh_token,
                    user=dict(
                        id=user.id,
                        full_name="{} {}".format(
                            user.first_name,
                            user.last_name),
                        email=user.email,
                        roles=[user_role.role.name for user_role in user.roles]
                    )
                )
                return self.response(result)
        else:
            app.logger.warning(
                "User with the email {0} does not exist".format(email))
            result = dict(message="Bad username or password")
            return self.response(result, 401)
Example #28
0
def main():
    parser = argparse.ArgumentParser(
        description='Meta Reverse Image Search API')
    parser.add_argument('-p',
                        '--port',
                        type=int,
                        default=5000,
                        help='port number')
    parser.add_argument('-d',
                        '--debug',
                        action='store_true',
                        help='enable debug mode')
    parser.add_argument('-c',
                        '--cors',
                        action='store_true',
                        default=False,
                        help="enable cross-origin requests")
    parser.add_argument('-a',
                        '--host',
                        type=str,
                        default='0.0.0.0',
                        help="sets the address to serve on")
    args = parser.parse_args()

    if args.debug:
        app.debug = True

    if args.cors:
        CORS(app, resources=r'/shopping/*')
        CORS(app, resources=r'/food/*')
        CORS(app, resources=r'/imgcap/*')
        app.config['CORS_HEADERS'] = 'Content-Type'

        global search
        search = cross_origin(search)
        print(" * Running with CORS enabled")

    app.run(host=args.host, port=args.port)
Example #29
0
class ConfHostname(Resource):
    decorators = [cross_origin(origin='*')]

    def get(self):
        return jsonify({'hostname': current_app.config["DOTBOT_NAME"]})

    def put(self):
        parser = reqparse.RequestParser()
        parser.add_argument('hostname')
        args = parser.parse_args()

        if args["hostname"] is not None and args["hostname"] != "":
            replace('/opt/virtualenvs/ros/project/config.bash',
                    '^export\sDOTBOT_NAME.*\W',
                    'export DOTBOT_NAME=%s\n' % args["hostname"])
            replace('/etc/avahi/avahi-daemon.conf', '^host-name=.*\W',
                    'host-name=%s\n' % args["hostname"])
            replace(
                '/opt/virtualenvs/ros/project/config.bash',
                '^export\sROS_MASTER_URI.*\W',
                'export ROS_MASTER_URI=http://%s.local:11311\n' %
                args["hostname"])
            return jsonify({'response': "ok"})
        return jsonify({'response': "error"})
Example #30
0
class GithubView(MethodView):

    decorators = [cross_origin()]

    @cached_property
    def repo(self):
        client = github3.login(token=config.github_token)
        return client.repository('18F', 'fec')

    @use_kwargs({
        'referer': fields.Url(
            required=True,
            validate=validate_referer,
            location='headers',
        ),
        'action': fields.Str(),
        'feedback': fields.Str(),
        'about': fields.Str(),
        'chart_reaction': fields.Str(),
        'chart_location': fields.Str(),
        'chart_name': fields.Str(),
        'chart_comment': fields.Str()

    })
    def post(self, **kwargs):
        if not any([kwargs['action'], kwargs['feedback'], kwargs['about'], kwargs['chart_comment']]):
            return jsonify({
                'message': 'Must provide one of "action", "feedback", or "about".',
            }), 422
        if kwargs['chart_comment']:
            title = 'Chart reaction on {} page'.format(kwargs['chart_location'])
        else:
            title = 'User feedback on {}'.format(kwargs['referer'])
        body = render_template('feedback.html', headers=request.headers, **kwargs)
        issue = self.repo.create_issue(title, body=body)
        return jsonify(issue.to_json()), 201
Example #31
0
    def cors(cls, fn):
        """
        CORS decorator, to make the endpoint available for CORS

        Make sure @cors decorator is placed at the top position.
        All response decorators must be placed below. 
        It's because it requires a response to be available

        class Index(Assembly):
            def index(self):
                return self.render()

            @request.cors
            @response.json
            def json(self):
                return {}

        :return:
        """
        if inspect.isclass(fn):
            raise Error("@cors can only be applied on Assembly methods")
        else:
            cors_fn = flask_cors.cross_origin(automatic_options=True)
            return cors_fn(fn)
Example #32
0
class GetEnvironment(Resource):

    decorators = [
        cross_origin(origin="*", headers=["content-type", "autorization"])
    ]

    def get(self):
        return "ok"
        import json
        source1 = app.config["ROS_GLOBAL_SOURCE"]
        source2 = app.config["ROS_LOCAL_SOURCE"]
        dump = 'python -c "import os, json;print json.dumps(dict(os.environ))"'
        pipe = subprocess.Popen(
            ['/bin/bash', '-c',
             '%s && %s && %s' % (source1, source2, dump)],
            stdout=subprocess.PIPE)
        print pipe
        env_info = pipe.stdout.read()
        print env_info
        _env = json.loads(env_info)
        if 'LS_COLORS' in _env:
            del _env['LS_COLORS']
        _env["PWD"] = app.config["CATKING_PATH"]
        return jsonify(_env)
Example #33
0
class DownloadUserApi(BaseResource):
    decorators = [cross_origin(), jwt_required]

    def get(self):
        si = StringIO()
        cw = csv.writer(si)
        cw.writerow([
            'id', 'first_name', 'last_name', 'phone', 'email', 'roles',
            'created_at', 'updated_at'
        ])
        users = User.query.order_by(desc(User.created_at)).all()
        for obj in users:
            cw.writerow([
                obj.id, obj.first_name, obj.last_name, obj.phone, obj.email,
                [user_role.role.name for user_role in obj.roles],
                obj.created_at, obj.updated_at
            ])
        output = make_response(si.getvalue())
        output.headers[
            "Content-Disposition"] = "attachment; filename={}_{}.csv".format(
                "all_users", datetime.now())
        output.headers["Content-type"] = "text/csv"
        si.close()
        return output
Example #34
0
DB = ROOT_DIR + '/users.db'
SCALE = ScaleController()
LOGGER = logging.getLogger(__name__)
LOGGER.setLevel(logging.INFO)

parser = argparse.ArgumentParser(
    description='Provide a JSON-RPC proxy for a USB scale.'
)
parser.add_argument('-w', '--weight', help='a test weight to return instead of doing a real reading', default=None)
parser.add_argument('-p', '--port', help='the port to run on', default="443")
args = parser.parse_args()

app = Flask(__name__)
auth = HTTPBasicAuth()
jsonrpc = JSONRPC(app, "/api", decorators=[
    cross_origin(methods=['POST', 'OPTIONS'], headers=["accept", "authorization", "content-type"]),
    json_headers,
    max_age_headers
])


# Not a route on purpose.
# Use an interactive Python shell to add users.
def add_user(username, password):
    '''Adds a new JSON-RPC user to the database.'''

    salt = str(uuid.uuid4())
    db = sqlite3.connect(DB)
    db.cursor().execute('''
        INSERT INTO users(username, pwd_hash, salt) VALUES (?, ?, ?)
    ''', (username, hashlib.sha256(password + "\x00" + salt).hexdigest(), salt))
Example #35
0
# main application serving web content and data

from flask_cors import cross_origin

import time
from flask import Flask, request, jsonify, Response, render_template, url_for
from flask.ext.cors import CORS

from DatabaseAccess.service.HeadlineSummaryService import HeadlineSummaryService



app = Flask(__name__)
CORS(app)
cross_origin(app)

service = HeadlineSummaryService()

# API ROUTES
# -------------------------------------------------------------------------------------------

@app.route('/api/sample', methods=['GET'])
def getSample():
    return jsonify(service.getSampleData())


@app.route('/api/headlines', methods=['GET'])
def getHeadlines():
     date = request.args.get('date')
     return jsonify(service.findByDate(date))
def _generate_handler_wrapper(api_name, api_spec, endpoint, handler_func, error_callback, global_decorator):
    """Generate a handler method for the given url method+path and operation"""

    # Decorate the handler function, if Swagger spec tells us to
    if endpoint.decorate_server:
        endpoint_decorator = get_function(endpoint.decorate_server)
        handler_func = endpoint_decorator(handler_func)

    @wraps(handler_func)
    def handler_wrapper(**path_params):
        log.info("=> INCOMING REQUEST %s %s -> %s" %
                 (endpoint.method, endpoint.path, handler_func.__name__))

        # Get caller's klue-call-id or generate one
        call_id = request.headers.get('KlueCallID', None)
        if not call_id:
            call_id = str(uuid.uuid4())
        stack.top.call_id = call_id

        # Append current server to call path, or start one
        call_path = request.headers.get('KlueCallPath', None)
        if call_path:
            call_path = "%s.%s" % (call_path, api_name)
        else:
            call_path = api_name
        stack.top.call_path = call_path

        if endpoint.param_in_body or endpoint.param_in_query:
            # Turn the flask request into something bravado-core can process...
            try:
                req = FlaskRequestProxy(request, endpoint.param_in_body)
            except BadRequest:
                ee = error_callback(ValidationError("Cannot parse json data: have you set 'Content-Type' to 'application/json'?"))
                return _responsify(api_spec, ee, 400)

            try:
                # Note: unmarshall validates parameters but does not fail
                # if extra unknown parameters are submitted
                parameters = unmarshal_request(req, endpoint.operation)
                # Example of parameters: {'body': RegisterCredentials()}
            except jsonschema.exceptions.ValidationError as e:
                ee = error_callback(ValidationError(str(e)))
                return _responsify(api_spec, ee, 400)

        # Call the endpoint, with proper parameters depending on whether
        # parameters are in body, query or url
        args = []
        kwargs = {}

        if endpoint.param_in_path:
            kwargs = path_params

        if endpoint.param_in_body:
            # Remove the parameters already defined in path_params
            for k in path_params.keys():
                del parameters[k]
            l = list(parameters.values())
            assert len(l) == 1
            args.append(l[0])

        if endpoint.param_in_query:
            kwargs.update(parameters)

        result = handler_func(*args, **kwargs)

        if not result:
            e = error_callback(KlueException("Have nothing to send in response"))
            return _responsify(api_spec, e, 500)

        # Did we get the expected response?
        if endpoint.produces_html:
            if type(result) is not tuple:
                e = error_callback(KlueException("Method %s should return %s but returned %s" %
                                                 (endpoint.handler_server, endpoint.produces, type(result))))
                return _responsify(api_spec, e, 500)

            # Return an html page
            return result

        elif endpoint.produces_json:
            if not hasattr(result, '__module__') or not hasattr(result, '__class__'):
                e = error_callback(KlueException("Method %s did not return a class instance but a %s" %
                                                 (endpoint.handler_server, type(result))))
                return _responsify(api_spec, e, 500)

            # If it's already a flask Response, just pass it through.
            # Errors in particular may be either passed back as flask Responses, or
            # raised as exceptions to be caught and formatted by the error_callback
            result_type = result.__module__ + "." + result.__class__.__name__
            if result_type == 'flask.wrappers.Response':
                return result

            # Otherwise, assume no error occured and make a flask Response out of
            # the result.

            # TODO: check that result is an instance of a model expected as response from this endpoint
            result_json = api_spec.model_to_json(result)

            # Send a Flask Response with code 200 and result_json
            r = jsonify(result_json)
            r.status_code = 200
            return r

    handler_wrapper = cross_origin(headers=['Content-Type', 'Authorization'])(handler_wrapper)

    # And encapsulate all in a global decorator, if given one
    if global_decorator:
        handler_wrapper = global_decorator(handler_wrapper)

    return handler_wrapper