How to return the error "already exists" in Flask-restless?

I would like to make some exception handler. I am using a combination of Flask-restless and SQLAlchemy in python.

My problem:

When I submit a request for api with an object that already exists in the database, SQLAlchemy shows an exception:

IntegrityError: (IntegrityError) column <column_name> is not unique u'INSERT INTO ... 

So, I tried to add the validation_exceptions attribute to the create_api method:

 manager.create_api( ... , validation_exceptions=[IntegrityError]) 

But the json answer contains:

 { "validation_errors": "Could not determine specific validation errors" } 

and the api server shows an exception:

 Traceback (most recent call last): File "C:\Python27\lib\site-packages\flask_restless\views.py", line 797, in _extract_error_messages left, right = str(exception).rsplit(':', 1) ValueError: need more than 1 value to unpack 

Flask-restless exception checking does not work with this type of exception (IntegrityError)

What should I do? Is it possible to create some handler for the exception and return my own error message in json?

+5
source share
2 answers

documentation (v0.17.0 to date of this post):

Currently, Flask-Restless expects an instance of the specified validation error to have the errors attribute, which is the name of the dictionary mapping field for describing the error (note: one error for each field).

So, to change the contents of validation_errors for your exception, you need the errors attribute containing the dictionary. The contents of this dictionary will appear in the server response as validation_errors .

From flask-restless / tests / test_validation.py :

 class TestSimpleValidation(ManagerTestBase): """Tests for validation errors raised by the SQLAlchemy simple built-in validation. For more information about this functionality, see the documentation for :func:`sqlalchemy.orm.validates`. """ def setup(self): """Create APIs for the validated models.""" super(TestSimpleValidation, self).setup() class Person(self.Base): __tablename__ = 'person' id = Column(Integer, primary_key=True) age = Column(Integer, nullable=False) @validates('age') def validate_age(self, key, number): if not 0 <= number <= 150: exception = CoolValidationError() exception.errors = dict(age='Must be between 0 and 150') raise exception return number @validates('articles') def validate_articles(self, key, article): if article.title is not None and len(article.title) == 0: exception = CoolValidationError() exception.errors = {'articles': 'empty title not allowed'} raise exception return article class Article(self.Base): __tablename__ = 'article' id = Column(Integer, primary_key=True) title = Column(Unicode) author_id = Column(Integer, ForeignKey('person.id')) author = relationship('Person', backref=backref('articles')) self.Article = Article self.Person = Person self.Base.metadata.create_all() self.manager.create_api(Article) self.manager.create_api(Person, methods=['POST', 'PATCH'], validation_exceptions=[CoolValidationError]) 

Inquiry:

 data = dict(data=dict(type='person', age=-1)) response = self.app.post('/api/person', data=dumps(data)) 

Answer:

 HTTP/1.1 400 Bad Request { "validation_errors": { "age": "Must be between 0 and 150", } } 
+2
source

You can use preprocessors to get validation errors.

 def validation_preprocessor(data, *args, **kwargs): # validate data by any of your cool-validation-frameworks if errors: raise ProcessingException(description='Something went wrong', code=400) manager.create_api( Model, methods=['POST'], preprocessors=dict( POST=[validation_preprocessor] ) ) 

But I'm not sure if this is a good way to do this.

0
source

All Articles