Что за мода пошла? REST-like HTML CRUD

Проверенные VDS на SSD в Европе от $4 и России: Датацентр №1 от 199руб

Тема в разделе "Вопросы по теории программирования", создана пользователем Adelf, 5 апр 2016.

  1. Adelf

    Adelf Laravel&PhpStorm Команда форума

    Сообщения:
    3.128
    Ваш город:
    Казань
    Address:
    Kazan, Russia
    Country:
    Location on Map:
    Уже не первый раз замечаю, что народ, особенно в Laravel, начал делать обычные HTML CRUD приложения, используя контроллеры для REST. Эмулируя PUT и DELETE методы(ларвель это умеет) получается почти REST, но через HTML.
    Я этому очень плохо отношусь, но раз народ делает... хочу знать зачем. Там банально неудобно.. каждой форме свой экшен вешать(у меня почти все формы идут на ту же страницу, но через POST. привык уже).
    Мож тут тоже кто-то такой же? Расскажет зачем. Все эти эмуляции через эмуляции для меня... как надувные женщины :)
     
  2. флоппик

    флоппик promotor fidei Команда форума Партнер клуба

    Сообщения:
    4.795
    Ваш город:
    Павлодар, Казахстан
    Address:
    Pavlodar, Kazakhstan
    Country:
    Location on Map:
    code-generation + sane method naming + automatic api implemetation.
    Ну и программисты же, не для людей делают, для машин и для других программистов.
     
  3. c0dex

    c0dex web.dev 2002-... Команда форума Партнер клуба

    Сообщения:
    7.515
    Ваш город:
    Moscow, Russia
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    Зафигачил у себя CRUD, 4 метода для сущности. Отдельные шаблоны. Удобно. Но метод PUT я не эмулирую, только DELETE через AJAX запрос.
     
  4. WMix

    WMix герр M:)ller Партнер клуба

    Сообщения:
    5.961
    Ваш город:
    Berlin
    Address:
    Berlin, Germany
    Country:
    Location on Map:
    @Adelf, это html эмулирует PUT и DELETE a Laravel их великолепно понимает как и эмуляцию. а идея как раз написать и на голом html и с поддержкой js
     
  5. Adelf

    Adelf Laravel&PhpStorm Команда форума

    Сообщения:
    3.128
    Ваш город:
    Казань
    Address:
    Kazan, Russia
    Country:
    Location on Map:
    как? Там контроллеры все равно в ответ дают HTML.
     
  6. WMix

    WMix герр M:)ller Партнер клуба

    Сообщения:
    5.961
    Ваш город:
    Berlin
    Address:
    Berlin, Germany
    Country:
    Location on Map:
    это как отрендишь у меня контроллеры отдают array a дальше стратегия _format и можно в json завернуть
     
  7. Adelf

    Adelf Laravel&PhpStorm Команда форума

    Сообщения:
    3.128
    Ваш город:
    Казань
    Address:
    Kazan, Russia
    Country:
    Location on Map:
    А ну это уже интересней. Просто я вижу это в контроллерах, которые отдают сразу HTML view... и не понимаю зачем там этот REST-like стиль.
     
  8. WMix

    WMix герр M:)ller Партнер клуба

    Сообщения:
    5.961
    Ваш город:
    Berlin
    Address:
    Berlin, Germany
    Country:
    Location on Map:
    делаешь config
    id => [route, controller, view]
    отлавливаешь событие у меня onKernelView на silex
    a дальше if( $event->getRequest() ... )
     
  9. c0dex

    c0dex web.dev 2002-... Команда форума Партнер клуба

    Сообщения:
    7.515
    Ваш город:
    Moscow, Russia
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    Затем, что это удобно =D
     
    Hello нравится это.
  10. Вурдалак

    Вурдалак Newbie

    Сообщения:
    6.032
    Ваш город:
    Russia, Moscow
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    В качестве оффтопика: вас никогда не посещала мысль, что король-то голый REST иногда выглядит сомнительно? Вы работаете с API, который выглядит, как анемичная модель. Вы ограничены HTTP-глаголами GET, PUT, POST, DELETE, то время как вам нужно ими отражать реальные бизнес-действия.

    Как пример: вы хотите забанить юзера. Что вы будете делать? Писать POST /users/42 {"banned": true}? Или POST /users/42/ban?
    Если допустить, что первое, то такой API становится достаточно скудным: вы не знаете какие действия возможно таким образом описать, потому что нельзя просто так выставлять какие-то свойства, в реальности-то будет вызываться какой-нибудь $user->ban(), а не $user->setBanned(true). Я думаю, не нужно объяснять, почему это так.
    Если второе, то это приведет к тому, что вы просто будете писать POST /users/42/<commandName>, т.е. вы будете выполнять те же команды, только записанные, вероятно, в менее удобном формате. Почему бы тогда просто не написать POST /commands/ {"command": "BanUser", "payload": {"id": 42}} и не выводить список всех таких команд в документацию?

    Я для себя пришёл к тому, что для запросов на изменение нужно работать с чем-то а-ля JSON RPC.
     
    Последнее редактирование: 5 апр 2016
  11. Adelf

    Adelf Laravel&PhpStorm Команда форума

    Сообщения:
    3.128
    Ваш город:
    Казань
    Address:
    Kazan, Russia
    Country:
    Location on Map:
    Мне всегда RPC вариант нравился больше. Мы всегда просим API сделать что-нибудь. Выбрать сущности, добавить, удалить(не говоря уже о том, что написал Вурдалак). Т.е. главное - глагол. И процедуры под это подходят больше. Чем тщательно спрятанные в HTTP-методы глаголы.
     
  12. WMix

    WMix герр M:)ller Партнер клуба

    Сообщения:
    5.961
    Ваш город:
    Berlin
    Address:
    Berlin, Germany
    Country:
    Location on Map:
    или POST /users/42 {"name": 'Pupkin'}
    до тех пор пока возможно почему бы и нет... но и параллельно POST /users/42/ban ничего не мешает сделать я не понимаю твою проблему
    яб наоборот сказал, для этих 4х уже придумывать ничего не надо

    али тебя CRUD в рамках держит?
     
    Hello нравится это.
  13. Вурдалак

    Вурдалак Newbie

    Сообщения:
    6.032
    Ваш город:
    Russia, Moscow
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    OK, а теперь выяснится, что юзер не может быть переименован, если он заблокирован:
    PHP:
    final class User
    {
        public function 
    rename(Name $newName) {
            
    Assertion::false($this->banned'Banned user cannot be renamed');
            
    $this->name $newName;
        }
    }
    Что твой метод должен вернуть при запросе POST /users/42 {"name": "Blah", "banned": false}? С точки зрения клиента может показаться, что ошибка о блокировке неуместна, т.к. одновременно с переименованием я посылаю флаг разблокировки, но каким образом внутри мы можем понять в каком порядке нужно выполнять соответствующие бизнес-действия, т.е. что сначала нужно выполнить UnbanUser, а лишь затем — RenameUser?

    Далее, теперь представь, что мы отправляем юзера на перемодерацию, если он сменил имя:
    PHP:
    final class User
    {
        public function 
    rename(Name $newName) {
            
    Assertion::false($this->banned'Banned user cannot be renamed');
            
    $this->name $newName;
            
    $this->status Status::moderation();
        }
    }
    Сам по себе метод /users/42 будет возвращать скорее всего и name, и status. При этом при переименовании ты меняешь одно свойство, но в результате меняются 2. Более того, нужно каким-то образом дать понять клиенту, что поля неравнозначные и он не может напрямую менять status, т.е. это read-only поле.

    Т.е. возникает leaky abstraction: якобы ты можешь работать с ресурсом, как с пачкой свойств, но в реальности всё сложнее.

    Далее возникнут проблемы документирования: если для одних действий могут быть одни ошибки, для других — другие, то метод POST /users/42 будет содержать кучу возможных errorCode'ов, в то время как на, допустим, то же переименование может быть только 2 errorCode'а, но клиенту придётся поддерживать все 10, т.к. неочевидно какие из них когда могут «выстрелить». Один большой жирный анемичный метод, который делает хрен сколько всего. Не круто.

    Это неконсистентность. Такой API труднее понимать. То так, то эдак.
     
    Последнее редактирование: 5 апр 2016
  14. Вурдалак

    Вурдалак Newbie

    Сообщения:
    6.032
    Ваш город:
    Russia, Moscow
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    Ещё один пример в догонку: а теперь нужно сделать метод на принудительную отправку юзера не перемодерацию. Внимание вопрос: каким образом этот метод будет выглядеть? POST /users/42/ {"status": "moderation"}? Выглядит так, словно мы можем менять статус напрямую? Это не так. Это просто такой синтаксис для команды SendUserForModeration. Это неочевидно.

    Также иногда возникают различные способы создания сущности. К примеру, обычная рега и через партнёра. В случае команд будет две явные команды: RegiserUser, RegisterUserViaPartner. Будет различие в содержимом команд, вторая будет требовать partnerId. А в REST это будет одинаково: POST /users/. Это тоже неочевидно.
     
  15. WMix

    WMix герр M:)ller Партнер клуба

    Сообщения:
    5.961
    Ваш город:
    Berlin
    Address:
    Berlin, Germany
    Country:
    Location on Map:
    POST /users/42 {"banned": true}?
    это голый crud
    $user->update($post,$id); те. тут предполагается что banned один из аттрибутов
    какой ответ придумал, тот и возвращай всегда

    POST /users/42/ban
    а это твой
    $user->ban()

    дальше хоть whiteliste на POST /users/{id} в аттрибутах чтоб только 2й метод разрешить.

    в смысле я не вижу проблемы ограгничения
     
  16. Вурдалак

    Вурдалак Newbie

    Сообщения:
    6.032
    Ваш город:
    Russia, Moscow
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    Вот именно, что у меня не будет update(), у меня будет список конкретных действий: rename(), ban(), etc. У меня будут только методы POST /users/42/<commandName>, не будет никакого POST /users/42/. О чём я и говорю, нафиг тогда делать вид, что это REST, когда JSON RPC тут ложится куда лучше?
     
  17. fixxxer

    fixxxer К.О. Партнер клуба

    Сообщения:
    12.462
    Ваш город:
    Moscow, Russia
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    Посещала. Поэтому везде, где бэкенд сложнее, чем этакий http-доступ к базе данных с аутентификацией -авторизацией и row-level security, по возможности использую json-rpc. Аргументировал ровно так же.
     
  18. WMix

    WMix герр M:)ller Партнер клуба

    Сообщения:
    5.961
    Ваш город:
    Berlin
    Address:
    Berlin, Germany
    Country:
    Location on Map:
    я понимаю ситуации разные, но самая простая форма где и имя и адрес и телефон и мыло и галочка заблокирован всегда присутствует, хоть даже если это не про пользователя, ну не пошагово же менять данные, а скопом простой update, а там уже смотрим на бизнес логику, не?
     
  19. Вурдалак

    Вурдалак Newbie

    Сообщения:
    6.032
    Ваш город:
    Russia, Moscow
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    Почему нет?

    Можно, если так припрёт, сделать команду, которая обновляет различные данные юзера. Можно, например, сделать команду Update/ChangeProfile, где обновлять имя, фамилию и так далее. Но когда тебе нужно подписываться на конкретные события: юзер был забанен, юзер был разбанен (и ему требуется компенсация за время бана), то всё равно ты приходишь к тому, что внутри эти команды будут fine-grained: будет отдельно метод ban(), будет отдельно метод unban(), changeProfile() и т.д.
     
    Последнее редактирование: 5 апр 2016
  20. WMix

    WMix герр M:)ller Партнер клуба

    Сообщения:
    5.961
    Ваш город:
    Berlin
    Address:
    Berlin, Germany
    Country:
    Location on Map:
    ну те твой контроллер похож на
    user->rename($post[name]);
    user->moved($post[address]);
    user->reborn($post[birthdate]);

    а как на счет атомарности? ну дело не в пользователе, это же и заказы, деньги?