Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions docs/source/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ class PostRequest(JsonRequest):

### Error Messages Format

In case validation fails to pass, the following is the format of the generated response:
In case validation fails to pass, the following is the default format of the generated response:
```js
{
success: False,
Expand All @@ -181,7 +181,19 @@ In case validation fails to pass, the following is the format of the generated r
}
}
```
All validation error messages will have a HTTP error status code 400.

This format can be configured using the following flask configurations:
- `SIEVE_RESPONSE_MESSAGE` - Set this to modify your default error message e.g "Invalid Input".
- `SIEVE_INCLUDE_SUCCESS_KEY` - Set this to False to remove the success key from the response.
- `SIEVE_RESPONSE_WRAPPER` - Set this to wrap your response e.g. `data`.


### Response Status Code

By default, all validation error messages will have a HTTP error status code 400. This can be configured by setting the flask config `SIEVE_INVALID_STATUS_CODE`.
```python
app.config['SIEVE_INVALID_STATUS_CODE'] = 422
```

### Stopping on First Validation Failure

Expand Down
8 changes: 7 additions & 1 deletion flask_sieve/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
from .validator import validate, Validator
from .exceptions import ValidationException, register_error_handler


class Sieve:
def __init__(self, app):
def __init__(self, app=None):
if app is not None:
self.init_app(app)

@staticmethod
def init_app(app):
register_error_handler(app)
18 changes: 13 additions & 5 deletions flask_sieve/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
from flask import jsonify


class ValidationException(Exception):
def __init__(self, errors):
self.errors = errors


def register_error_handler(app):
def validations_error_handler(ex):
return jsonify({
'success': False,
'message': 'Validation error',
response = {
'message': app.config.get('SIEVE_RESPONSE_MESSAGE', 'Validation error'),
'errors': ex.errors
}), 400
}

if app.config.get('SIEVE_INCLUDE_SUCCESS_KEY'):
response['success'] = False

if app.config.get('SIEVE_RESPONSE_WRAPPER'):
response = {app.config.get('SIEVE_RESPONSE_WRAPPER'): response}

return jsonify(response), app.config.get('SIEVE_INVALID_STATUS_CODE', 400)

app.register_error_handler(
ValidationException,
validations_error_handler
)

90 changes: 90 additions & 0 deletions tests/test_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,93 @@ def test_error_handler(self):
)
self.assertEqual(400, status)
self.assertIn('Test error', str(response.get_json()))

def test_configurable_status_code(self):
app = Flask(__name__)
app.config['SIEVE_INVALID_STATUS_CODE'] = 422
register_error_handler(app)
self.assertIn(ValidationException, app.error_handler_spec[None][None])
errors = {'field': 'Test error'}

with app.app_context():
response, status = app.error_handler_spec[None][None][ValidationException](
ValidationException(errors)
)
self.assertEqual(422, status)
self.assertIn('Test error', str(response.get_json()))

def test_configuring_response_message(self):
app = Flask(__name__)
msg = "Only Chuck Norris can submit invalid data!"
app.config['SIEVE_RESPONSE_MESSAGE'] = msg
register_error_handler(app)
self.assertIn(ValidationException, app.error_handler_spec[None][None])
errors = {'field': 'Test error'}

with app.app_context():
response, status = app.error_handler_spec[None][None][ValidationException](
ValidationException(errors)
)
self.assertEqual(400, status)
self.assertIn(msg, str(response.get_json()))

def test_keeping_success_message(self):
app = Flask(__name__)
app.config['SIEVE_INCLUDE_SUCCESS_KEY'] = True

register_error_handler(app)
self.assertIn(ValidationException, app.error_handler_spec[None][None])
errors = {'field': 'Test error'}

with app.app_context():
response, status = app.error_handler_spec[None][None][ValidationException](
ValidationException(errors)
)
self.assertEqual(400, status)
self.assertTrue('success' in response.get_json())

def test_keeping_removing_message(self):
app = Flask(__name__)
app.config['SIEVE_INCLUDE_SUCCESS_KEY'] = False

register_error_handler(app)
self.assertIn(ValidationException, app.error_handler_spec[None][None])
errors = {'field': 'Test error'}

with app.app_context():
response, status = app.error_handler_spec[None][None][ValidationException](
ValidationException(errors)
)
self.assertEqual(400, status)
self.assertFalse('success' in response.get_json())

def test_wrapping_response_with_data(self):
app = Flask(__name__)
app.config['SIEVE_RESPONSE_WRAPPER'] = 'data'

register_error_handler(app)
self.assertIn(ValidationException, app.error_handler_spec[None][None])
errors = {'field': 'Test error'}

with app.app_context():
response, status = app.error_handler_spec[None][None][ValidationException](
ValidationException(errors)
)
self.assertEqual(400, status)
self.assertIn('Test error', str(response.get_json()))
self.assertTrue('data' in response.get_json())

def test_wrapping_response_without_data(self):
app = Flask(__name__)
register_error_handler(app)
self.assertIn(ValidationException, app.error_handler_spec[None][None])
errors = {'field': 'Test error'}

with app.app_context():
response, status = app.error_handler_spec[None][None][ValidationException](
ValidationException(errors)
)
self.assertEqual(400, status)
self.assertIn('Test error', str(response.get_json()))
self.assertFalse('data' in response.get_json())
self.assertTrue('errors' in response.get_json())
16 changes: 16 additions & 0 deletions tests/test_sieve.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,19 @@ def test_registers_error_handler(self):
)
self.assertEqual(400, status)
self.assertIn('Test error', str(response.get_json()))

def test_deferring_registration_of_error_handler(self):
app = Flask(__name__)
s = Sieve()

s.init_app(app)

self.assertIn(ValidationException, app.error_handler_spec[None][None])
errors = {'field': 'Test error'}

with app.app_context():
response, status = app.error_handler_spec[None][None][ValidationException](
ValidationException(errors)
)
self.assertEqual(400, status)
self.assertIn('Test error', str(response.get_json()))