简体   繁体   English

在 Python Flask RestPlus 上捕获异常

[英]Catching Exceptions on Python Flask RestPlus

I am struggling with finding a way to return a response when a call to one of my APIs does not return any result.当对我的一个 API 的调用没有返回任何结果时,我正在努力寻找一种返回响应的方法。 I am using flask_restplus, and tried to use the @api.errorhandler annotation with no success and then I resorted to try a plain try/except block in my class.我正在使用flask_restplus,并尝试使用@api.errorhandler 注释但没有成功,然后我在我的班级中尝试使用普通的try/except 块。

In this particular issue, I am trying to call the endpoint, where the GUID is a non-existent user in the database.在这个特定问题中,我试图调用端点,其中 GUID 是数据库中不存在的用户。

http://localhost:5000/api/users/b3d8e86b-f2ad-4b6a-b768-e7adc1d94ced

The user end point has been defined as following:用户端点定义如下:

import logging

from flask import Response
from flask_restplus import Resource, fields
from neomodel.core import DoesNotExist

from app.api.restplus import api
from app.models import User

log = logging.getLogger(__name__)

ns = api.namespace('users', description='Users')

user = api.model('user', {
    'id': fields.Integer(readOnly=True, description='The internal id of of a user'),
    'user_id': fields.String(required=True, description='The user unique identifier')}
)

@ns.route('/')
@api.response(404, 'Users not found.')
class UsersList(Resource):

    @api.marshal_list_with(user)
    def get(self):
        """
        Returns a list of all users
        :return: list_of_users
        """
        try:
            users = User.nodes
            list_of_users = list(users)
            return list_of_users
    #        return json.dumps(dict(users = [user.serialize for user in list_of_users]))
        except DoesNotExist:
            return Response(('{"No Content": "No user nodes found"}'), status = 200, mimetype = 'application/json')


@ns.route('/<string:user_id>')
class UserItem(Resource):

   @api.marshal_with(user)
   def get(self, user_id):
        """
        Returns a user with the given user_id
        :param id: user_id
        :return: user
        """
        try:
            user = User.nodes.get(user_id=user_id)
            return user
        except User.DoesNotExist:
            return Response({'message': 'Could not locate a user with the user_id provided.'}, 404)

My initialization is done in app/ init .py:我的初始化是在 app/ init .py 中完成的:

import logging.config
from flask import Flask, Blueprint
from neomodel import clear_neo4j_database
from neomodel import db

from app.config import Configuration
from app.web_app.routes import webapp_mod
from app.data_loader.routes import dataloader_mod
from app.utilities import prepare_rerun
from app.api.endpoints.users import ns as users_namespace
from app.api.endpoints.sessions import ns as sessions_namespace
from app.api.endpoints.browsers import ns as browsers_namespace
from app.api.endpoints.os import ns as os_namespace
from app.api.endpoints.applications import ns as applications_namespace
from app.api.endpoints.tenants import ns as tenants_namepspace
from app.api.endpoints.devices import  ns as devices_namespace
from app.api.endpoints.environments import ns as environments_namespace

from app.api.restplus import api
from os import path


app = Flask(__name__)
app.config.from_object(Configuration)
app.register_blueprint(dataloader_mod, url_prefix='/data_loader')
log_file_path = path.join(path.dirname(path.abspath(__file__)), 'logging.conf')
logging.config.fileConfig(log_file_path)
log = logging.getLogger(__name__)

blueprint = Blueprint('api', __name__, url_prefix='/api')
api.init_app(blueprint)
api.add_namespace(users_namespace)
api.add_namespace(sessions_namespace)
api.add_namespace(browsers_namespace)
api.add_namespace(applications_namespace)
api.add_namespace(tenants_namepspace)
api.add_namespace(devices_namespace)
api.add_namespace(os_namespace)
api.add_namespace(environments_namespace)

The resplus.py module where I define the api at this point has just the definition of the api object, but I had tried to follow some examples online and define in it methods to handle the exceptions through the annotations in the users object.此时我定义api的resplus.py模块只有api对象的定义,但是我尝试了网上的一些例子,并在其中定义了通过users对象中的注解来处理异常的方法。

from flask_restplus import Api
from neomodel.core import DoesNotExist

api = Api(version='1.0', title='Users Activity Log',
          description='An API to retreive information about users'' activities in Infor Ming.le')

However when I make the call, instead of getting a JSON response with the message and 404 code, I am getting:但是,当我拨打电话时,我得到的不是带有消息和 404 代码的 JSON 响应,而是:

{
    "id": null,
    "user_id": null
}

Thanks in advance for any help.在此先感谢您的帮助。

I suppose I am a little late to help you but I might help other people having the same problem:我想我来帮助有点晚了但我可能会帮助其他有同样问题的人:

The thing is, although you have an other return code (and you have an error) flask still tries to use @marshal_with(user) .问题是,尽管您有其他返回码(并且您有错误),flask 仍然尝试使用@marshal_with(user) It might be a little bit confusing at first.一开始可能会有点混乱。

If you look at this answer you can see how to return multiple answer types without loosing the swagger functionality plus you still got the marshalling.如果您查看此答案,您可以看到如何在不失去 swagger 功能的情况下返回多种答案类型,而且您仍然可以进行编组。 This is a bit more versatile than the standard @marshal_with .这比标准的@marshal_with更通用。

There are other ways of achieving similar results for errors: Eg you could use the abort() function (which might be more logical in some cases).还有其他方法可以获得类似的错误结果:例如,您可以使用 abort() 函数(在某些情况下可能更合乎逻辑)。

So in other words your code transformed would look somehow like this:因此,换句话说,您转换的代码看起来像这样:

import logging

from flask import Response
from flask_restplus import Resource, fields, marshal
from neomodel.core import DoesNotExist

from app.api.restplus import api
from app.models import User

log = logging.getLogger(__name__)

ns = api.namespace('users', description='Users')

user = api.model('user', {
    'id': fields.Integer(readOnly=True, description='The internal id of of a user'),
    'user_id': fields.String(required=True, description='The user unique identifier')}
)

@ns.route('/')
@api.response(404, 'Users not found.')
class UsersList(Resource):

    @api.response(model=user, code=200)
    @api.response(404, 'Users not found.')
    def get(self):
        """
        Returns a list of all users
        :return: list_of_users
        """
        try:
            users = User.nodes
            list_of_users = list(users)
            return marshal(list_of_users)
        except DoesNotExist:
            return {"No Content": "No user nodes found"}, 404


@ns.route('/<string:user_id>')
class UserItem(Resource):

   @api.response(model=user, code=200)
   @api.response(code=404, 'Users not found.')
   def get(self, user_id):
        """
        Returns a user with the given user_id
        :param id: user_id
        :return: user
        """
        try:
            user = User.nodes.get(user_id=user_id)
            return marshal(user)
        except User.DoesNotExist:
            return {'message': 'Could not locate a user with the user_id provided.'}, 404

# More Endpoints - I hope this did the job...

You can use你可以使用

from flask_restplus import abort
abort(400, custom='value')

To abort and through errors中止和通过错误

or

namespace.abort(400, "An error occured") 

This is likely no longer relevant as your question is from quite a while ago, but I came across this as I was searching around for flask-restplus exception handling best practices.这可能不再相关,因为您的问题来自很久以前,但我在寻找flask-restplus异常处理最佳实践时遇到了这个问题。 I don't think your problem is with flask-restplus' exception handling.我认为您的问题不在于flask-restplus 的异常处理。 It sounds like your User class is not raising a DoesNotExist exception when the user doesn't exist.听起来您的 User 类在用户不存在时不会引发DoesNotExist 异常。 Did you verify whether you're even hitting the Except: block?你有没有验证你是否甚至点击了Except:块?

Anyhow, once you verify that you are indeed raising the DoesNotExist exception, you can register an errorhandler for that exception in your init.py like this:总之,一旦你确认你确实提高DoesNotExist异常,可以申请参加在您init.py像这样的例外设置ErrorHandler:

@api.errorhandler(DoesNotExist)
def handle_user_does_not_exist_error(error):
    return ({'message': 'Could not locate a user with the user_id provided.'}, 404) 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM