def api_request(methods=None, require_token=True):
def decorator(view_func):<EOL><INDENT>@wraps(view_func, assigned=available_attrs(view_func))<EOL>def _wrapped_view(request, *args, **kwargs):<EOL><INDENT>ApiToken = apps.get_model('<STR_LIT>', '<STR_LIT>')<EOL>m = methods if methods is not None else DEFAULT_API_METHODS<EOL>if request.method not in m:<EOL><INDENT>response = ApiResponse(False, '<STR_LIT>', status=<NUM_LIT>)<EOL>response['<STR_LIT>'] = '<STR_LIT:U+002CU+0020>'.join(methods)<EOL>return response<EOL><DEDENT>try:<EOL><INDENT>data = json.loads(request.body.decode('<STR_LIT:utf-8>')) if request.body else {}<EOL>if require_token:<EOL><INDENT>token_string = request.GET['<STR_LIT>'] if request.method == '<STR_LIT:GET>' else data['<STR_LIT>']<EOL>try:<EOL><INDENT>token = ApiToken.objects.get(token=token_string)<EOL>token.save()  <EOL>data['<STR_LIT>'] = token<EOL><DEDENT>except ApiToken.DoesNotExist:<EOL><INDENT>logger.exception('<STR_LIT>'.format(token_string))<EOL>return ApiResponse(False, '<STR_LIT>', status=<NUM_LIT>)<EOL><DEDENT><DEDENT>return ApiResponse(data=view_func(request, data=data, *args, **kwargs))<EOL><DEDENT>except Exception as e:<EOL><INDENT>if e.__class__.__name__ == '<STR_LIT>':<EOL><INDENT>logger.exception('<STR_LIT>')<EOL>return ApiResponse(False, '<STR_LIT>'.format(e), status=<NUM_LIT>)<EOL><DEDENT>else:<EOL><INDENT>logger.exception('<STR_LIT>')<EOL>return ApiResponse(False, '<STR_LIT>'.format(e), status=<NUM_LIT>)<EOL><DEDENT><DEDENT><DEDENT>return _wrapped_view<EOL><DEDENT>return decorator<EOL>
View decorator that handles JSON based API requests and responses consistently.
:param methods: A list of allowed methods
:param require_token: Whether API token is checked automatically or not