Skip to content

Commit

Permalink
Adds Configuration Options (#15)
Browse files Browse the repository at this point in the history
Although nothing is currently stored in the class instance, this change just allows the app registration to be done after instantiation.
  • Loading branch information
pet1330 authored Sep 18, 2020
1 parent 6453739 commit 0992928
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 8 deletions.
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()))

0 comments on commit 0992928

Please sign in to comment.