Use marshmallow and webargs for parsing and marshaling
parent
8d151ba8c3
commit
55caf167c9
|
@ -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)
|
||||||
|
|
|
@ -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'],
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue