2017-08-24 86 views
0

我使用的瓶的RESTful創建API端點和我指定的URL這樣JSON響應自定義的參數驗證給定的參數不是int,它會返回一個HTML響應。與瓶的RESTful

我怎樣才能返回一個自定義的JSON錯誤響應,例如:

except InvalidParameter as err: 
      abort(err.status_code, **err.to_dict()) 

檢查這種方式也行不通了值,參數的類型始終爲字符串

class SpecificProject(Resource): 
    def get(self, project_id): 
     print("DEBUG: project_id is [", project_id, "]", file=sys.stderr) 
     print("DEBUG: Type is [", type(project_id), "]", file=sys.stderr) 
     if isinstance(project_id, int): 
      pass 
     else: 
      message = "'{}' is not a valid project_id. Hint: this is a number representing primary key.".format(project_id) 
      errors = {} 
      errors['resource'] = "Project" 
      errors['field'] = "project_id" 
      errors['code'] = "invalid" 
      errors['stack_trace'] = "" 
      abort(400, message=message, errors=errors) 

輸出:

DEBUG: project_id is [ 1 ] 
DEBUG: Type is [ <class 'str'> ] 
+0

我的理解,你想用'project_id'工作與'INT '並將請求參數的驗證移動到其他級別(從視圖中)? –

+0

是的,我想確保'project_id'是'int'。如果不是,我想返回自定義的JSON錯誤消息 – hanxue

+0

我以前有同樣的問題。我一直在尋找解決方案。 Flask沒有現代的驗證方式(通過類型轉換)。您可以使用Flask-WTF或RequestParser驗證POST或GET參數。但是這個工具不會將值轉換爲指定的類型。此外,他們對請求參數進行繁瑣的描述。你可以嘗試[this](https://github.com/d-ganchar/flask_request_validator)工具。目前這個庫不支持Flask-RESTful('from box'),但是這是一個小型庫,你可以擴展它。 –

回答

0

我的解決方案是擴展Flask-RESTful Api clas並實現我的自定義錯誤處理程序。該official documentation explains a little bit about extending,但沒有進入足夠的細節。

自定義錯誤消息

在我的應用程序的所有錯誤是在這個結構中

class InvalidParameter(Exception): 
    status_code = 400 

    def __init__(self, message, status_code=None, resource=None, 
       field=None, code=None, stack_trace=None): 
     Exception.__init__(self) 
     self.message = message 
     if status_code is not None: 
      self.status_code = status_code 
     self.resource = resource 
     self.field = field 
     self.code = code 
     self.stack_trace = stack_trace 

    def to_dict(self): 
     rv = {} 
     errors = {} 
     rv['message'] = self.message 
     errors['resource'] = self.resource 
     errors['field'] = self.field 
     errors['code'] = self.code 
     errors['stack_trace'] = self.stack_trace 
     rv['errors'] = errors 
     return rv 

這是默認瓶的RESTful返回

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> 
<title>404 Not Found</title> 
<h1>Not Found</h1> 
<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p> 

輸出應該是JSON,在這種格式

{ 
    "message": "The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. You have requested this URI [/projects/1asd] but did you mean /projects/<int:project_id> or /projects or /project/new ?", 
    "errors": { 
     "resource": null, 
     "field": null, 
     "code": "invalid_url", 
     "stack_trace": null 
    } 
} 

解決方案

擴展Api類,並覆蓋了404錯誤

class CustomApi(Api): 
    def handle_error(self, e): 
     code = getattr(e, 'code', 404) 
     if code == 404: 
      response_dict = Api.handle_error(self, e).__dict__ 
      resp_message = response_dict['response'][0] 
      error_message = re.sub(r'.*"(.*)".*', r'\1', resp_message.decode('utf-8'), flags=re.DOTALL) 
      err = InvalidParameter(error_message, stack_trace=None, 
            resource=None, code="invalid_url", field=None) 
      return self.make_response(err.to_dict(), 404) #{'message': "something", 'error': {'sub1': 'val1'}}, 404) 

     return super(Api, self).handle_error(e) 

handle_error字典是在這種格式handle_error方法

{'headers': Headers([('Content-Type', 'application/json'), ('Content-Length', '263')]), '_status_code': 404, '_status': '404 NOT FOUND', 'direct_passthrough': False, '_on_close': [], 'response': [b'{\n "message": "The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. You have requested this URI [/projects/1asd] but did you mean /projects/<int:project_id> or /projects or /project/new ?"\n}\n']} 

我想重新使用'response':'message'這是生成,但不是默認格式。 message不是沒有正確JSON格式的,所以我去掉一切,除了爲message內容,使用此正則表達式

error_message = re.sub(r'.*"(.*)".*', r'\1', resp_message.decode('utf-8'), flags=re.DOTALL) 

注意re.DOTALL需要剝離出來,是由瓶的RESTful加入\n

即實際編制JSON響應的代碼是self.make_response(err.to_dict(), 404)

對於所有其他非404錯誤(例如400,500,503),該錯誤只是沿着原來的瓶的RESTful API類通過。

注意,當您創建瓶的應用程序,您需要使用您的自定義API類,並捕獲所有的404錯誤:

app = Flask(__name__) 
api = CustomApi(app, catch_all_404s=True) 
+0

燒瓶 - 骯髒的黑客輕鬆/基本任務...))) –

+0

我還是喜歡Flask的簡單性,與全功能替代品相比,如Django – hanxue