- PVSM.RU - https://www.pvsm.ru -
За последнее время очень многие веб-фреймворки обзавелись RESTful роутингом. Более того, REST стал де-факто стандартом проектирования архитектуры веб-приложений. Практически все более-менее значимые сервисы обзавелись RESTful API с представлением данных через xml и json форматы. Такой популярности REST помогло как появление большого количества руководств, так и горячие обсуждения REST среди специалистов.
Вместе с тем, REST до сих пор воспринимается скорее как некоторый набор правил роутинга, а всё что не связано в прямую с роутингом решается произвольным путём, в частности это касается обработки ошибок в RESTful-приложениях.
Рассмотрим некоторое веб-приложение в котором пользователь может динамически добавить статью article
в список статей self.articles
. Обычно при динамической реализации используется такой подход:
Т.е. в коде на javscript + jQuery и Ruby это могло бы выглядеть так:
$.post('articles', {title: 'title', text: 'text'}, 'json').done(function(article_data){
if(response.status == 'ok'){
self.articles.push(article_data);
}else{
var messages = response.messages;
// Обработать ошибку валидации и вывести сообщения
}
}).fail(function(response){
// Обработать ошибку сервера или соединения
});
А это пример контроллера на Ruby on Rails. Это далеко не идеальный код, но часто встречающийся в таком виде. Результат выполнения метода create
не влияет на статус код HTTP:
def ArticlesController < ApplicationController
def create
@article = Article.new
@article.title = params[:title]
@article.text = params[:text]
# ... какие-то действия ...
if not @article.valid?
render json: {status: 'error', messages: @article.errors.messages}
end
@article.save
render json: @article
end
end
Плюсы:
В таком подходе есть несколько слабых мест:
Т.к. RESTful уже подразумевает наложение некоторых ограничений, то такой же подход можно применить и по отношению к ошибкам. Т.е. использовать для обработки ошибок статус коды HTTP, подобно тому как ресурсы отображают доступные модели и контроллеры. Так, например, для уведомления о невалидных данных можно использовать ошибку 422 Unprocessable Entity
, а список невалидных полей передавать непосредственно в виде массива в теле ответа:
$.post('articles', {title: 'title', text: 'text'}, 'json').done(function(response){
var article = response.data;
self.articles.push(article);
}).fail(function(e, ){
switch(e.status){
case 422:
var messages = response.responseText;
// Обработать ошибку валидации и вывести сообщения
default:
// Обработать ошибку сервера или соединения
}
});
При реализации контроллера есть смысл разнести обработку ошибок по разным rescue блокам.
Так, в случае если поля окажутся невалидными, выполнится первый rescue-блок. Если случится какая-то иная ошибка с валидными данными, то сработает последний rescue. Таким образом, на стороне клиента можно отлавливать ошибки без привлечения дополнительных статус-полей в json.
def ArticlesController < ApplicationController
def create
@article = Article.new
@article.title = params[:title]
@article.text = params[:text]
# ... какие-то действия ...
# ! возбуждает исключение если есть невалидные поля
@article.save!
render json: @article
rescue Mongoid::Errors::Validations
render json: @article.errors.messages, status: 422
rescue
render text: 'Internal server error', status: 500
end
end
Плюсы:
Недостатки:
Как вариант, для расширения существующих статусов можно добавлять поля в заголовок, например X-Status-Reason: Validation failed
В 70% случаев мне удаётся ограничится данными статус кодами HTTP:
200 OK |
Штатный ответ, у пользователя есть права на доступ к ресурсу |
404 Not Found |
Ресурса с данным id не существует |
403 Forbidden |
Попытка доступа к ресурсу на которого у пользователя нет прав. |
409 Conflict |
Попытка создания дублирующего ресурса, например регистрация пользователя с существующим в БД email'ом. |
422 Unprocessable Entity |
Форма с невалидными данными. |
500 Internal Server Error |
В случае какого-то непредвиденного исключения. |
Тем не менее вопрос, какие коды использовать в конкретном случае может зависит от многих факторов.
Поэтому привожу полезные обсуждения на стековерфлоу:
REST HTTP status codes [1]
Proper use of HTTP status codes in a “validation” server [2]
Руководство по роутингу в Ruby on Rails:
Rails Routing from the Outside In [3]
Диссертация Роя Филдинга по REST:
Fielding, Roy Thomas. Architectural Styles and the Design of Network-based Software Architectures. Doctoral dissertation, University of California, Irvine, 2000. [4]
Автор: kreshikhin
Источник [5]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/json/52282
Ссылки в тексте:
[1] Image: http://stackoverflow.com/q/3290182/1062636
[2] Image: http://stackoverflow.com/q/362618/1062636
[3] Image: http://guides.rubyonrails.org/routing.html
[4] Fielding, Roy Thomas. Architectural Styles and the Design of Network-based Software Architectures. Doctoral dissertation, University of California, Irvine, 2000.: http://www.ics.uci.edu/~fielding/pubs/dissertation/top.html
[5] Источник: http://habrahabr.ru/post/208404/
Нажмите здесь для печати.