Use marshmallow and webargs for parsing and marshaling

master
esensar 2018-05-07 13:57:53 +02:00
parent 8d151ba8c3
commit 55caf167c9
4 changed files with 42 additions and 62 deletions

View File

@ -2,6 +2,7 @@ from flask import Blueprint
from flask_restful import Api from flask_restful import Api
from .resources.account import AccountResource from .resources.account import AccountResource
from .resources.token import TokenResource from .resources.token import TokenResource
from marshmallow import ValidationError
api_bp = Blueprint('api', __name__) api_bp = Blueprint('api', __name__)
api = Api(api_bp) api = Api(api_bp)
@ -9,3 +10,16 @@ api = Api(api_bp)
# Add resources # Add resources
api.add_resource(AccountResource, '/v1/accounts') api.add_resource(AccountResource, '/v1/accounts')
api.add_resource(TokenResource, '/v1/token') api.add_resource(TokenResource, '/v1/token')
@api_bp.errorhandler(ValidationError)
def handle_validation_error(e):
return {'status': 'error', 'message': str(e)}, 422
@api_bp.errorhandler(Exception)
def handle_unknown_errors(e):
return ({
'status': 'failed',
'message': 'Unknown error has occurred! ({0})'.format(str(e))
}, 500)

View File

@ -1,38 +1,22 @@
from flask_restful import Resource, reqparse, abort from flask_restful import Resource, abort
from webargs import fields
from webargs.flaskparser import use_args
import app.accounts as accounts import app.accounts as accounts
def user(user_dict):
"""
Type definition of user object required as a parameter
Required keys:
* username - string
* password - string
* email - string
:returns user dictionary with required keys
:rtype dict
:raises ValueError if parameter is not dict or is missing required keys
"""
if not isinstance(user_dict, dict):
raise ValueError("User should contain username, password and email")
if ('username' not in user_dict or
'password' not in user_dict or
'email' not in user_dict):
raise ValueError("User should contain username, password and email")
return user_dict
class AccountResource(Resource): class AccountResource(Resource):
parser = reqparse.RequestParser(bundle_errors=True) user_args = {
parser.add_argument('user', location='json', type=user, 'user': fields.Nested({
help='User is not valid. Error: {error_msg}', 'username': fields.Str(required=True),
required=True) 'email': fields.Email(required=True),
'password': fields.Str(required=True)
}, required=True, location='json')
}
def post(self): @use_args(user_args)
def post(self, args):
try: try:
args = AccountResource.parser.parse_args()['user'] args = args['user']
success = accounts.create_account( success = accounts.create_account(
args['username'], args['username'],
args['email'], args['email'],

View File

@ -1,46 +1,25 @@
from flask_restful import Resource, reqparse, abort, fields, marshal_with from flask_restful import Resource, abort
from webargs import fields
from webargs.flaskparser import use_args
import app.accounts as accounts import app.accounts as accounts
def user(user_dict):
"""
Type definition of user object required as a parameter
Required keys:
* username - string
* password - string
:returns user dictionary with required keys
:rtype dict
:raises ValueError if parameter is not dict or is missing required keys
"""
if not isinstance(user_dict, dict):
raise ValueError("User should contain username, password and email")
if ('username' not in user_dict or
'password' not in user_dict):
raise ValueError("User should contain username, password and email")
return user_dict
class TokenResource(Resource): class TokenResource(Resource):
parser = reqparse.RequestParser(bundle_errors=True) user_args = {
parser.add_argument('user', location='json', type=user, 'user': fields.Nested({
help='User is not valid. Error: {error_msg}', 'username': fields.Str(),
required=True) 'password': fields.Str()
}, required=True, location='json')
res_fields = {
'status': fields.String(default='Success'),
'token': fields.String
} }
@marshal_with(res_fields) @use_args(user_args)
def post(self): def post(self, args):
try: try:
args = TokenResource.parser.parse_args()['user'] args = args['user']
token = accounts.create_token( token = accounts.create_token(
args['username'], args['username'],
args['password']) args['password'])
if token: if token:
return {'token': token}, 200 return {'status': 'success', 'token': token}, 200
except ValueError: except ValueError:
abort(401, message='Invalid credentials', status='error') abort(401, message='Invalid credentials', status='error')

View File

@ -16,8 +16,10 @@ itsdangerous==0.24
Jinja2==2.10 Jinja2==2.10
Mako==1.0.7 Mako==1.0.7
MarkupSafe==1.0 MarkupSafe==1.0
marshmallow==3.0.0b9
paho-mqtt==1.3.1 paho-mqtt==1.3.1
psycopg2==2.7.4 psycopg2==2.7.4
psycopg2-binary==2.7.4
pycparser==2.18 pycparser==2.18
PyJWT==1.4.2 PyJWT==1.4.2
python-dateutil==2.7.2 python-dateutil==2.7.2
@ -26,4 +28,5 @@ pytz==2018.4
six==1.11.0 six==1.11.0
SQLAlchemy==1.2.7 SQLAlchemy==1.2.7
typing==3.6.4 typing==3.6.4
webargs==2.1.0
Werkzeug==0.14.1 Werkzeug==0.14.1