Pull to refresh

Comments 21

Не зря на yiiframework.ru/forum/ я просил у вас больше документации. Так гораздо лучше, спасибо, пригодится.
Хорошая наработка. Возьму на заметку.
Вот версионность API конечно спорный вопрос.
Вообще советовал бы еще по сабжу посмотреть вот этот доклад. Много интересных мыслей.

Кстати, чем не понравилось вот это решение http://www.yiiframework.com/wiki/175/how-to-create-a-rest-api?

По поводу версионности — спорный вопрос сама версионность или её реализация?
Я считаю вполне приемлемым то, что версионность поддерживается на уровне роутов, т.к. изменение нескольких параметров не должно приводить к смене версии, а новый код естественно будет писаться в новых модулях/контроллерах/экшенах, которые внутри можно удобно именовать, а снаружи просто прилинковать с соответствующей версией.

В приведенной ссылке на How-To по REST API, не идет речь о том чтобы добавить API к существующей бизнес-логике, там просто приведен пример построения ответов. Ошибки приложения (эксепшены, ворнинги) там также никак не обрабатываются, ошибки валидации форм отдаются в html и без возможности определения типа ошибки. Да и просто много оверхеда по приведенному коду.
Но как тема для размышлений — вполне нормальный пример.
Плюсую за видео, тоже рекомендую.
Интересный доклад, как-то его раньше не видел. Жаль что эллементы гипермедиа не так уж часто можно встретить в апишках.
if ($this->isPost() && ($data = $_POST)) {

Почему так, а не проверять на уровне роутов, или же более обычным способом?:
if (Yii::app()->request->isPostRequest) {


И что за ужасный && ($data = $_POST)?
А что Вы собираетесь проверять на уровне роутов? Я в тексте достаточно чётко объяснил, что экшен по GET запросу отдает форму, по POST добавляет запись.

Метод isPost добавлен для семантики, в месте с методами isPut и isDelete которые обдадают расширенной функциональностью по ср. с базовыми — github.com/paysio/yii-rest-api/blob/master/library/rest/controller/Behavior.php. Да и просто так писать меньше =)

($data = $_POST) в таком виде действительно особого смысла не имеет, но присутствует здесь т.к. работать с переменной $_POST напрямую — плохая практика, которая, между тем, в Yii используется. Хорошим примером является предоставление единой точки доступа, как, например, тут — github.com/zendframework/zf2/blob/master/library/Zend/Http/Request.php
В Yii тоже есть единая точка доступа Yii::app()->request->getPost('name'), но почему-то исторически повелось обращаться напрямую…
Не совсем так, в Yii метод getPost оперирует с переменной $_POST
    public function getPost($name,$defaultValue=null)
    {
        return isset($_POST[$name]) ? $_POST[$name] : $defaultValue;
    }

когда как в Zend-е данные хранятся в $this->postParams
    public function getPost($name = null, $default = null)
    {
        if ($this->postParams === null) {
            $this->postParams = new Parameters();
        }

        if ($name === null) {
            return $this->postParams;
        }

        return $this->postParams->get($name, $default);
    }
А в чем профит то? Ну работаете через $_POST, ну и что с того? В Yii есть обертка которая удобнее, в плане того что там есть возможность указать значение по умолчанию. В Zend по сути тоже самое, просто данные представлены в ОО виде, ну мол так как бы более по феншую. Есть ли там обработка данных перед записью в массив, это уже другой вопрос.

А так делать $data = $_POST это… просто переименовать переменную, содержащую массив неблагонадежных данных. Смысла в этом нету.
Так это, действительно, если нужно расшарить какой-то объект между классами, зачем парится и использовать паттерн Registry martinfowler.com/eaaCatalog/registry.html, лучше его наверно в переменную $GLOBALS записать.

Переменная $_POST содержит исходные данные запроса, и не предназначена для того, чтобы в неё писали что-то, в то время как с лёгкой руки программистов Yii она активно меняется, в том числе и самим фреймворком.
Почему это плохо — один из примеров, представим что у нас есть система которая логирует обращения к сервису, а затем выводит эти логи пользователям данного сервиса, чтобы они могли проконтролировать насколько верно их приложение работает с API. Но при такой модели работы с переменной $_POST в ней может оказаться всё что угодно, ещё до того как она будет записана в базу. Естественно можно извернуться и записывать всегда нескомпроментированные данные, но я повторяю — это плохой дизайн.

Теперь последний раз по поводу $data = $_POST на этом месте должно быть что-то вроде $data = $this->getPost(), но даже в простом присваивании переменной $_POST к $data есть смысл, если в дальнейшем будет написано что-то вроде $data['user_id'] = Yii::app()->user->getId();
    if (isset($_POST) && ($data = $_POST)) { // проверяем отправлен ли POST запрос 
        $data['user_id'] = Yii::app()->user->getId();
        $model->attributes = $data; // пишем в модель новые атрибуты
        if ($model->save()) { // проверяем атрибуты, если валидны - то сохраняем
            $this->redirect(array('view', 'id' => $model->id));
        }
    }

или что-то в этом духе, в общем, я не вижу смысла это больше обсуждать.

Если есть желание по коду подискутировать, давайте обсудим лучше какие-то сложные/спорые моменты в самой библиотеке.
Можете подсказать, в каких местах Yii Framework изменяет переменную $_POST?
Мое мнение по этому поводу: лучше работать через обертку Yii::app()->request->..., т.к. в таком случае у нас появляется возможность переопределить request, наследовать методы в каких либо целях. Например, вызывать определенную функциональность при попытке получения данных из запроса.
Использовать $_POST конечно же никто не запрещает. Просто использовать API фреймверка — «удобней», т.к. гипотетически дает больше «свободы» в будущем.
Смешивать REST контроллеры и обычные контроллеры — плохая практика. Дублирование кода в контроллерах нормальное явление, а бизнес логика по умолчанию должна быть удалена из контроллера и перенесена в модели/сервисы.
Никто не спорит, что тонкие контроллеры — это хорошо, но чем по вашему «обычные контроллеры» отличаются от обрабатывающих REST-запросы, если они выполняют одну и туже функцию — получают данные и добавляют запись. В то время, как вся логика добавления записи может и должна быть зашита внутри модели, а сложная логика обработки в сервис.
Хм, а куда тогда деть логику REST контроллеров? Т.е. в какой сервисный слой вынести ту логику которая там была?
В идеале я бы хотел видеть REST API в виде какого-то сервиса, который можно использовать в контроллере, но так редко выходит. Да и редко выходит красиво, когда у тебя REST контроллер и обычный контроллер — это один и тот же класс. Обычно приходится разносить по разным контроллерам.
Всё просто, ошибка тут:

class RestUserController extends Controller
{
    ....

    public function render($view, $data = null, $return = false, array $fields = null /* значение по умолчанию было - пустой массив, что означает - НИЧЕГО наружу не отдавать */)
    {
А зачем понадобилась обязательно переформатировать JSON?

class Json implements AdapterInterface
{
   ...


     /**
     * Pretty-print JSON string from ZendFramework
     *
     * Use 'indent' option to select indentation string - by default it's a tab
     *
     * @param string $json Original JSON string
     * @param array $options Encoding options
     * @return string
     */
    public static function prettyPrint($json, $options = array())
    {


1. Это излишнее украшательство — реализовать user friendly просмотр JSON лучше на стороне получателя
2. Это непроизводительно — делать разбор посредством интерпретируемого языка

Как минимум можно поставить проверку на if (defined(YII_DEBUG) && YII_DEBUG))
Sign up to leave a comment.

Articles