MyShows, Eaze и мысли о правильном построении веб-приложения

Когда я только начинал делать MyShows, все было достаточно просто – все url описаны в pages.xml, и на каждый url по экшену.

Кусок сайта из pages.xml:

<page uri="/profile/">
    <actions>MyShows.Site.ManageEpisode, MyShows.Site.GetMyShows, MyShows.Site.GetFirstUnwatchedEpisodes</actions>
    <template>tmpl://fe/profile/index.tmpl.php</template>
</page>
<page uri="/view/([0-9]+)/">
    <actions>MyShows.Site.GetShow, MyShows.Site.ManageShow</actions>
    <template>tmpl://fe/search/view.tmpl.php</template>
</page>
<page uri="/view/episode/([0-9]+)/">
    <actions>MyShows.Site.GetEpisode</actions>
    <template>tmpl://fe/search/episode.tmpl.php</template>
</page>

И в таком духе…

Мобильная версия

Вскоре понадобилось создать мобильную версию сайта, где логика примерно такая же, но со своими исключениями:

<page uri="/unaired/">
    <actions>MyShows.Site.GetMyShows, MyShows.Site.GetMyFutureEpisodesIphone</actions>
    <template>tmpl://iphone/unaired-shows.tmpl.php</template>
</page>
<page uri="/unaired/([0-9]+)">
    <actions>MyShows.Site.GetMyShows, MyShows.Site.GetMyFutureEpisodesIphone</actions>
    <template>tmpl://iphone/unaired-episodes.tmpl.php</template>
</page>

На получение данных, в принципе, экшены все одни и те же, но с дополнительными настройками, которые заданы через MyShows.Site.xml. Так что, более менее проблема решается.

API

А потом понадобилось сделать API. И тут началось, т.к. API должен продублировать почти все функции, которые есть у сайта… С точки зрения системы экшенов – отлично подходила REST-архитектура (ну или её подобие).

Для управления данными требовалось написать экшен-фильтр, который преобразует данные из Page::$RequestData в GET/POST параметры, как будто это действие было совершено через сайт.

<page uri="/profile/shows/([0-9]+)/(sync|watching|cancelled|later|remove|episodes)">
    <actions>MyShows.Site.ManageShowAPI, MyShows.Site.ManageShow</actions>
</page>
<page uri="/profile/shows/([0-9]+)/(rate)/([1-5])">
    <actions>MyShows.Site.ManageShowAPI, MyShows.Site.ManageShow</actions>
</page>

А для вывода данных пришлось написать свои экшены, в которых был организован вывод в JSON. Благо данные (сериалы, эпизоды, новости и остальное) обычно брались из уже заранее написанных утилит.
Как мы видим, полученный результат не очень удовлетворяет наши программистские потребности :) — DRY передавал привет.

Назад в будущее

Если бы мы заранее предположили, что у нас будет не только мобильная версия, но ещё и API, а API ещё и с версионностью, то скорее всего подход был бы другой:

  1. Выбор API пал бы точно на JSON-RPC 2.0, т.к. есть batch-запросы и для JSON-RPC есть нормальные библиотеки для работы с ним.
  2. Если раньше были утилиты (например ShowUtility, которые работали с базой) и экшены, в которых выполнялась логика, то к ним нужно добавить ещё *Manager’ов, которые использовались бы в API и в экшенах, например: SiteUserManager::Register( $login, $email, $password, $gender ).
  3. Мобильную версию сайта можно полностью перевести на javascript и API для того, чтобы не дублировать экшены и не писать никаких адаптеров-переходников.

Руководствуясь этими принципами, можно получить вполне хороший результат.

Но можно пойти ещё дальше и сделать API на каком-нибудь языке типа Go, а сайт – таким же клиентом к этому API. Или заложить такой же принцип, вызывая методы API из экшенов напрямую – как подготовку к будущей версии с Go.

Posted Январь 29th, 2013 in Без рубрики.

Comments are closed.