def test_on_put_error_result(self): """ Test if we will receive correct response """ resource = CollectionResource(objects_class=FakeObjectClass) env = create_environ(path='/') req = Request(env) req.context = { 'doc': { 'id': 1, } } def clean(data): if 'name' not in data: return {}, {'name': ['Test Error Message']} resource.clean = clean resp = Response() resource.on_put(req=req, resp=resp) self.assertEqual(resp.body, {'errors': { 'name': ['Test Error Message'] }})
def on_get_search_by_url(self, req: Request, resp: Response): image_match_percent = req.get_param_as_int('image_match_percent', required=False, default=None) target_meme_match_percent = req.get_param_as_int('target_meme_match_percent', required=False, default=None) same_sub = req.get_param_as_bool('same_sub', required=False, default=False) only_older = req.get_param_as_bool('only_older', required=False, default=False) meme_filter = req.get_param_as_bool('meme_filter', required=False, default=False) filter_crossposts = req.get_param_as_bool('filter_crossposts', required=False, default=True) filter_author = req.get_param_as_bool('filter_author', required=False, default=True) url = req.get_param('url', required=True) filter_dead_matches = req.get_param_as_bool('filter_dead_matches', required=False, default=False) target_days_old = req.get_param_as_int('target_days_old', required=False, default=0) try: search_results = self.image_svc.check_image( url, target_match_percent=image_match_percent, target_meme_match_percent=target_meme_match_percent, meme_filter=meme_filter, same_sub=same_sub, date_cutoff=target_days_old, only_older_matches=only_older, filter_crossposts=filter_crossposts, filter_dead_matches=filter_dead_matches, filter_author=filter_author, max_matches=500, max_depth=-1, source='api' ) except NoIndexException: log.error('No available index for image repost check. Trying again later') raise HTTPServiceUnavailable('Search API is not available.', 'The search API is not currently available') print(search_results.search_times.to_dict()) resp.body = json.dumps(search_results, cls=ImageRepostWrapperEncoder)
def on_get_changes(self, req: Request, resp: Response): since = req.get_param_as_int('since', required=False, default=0) batch_size = req.get_param_as_int('batch_size', required=False, default=50) i = 0 end = False items = [] with scoped_session() as session: while i < batch_size and not end: obj = session.query(Change).filter(Change.id > since).first() if obj is None: end = True break item, errors = ChangeSchema().dump(obj) if errors is not None: errors_num = len(errors) if errors_num > 0: resp.status = HTTP_BAD_REQUEST resp.body = json.dumps({'errors': errors}) return if self.__can_read_change(req, item): items.append(item) since = since + 1 i = i + 1 resp.status = HTTP_OK resp.body = json.dumps(items)
def on_get_top_image_reposts(self, req: Request, resp: Response): days = req.get_param_as_int('days', default=30, required=False) limit = req.get_param_as_int('limit', default=100, required=False, max_value=2000) nsfw = req.get_param_as_bool('nsfw', default=False, required=False) results = [] with self.uowm.start() as uow: result = uow.stats_top_image_repost.get_all(days=days, nsfw=nsfw) for repost in result: post = uow.posts.get_by_post_id(repost.post_id) if not post: continue results.append({ 'post_id': post.post_id, 'url': post.url, 'nsfw': repost.nsfw, 'author': post.author, 'shortlink': f'https://redd.it/{post.post_id}', 'created_at': post.created_at.timestamp(), 'title': post.title, 'repost_count': repost.repost_count, 'subreddit': post.subreddit }) resp.body = json.dumps(results)
def _set_page_limit(self, request: Request) -> None: """Extract the limit from the request and set it in the context dict. The offset will be located under context['pagination']['limit'] :param request: The Falcon request """ if self._limit_key not in request.params.keys(): self._logger.info( f"No pagination limit in request, setting it to {self.default_limit}" ) request.context["pagination"]["limit"] = self.default_limit return try: limit = int(request.params[self._limit_key]) except ValueError: self._logger.warning( f"Pagination limit is not an integer, setting it to {self.default_limit}" ) request.context["pagination"]["limit"] = self.default_limit return if limit > self._max_limit or limit <= 0: self._logger.info(f"Pagination limit out of bound, setting it to {self.default_limit}") request.context["pagination"]["limit"] = self.default_limit return request.context["pagination"]["limit"] = limit
def on_get(self, req: falcon.Request, resp: falcon.Response, logo_id: Optional[int] = None): index_name = req.get_param("index", default=settings.DEFAULT_INDEX) count = req.get_param_as_int("count", min_value=1, max_value=500, default=100) if index_name not in INDEXES: raise falcon.HTTPBadRequest("unknown index: {}".format(index_name)) ann_index = INDEXES[index_name] if logo_id is None: logo_id = ann_index.keys[random.randint(0, len(ann_index.keys) - 1)] results = get_nearest_neighbors(ann_index, count, logo_id) if results is None: resp.status = falcon.HTTP_404 else: resp.media = {"results": results, "count": len(results)}
def on_get(self, req: falcon.Request, resp: falcon.Response): index_name = req.get_param("index", default=settings.DEFAULT_INDEX) count = req.get_param_as_int("count", min_value=1, max_value=500, default=100) logo_ids = req.get_param_as_list("logo_ids", required=True, transform=int, default=[]) if index_name not in INDEXES: raise falcon.HTTPBadRequest("unknown index: {}".format(index_name)) ann_index = INDEXES[index_name] results = {} for logo_id in logo_ids: logo_results = get_nearest_neighbors(ann_index, count, logo_id) if logo_results is not None: results[logo_id] = logo_results resp.media = { "results": results, "count": len(results), }
def on_get(self, req: falcon.Request, resp: falcon.Response, barcode: str): response: JSONType = {} count: int = req.get_param_as_int("count", min_value=1) or 1 lang: str = req.get_param("lang", default="en") server_domain: Optional[str] = req.get_param("server_domain") keep_types = QuestionFormatterFactory.get_default_types() insights = list( get_insights( barcode=barcode, keep_types=keep_types, server_domain=server_domain, limit=count, )) if not insights: response["questions"] = [] response["status"] = "no_questions" else: questions: List[JSONType] = [] for insight in insights: formatter_cls = QuestionFormatterFactory.get(insight.type) formatter: QuestionFormatter = formatter_cls(TRANSLATION_STORE) question = formatter.format_question(insight, lang) questions.append(question.serialize()) response["questions"] = questions response["status"] = "found" resp.media = response
def __strip_out_authorization_token(req: falcon.Request) -> str: if req.get_header('Authorization') is None: raise falcon.HTTPUnauthorized( title="No Authorization for this request", description="You haven't added `Authorization` to this request" ) return req.get_header('Authorization').split(" ")[1]
def on_patch_potential(self, req: Request, resp: Response, id: int): token = req.get_param('token', required=True) vote = req.get_param_as_int('vote', required=True, min_value=-1, max_value=1) user_data = get_user_data(token) if not user_data: raise HTTPUnauthorized('Invalid user token provided', 'Invalid user token provided') with self.uowm.start() as uow: template = uow.meme_template_potential.get_by_id(id) if not template: raise HTTPNotFound(title=f'Unable to find template with ID {id}', description=f'Unable to find template with ID {id}') existing_vote = next((x for x in template.votes if x.user == user_data['name']), None) if existing_vote and existing_vote.vote == vote: raise HTTPBadRequest(title='Invalid vote', description='You have already cast a vote for this template') elif existing_vote: template.vote_total += vote existing_vote.vote = vote else: template.vote_total += vote template.votes.append( MemeTemplatePotentialVote( post_id=template.post_id, user=user_data['name'], vote=vote, meme_template_potential_id=template.id ) ) uow.commit()
def on_post(self, req: falcon.Request, resp: falcon.Response): insight_id = req.get_param("insight_id", required=True) annotation = req.get_param_as_int("annotation", required=True, min_value=-1, max_value=1) update = req.get_param_as_bool("update", default=True) data = req.get_param_as_json("data") auth: Optional[OFFAuthentication] = parse_auth(req) username = auth.get_username() if auth else "unknown annotator" logger.info( "New annotation received from {} (annotation: {}, insight: {})". format(username, annotation, insight_id)) annotation_result = save_insight(insight_id, annotation, update=update, data=data, auth=auth) resp.media = { "status": annotation_result.status, "description": annotation_result.description, }
def process_request(self, req: Request, _: Response) -> None: """ Jsonify the request :param req: Request object :param _: Response (unused) :return None """ req.json = {} if req.method.upper() != 'POST': return if req.content_type is not None and 'multipart/form-data' in req.content_type: req.json = req.params elif req.content_type is not None and 'application/json' in req.content_type: try: body = req.stream.read(req.content_length or 0).decode("utf-8") req.json = json.loads(body) except (JSONDecodeError, UnicodeDecodeError, ValueError): raise HTTPBadRequest( 'Error', 'Invalid JSON structure. ({})'.format(body)) elif req.content_type is not None and 'x-www-form-urlencoded' in req.content_type: body = req.stream.read(req.content_length or 0).decode("utf-8") req.json = dict(parse_qsl(body)) else: raise HTTPBadRequest( 'Error', 'Unsupported content-type. ({}). Body: {}'.format( req.content_type, req.stream.read(req.content_length or 0).decode("utf-8")))
def on_post(self, req: falcon.Request, resp: falcon.Response): """ Get data and arguments """ result = self.manager.dict() status = self.manager.dict() # Get our parameters args = self.get_args(req) # We need to do the load here because we can't pass a stream to our # child process if hasattr(req.get_param('data'), 'file'): # Python requests adds an extra dict args['json_data'] = json.load(req.get_param('data').file) else: # Assume it's just straight text args['json_data'] = json.loads(req.get_param('data')) f = open("/var/tmp/wsgi.log", "w") f.write(str(args['json_data'])) uuid = self.jobs.create_job(req.path, self) proc = Process(target=self.community_detection, args=(args, status, result)) self.myjobs[uuid] = (proc, status, result) proc.start() resp.code = falcon.HTTP_200 resp.text = json.dumps({'job_id': str(uuid)})
def on_get_monitored_sub_with_history(self, req: Request, resp: Response): results = [] limit = req.get_param_as_int('limit', required=False, default=20) if limit == -1: limit = 1000 with self.uowm.start() as uow: checked = uow.image_search.get_by_subreddit( req.get_param('subreddit', required=True), limit=limit, offset=req.get_param_as_int('offset', required=False, default=None), only_reposts=req.get_param_as_bool('repost_only', required=False, default=False) ) for search in checked: r = { 'checked_post': None, 'search': search.to_dict(), } post = uow.posts.get_by_post_id(search.post_id) results.append({ 'checked_post': post.to_dict(), 'search': search.to_dict(), 'search': json.loads(search.search_results) }) resp.body = json.dumps(results)
def test_require_representation_unsupported_media_type(): resource = TestResource() # invalid content type format env = create_environ( body=json.dumps({ 'one': 'foo', 'two': 'foo' }), headers={'Content-Type': 'foo bar'}, ) with pytest.raises(falcon.HTTPUnsupportedMediaType): resource.require_representation(Request(env)) # valid format but surely unsupported (RFC-1437) env = create_environ( body=json.dumps({ 'one': 'foo', 'two': 'foo' }), headers={'Content-Type': 'matter-transport/sentient-life-form'}, ) with pytest.raises(falcon.HTTPUnsupportedMediaType): resource.require_representation(Request(env))
def on_get(self, req: Request, resp: Response): post_id = req.get_param('post_id', required=False, default=None) url = req.get_param('url', required=False, default=None) if not post_id and not url: log.error('No post ID or URL provided') raise HTTPBadRequest("No Post ID or URL", "Please provide a post ID or url to search") search_settings = get_image_search_settings_from_request(req, self.config) search_settings.max_matches = 500 post = None if post_id: with self.uowm.start() as uow: post = uow.posts.get_by_post_id(post_id) try: search_results = self.image_svc.check_image( url, post=post, search_settings=search_settings, source='api' ) except NoIndexException: log.error('No available index for image repost check. Trying again later') raise HTTPServiceUnavailable('Search API is not available.', 'The search API is not currently available') except ImageConversioinException as e: log.error('Problem hashing the provided url: %s', str(e)) raise HTTPBadRequest('Invalid URL', 'The provided URL is not a valid image') print(search_results.search_times.to_dict()) resp.body = json.dumps(search_results, cls=ImageRepostWrapperEncoder)
def on_get(self, req: falcon.Request, resp: falcon.Response): response: JSONType = {} insight_type: Optional[str] = req.get_param("type") country: Optional[str] = req.get_param("country") value_tag: Optional[str] = req.get_param("value_tag") server_domain: Optional[str] = req.get_param("server_domain") count: int = req.get_param_as_int("count", default=1, min_value=1, max_value=50) keep_types = [insight_type] if insight_type else None get_insights_ = functools.partial( get_insights, keep_types=keep_types, country=country, value_tag=value_tag, order_by="random", server_domain=server_domain, ) insights = [i.serialize() for i in get_insights_(limit=count)] response["count"] = get_insights_(count=True) if not insights: response["insights"] = [] response["status"] = "no_insights" else: response["insights"] = insights response["status"] = "found" resp.media = response
def on_post(self, req: falcon.Request, resp: falcon.Response): barcode = req.get_param("barcode", required=True) image_url = req.get_param("image_url", required=True) ocr_url = req.get_param("ocr_url", required=True) server_domain = req.get_param("server_domain", required=True) if server_domain != settings.OFF_SERVER_DOMAIN: logger.info("Rejecting image import from {}".format(server_domain)) resp.media = { "status": "rejected", } return send_ipc_event( "import_image", { "barcode": barcode, "image_url": image_url, "ocr_url": ocr_url, "server_domain": server_domain, }, ) resp.media = { "status": "scheduled", }
def _validate_patch(req: falcon.Request, _: falcon.Response, __, ___): """ Validate update player params. Args: req (falcon.Request): the client request resp (falcon.Response): the client response (so far) resource: params: Returns: Nothing on success. Raises a falcon.HTTPBadRequest on validation error with explanation in response body. """ errors = PlayerValidator.validate_patch(req.context["body"]) if errors: raise falcon.HTTPBadRequest("Bad request", errors) if "date_of_birth" in req.context["body"]: req.context["body"]["date_of_birth"] = dt.datetime.fromisoformat(req.context["body"]["date_of_birth"]) req.context["body"]["last_modified_utc"] = dt.datetime.utcnow() req.context["body"]["last_modified_by"] = req.context["body"]["username"]
def on_post(self, req: falcon.Request, resp: falcon.Response): source_value = req.get_param("source_value", required=True) source_type = req.get_param("source_type", required=True) target_value = req.get_param("target_value", required=True) target_type = req.get_param("target_type", required=True) auth = parse_auth(req) username = None if auth is None else auth.get_username() completed_at = datetime.datetime.utcnow() target_value_tag = get_tag(target_value) source_value_tag = get_tag(source_value) taxonomy_value = match_unprefixed_value(target_value_tag, target_type) query = LogoAnnotation.update( { LogoAnnotation.annotation_type: target_type, LogoAnnotation.annotation_value: target_value, LogoAnnotation.annotation_value_tag: target_value_tag, LogoAnnotation.taxonomy_value: taxonomy_value, LogoAnnotation.username: username, LogoAnnotation.completed_at: completed_at, } ).where( LogoAnnotation.annotation_type == source_type, LogoAnnotation.annotation_value_tag == source_value_tag, ) updated = query.execute() resp.media = {"updated": updated}
def test_require_representation_application_json(): resource = TestResource() # simple application/json content type env = create_environ( body=json.dumps({ 'one': 'foo', 'two': 'foo' }), headers={'Content-Type': 'application/json'}, ) representation = resource.require_representation(Request(env)) assert isinstance(representation, dict) # application/json content type with charset param env = create_environ( body=json.dumps({ 'one': 'foo', 'two': 'foo' }), headers={'Content-Type': 'application/json; charset=UTF-8'}, ) representation = resource.require_representation(Request(env)) assert isinstance(representation, dict)
def on_get_monitored_sub_checked(self, req: Request, resp: Response): with self.uowm.start() as uow: results = uow.monitored_sub_checked.get_by_subreddit( req.get_param('subreddit', required=True), limit=req.get_param_as_int('limit', required=False, default=20), offset=req.get_param_as_int('offset', required=False, default=None) ) resp.body = json.dumps([r.to_dict() for r in results])
def test_slots_request(self): env = testing.create_environ() req = Request(env) try: req.doesnt = 'exist' except AttributeError: pytest.fail('Unable to add additional variables dynamically')
def on_get(req: falcon.Request, resp: falcon.Response): database = connect(constants.DB_URL) current_analyses_table = database[constants.CURRENT_ANALYSES_TABLE] if req.get_param(constants.TWEET_TOPIC_TABLE_KEY_NAME): if current_analyses_table.find_one( analysis_topic_id=req.get_param_as_int( constants.TWEET_TOPIC_TABLE_KEY_NAME)): resp.status = falcon.HTTP_OK resp.body = dumps({'currently_analysing': True}) else: resp.status = falcon.HTTP_OK resp.body = dumps({'currently_analysing': False}) elif req.get_param(constants.TWEET_USER_TABLE_KEY_NAME): if current_analyses_table.find_one( analysis_user_id=req.get_param_as_int( constants.TWEET_USER_TABLE_KEY_NAME)): resp.status = falcon.HTTP_OK resp.body = dumps({'currently_analysing': True}) else: resp.status = falcon.HTTP_OK resp.body = dumps({'currently_analysing': False}) elif req.get_param('all'): data = {'current_analyses': []} current_analyses = current_analyses_table.all() for current_analysis in current_analyses: if current_analysis[constants.TWEET_TOPIC_TABLE_KEY_NAME]: if current_analysis['is_hashtag']: data['current_analyses'].append({ 'type': 'hashtag', 'analysis_topic_id': current_analysis[ constants.TWEET_TOPIC_TABLE_KEY_NAME] }) else: data['current_analyses'].append({ 'type': 'topic', 'analysis_topic_id': current_analysis[ constants.TWEET_TOPIC_TABLE_KEY_NAME] }) elif current_analysis[constants.TWEET_USER_TABLE_KEY_NAME]: data['current_analyses'].append({ 'type': 'user', 'analysis_user_id': current_analysis[constants.TWEET_USER_TABLE_KEY_NAME] }) resp.status = falcon.HTTP_OK resp.body = dumps(data) else: resp.status = falcon.HTTP_NOT_FOUND
def on_get_reposters(self, req: Request, resp: Response): days = req.get_param_as_int('days', default=30, required=False) limit = req.get_param_as_int('limit', default=100, required=False, max_value=2000) nsfw = req.get_param_as_bool('nsfw', default=False, required=False) results = [] with self.uowm.start() as uow: result = uow.session.execute("SELECT author, COUNT(*) c FROM image_reposts WHERE author is not NULL AND author!= '[deleted]' AND detected_at > NOW() - INTERVAL :days DAY GROUP BY author HAVING c > 1 ORDER BY c DESC LIMIT 1000", {'days': days}) results = [{'user': r[0], 'repost_count': r[1]} for r in result] resp.body = json.dumps(results)
def process_request(self, req: falcon.Request, _: falcon.Response) -> None: """ Process the request before routing it. """ if req.path not in self._excluded_resources: req.context['received_at'] = datetime.now() req.context['body'] = {} if req.content_length: req.context['body'] = json.load(req.bounded_stream)
def get_filter(self, req: Request, resp: Response, query: Query, *args, **kwargs): limit = req.get_param_as_int('__limit') if not isinstance(limit, int): limit = 10 req.params['__limit'] = limit if limit > 1000: req.params['__limit'] = 1000 return query
def process_request(self, req: Request, resp: Response): self.context.logger.debug(f'process_request: {req.method} {req.path}') if req.method == 'POST': if req.content_type != 'application/jose+json': raise UnsupportedMediaTypeMalformed( detail=f'{req.content_type} is an unsupported media type') data = req.media token = f'{data["protected"]}.{data["payload"]}.{data["signature"]}' headers = jws.get_unverified_headers(token) protected = json.loads(b64_decode(data['protected'])) self.context.logger.debug(f'(Unverified) headers: {headers}') if headers.get('kid') and protected.get('jwk'): raise Unauthorized( detail='The "jwk" and "kid" fields are mutually exclusive') if headers.get('url') != req.uri: raise Unauthorized( detail=f'JWS header URL ({headers.get("url")})' f' does not match requested URL ({req.uri})') # Existing account kid = headers.get('kid', None) account = self.context.get_account_using_kid(kid) if account: if account.status != 'valid': self.context.logger.info(f'Account {account} deactivated') raise Unauthorized(detail='Account deactivated') self.context.logger.info( f'Authenticating request for account {account}') req.context['account'] = account jwk = account.jwk # Account registration elif req.path.endswith('/new-account') or req.path.endswith( '/new-account/'): jwk = protected['jwk'] if protected['alg'] not in SUPPORTED_ALGORITHMS: raise BadSignatureAlgorithm( algorithms=SUPPORTED_ALGORITHMS) req.context['account_creation'] = True else: self.context.logger.warning( f'Account not found using kid {kid}') raise Unauthorized(detail='Account not found') try: ret = jws.verify(token, jwk, algorithms=SUPPORTED_ALGORITHMS) except JOSEError as e: self.context.logger.error( f'Exception while verifying token: {e}') raise ServerInternal(detail=f'{e}') self.context.logger.debug(f'Verified data: {ret}') req.context['jose_verified_data'] = ret req.context['jose_headers'] = headers
def get_read_params(req: falcon.Request, resource: Type["BaseResource"]) -> dict: params = { "include": req.get_param_as_list("include"), "sort": req.get_param_as_list("sort"), "limit": req.get_param_as_int("limit"), "offset": req.get_param_as_int("offset"), "filters": FilterItem.parse(req._params, resource), } return params
def on_post(self, req: falcon.Request, resp: falcon.Response) -> None: """Support POST method.""" key: str = req.get_param('key') value: Any = req.get_param('value') self.log.debug(f'DEBUG {key} {value}') self.log.info(f'INFO {key} {value}') self.log.warning(f'WARNING {key} {value}') self.log.error(f'ERROR {key} {value}') self.log.critical(f'CRITICAL {key} {value}') resp.body = f'Logged - {key}'
def on_post_offchain(self, req: falcon.Request, resp: falcon.Response) -> None: request_id = req.get_header(offchain.X_REQUEST_ID) resp.set_header(offchain.X_REQUEST_ID, request_id) request_sender_address = req.get_header(offchain.X_REQUEST_SENDER_ADDRESS) input_data = req.stream.read() resp_obj = self.app.offchain_api(request_id, request_sender_address, input_data) if resp_obj.error is not None: resp.status = falcon.HTTP_400 resp.body = self.app.jws_serialize(resp_obj)
def _set_page_offset(self, request: Request) -> None: """Extract the offset from the request and set it in the context dict. The offset will be located under context['pagination']['offset'] :param request: The Falcon request """ if self._offset_key not in request.params.keys(): request.context["pagination"]["offset"] = 0 return try: request.context["pagination"]["offset"] = int(request.params[self._offset_key]) except ValueError: self._logger.warning(f"Pagination offset is not an integer, setting it to 0") request.context["pagination"]["offset"] = 0
def on_get(self, req: falcon.Request, res: falcon.Response): nickname = req.get_param('nickname') if nickname: user = r.db(DB_NAME).table(DB_TABLE_USERS).get(nickname).run(conn) if self.user and self.user['nickname'] == user['nickname']: response = user_schema_internal.dumps(user) else: response = user_schema_external.dumps(user) else: users = r.db(DB_NAME).table(DB_TABLE_USERS).run(conn) response = user_schema_external.loads(list(users), many=True) res.body = response.data
def on_patch(self, req: falcon.Request, res: falcon.Response): # todo: use salted password if self.auth_error: raise self.auth_error nickname = req.get_param('nickname') if not nickname: raise falcon.HTTPMethodNotAllowed(ERROR_INVALID_REQUEST) if self.user and self.user['nickname'] == nickname: result = r.db(DB_NAME).table(DB_TABLE_USERS).update(self.data).run(conn) res.body = json.dumps(result) else: raise falcon.HTTPUnauthorized('Unauthorized Error', ERROR_INVALID_REQUEST)
def on_get(self, req: falcon.Request, resp: falcon.Response): user_resp = req.get_param('g-recaptcha-response') resp.body = templates.get_template('register.html').render() resp.status = falcon.HTTP_200 resp.content_type = 'text/html' if user_resp and verify_recaptcha(user_resp, 'captcha_secret'): with db.transaction(): dash = Dash() dash.api_key = hashlib.sha1(os.urandom(2 ** 13)).hexdigest() dash.dash_id = hashlib.sha1(os.urandom(2 ** 13)).hexdigest() dash.save() resp.status = falcon.HTTP_201 resp.body = templates.get_template('register_after.html').render(api_key=dash.api_key, dash_id=dash.dash_id) elif user_resp: resp.status = falcon.HTTP_400 resp.body = templates.get_template('register.html').render()
def response(self, data): kwargs = {} if Request.get_header('X-Requested-With') == 'XMLHttpRequest' else {'indent': 2} Response.body = json.dumps(data, **kwargs) Response.content_type = 'application/json'