Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Как я принудил трудиться API в Yiinitializr Advanced

Anna | 31.05.2014 | нет комментариев

В продолжение моего предыдущего поста о таком увлекательном инструменте как Yiinitializr, я решил ответить на вопрос о вероятностях работы API, предоставляемых образцом Advanced. В рамках комментария либо добавочного пункта к прошлой статье материал уместить не удалось, следственно всех, кого волнует данная тема, приглашаю под кат. В ней мы не будем касаться тезисов проектирования положительной архитектуры API, а разберёмся как воспользоваться трудами ребят из 2amigos, которые дали нам вероятность стремительно (позже прочтения статьи — верно стремительно) развернуть API для наших планов на Yii.

Метод реализации работы с API в Yiinitializr

API — программный интерфейс приложения, служащий для применения во внешних программных продуктах. Если мы хотим, Дабы вероятностями нашего приложения могли воспользоваться другие разработчики в своих планах, то без отлично спроектированного API нам не обойтись. К сожалению, Yii первой версии не сумеет подмогнуть в этом деле. Возможно, вам подойдет Yiinitializr, тот, что решит часть вопросов, но, как мы знаем, неимение документации является серьезным препятствием.

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

Наша система генерирует, выдаёт и сберегает в базе данных публичный ключ (идентификатор внешнего приложения), приватный ключ, а также пользователя, за которым эти ключи резервируются. Регистрация на этом завершена. Взаимодействие пользователя API с нашей системой производится на основе тезисов REST. Приложение пользователя отправляет нашей системе запрос определённым HTTP-способом, включающий в себя HTTP-заголовок с публичным ключом, а также сообщение в JSON-формате, в котором непременно содержатся подпись и срок её годности, а также разные добавочные параметры. Обработав запрос и удостоверясь в его корректности, система выдаёт результат.

Различия образца Advanced

Если прежде речь шла о образце Intermediate, то сейчас давайте взглянем, что же добавилось в образец Advanced. Как вы теснее осознали — все добавочные вероятности, которые он нам даёт, связаны с API. Скачиваем, распаковываем и заходим в директорию ./api глядеть, что же у нас сейчас имеется. А имеются у нас:

./api/extensions/filters/EApiAccessControlFilter.php — класс-фильтр для выполнения проверки правил доступа к API.
./api/extensions/components/EApiAccessRule.php — класс, представляющий правило доступа к API.
./api/extensions/components/EApiActiveRecord.php — класс для вспомогательных способов работы AR-моделей с API.
./api/extensions/components/EApiController.php — класс-контроллер для обработки запросов к API.
./api/extensions/components/EApiError.php — класс ошибок API, присутствующий для комфорта чтения логов.
./api/extensions/components/EApiErrorHandler.php — класс для обработки ошибок API. Если мы решим логировать ошибки в базу данных, то воспользуемся именно этим классом.
./api/models/ApiUser.php — пример модели, которой мы будем руководить внешними пользователями нашего API.
./common/lib/YiiRestTools/ — вспомогательные классы для функционирования REST API.

Этих всеобщих сведений будет довольно для того, Дабы перейти непринужденно к реализации взаимодействия стороннего приложения с нашей системой посредством API.

Конфигурирование и исправление недоработок

Разработчики Yiinitializr по каждой видимости придерживались правила Парето, и исполнив 80% работы, решили не тратить 80% времени на документацию и исправление багов, возложив это на плечи искушённых разработчиков (то есть нас).

Раз мы решили заняться настройкой Yiinitializr, то безусловно же нас волнует файл конфигурации. Откроем его и посмотрим на правила роутинга API (./api/config/api.php):

'rules' => array(
    // REST patterns
    array('<controller>/index',  'pattern' => 'api/<controller:\w >',        'verb' => 'POST'),
    array('<controller>/view',   'pattern' => 'api/<controller:\w >/view',   'verb' => 'POST'),
    array('<controller>/update', 'pattern' => 'api/<controller:\w >/update', 'verb' => 'PUT'),
    array('<controller>/delete', 'pattern' => 'api/<controller:\w >/delete', 'verb' => 'DELETE'),
    array('<controller>/create', 'pattern' => 'api/<controller:\w >/create', 'verb' => 'POST'),
),

Видим что-то непонятное. Комментарий говорит нам, что это REST-образец, но на деле получаем не вовсе то. REST полагает, что все запросы идут на цельный URL, а действия выбираются на основе HTTP-способов и параметров запроса, т. е. должно быть так:

Адрес HTTP-способ Вызванное действие
api.yiinitializr.dev/test/ GET TestController\actionIndex()
api.yiinitializr.dev/test/1/ GET TestController\actionView(1)
api.yiinitializr.dev/test/ POST TestController\actionCreate()
api.yiinitializr.dev/test/1/ PUT TestController\actionUpdate(1)
api.yiinitializr.dev/test/1/ DELETE TestController\actionDelete(1)

Приводим правила к необходимому виду:

'rules' => array(
    // REST patterns
    array('<controller>/index',  'pattern' => '<controller:\w >',          'verb' => 'GET'),
    array('<controller>/view',   'pattern' => '<controller:\w >/<id:\d >', 'verb' => 'GET'),
    array('<controller>/update', 'pattern' => '<controller:\w >/<id:\d >', 'verb' => 'PUT'),
    array('<controller>/delete', 'pattern' => '<controller:\w >/<id:\d >', 'verb' => 'DELETE'),
    array('<controller>/create', 'pattern' => '<controller:\w >',          'verb' => 'POST'),
),

Огромнее в файле конфигурации ничего подлинно значимого для текущего этапа мы не найдём, следственно переходим к иным задачам. Решение первой безусловно примитивное — переносим

use YiiRestTools\Helpers\RequestData;
use Yiinitializr\Helpers\ArrayX;

из EApiAccessControlFilter.php в EApiAccessRule.php, т. к. эти классы применяются именно во втором файле.

Дальнейшая задача теснее увлекательнее. Допустимо, я чего-то не осознал, следственно предлагаю порассуждать совместно. Наблюдательно посмотрите на приведённый ниже код (./api/extensions/components/EApiAccessRule.php):

public function isRequestAllowed($user, $controller, $action, $ip, $verb) {
    if ($this->isActionMatched($action)
        && $this->isUserMatched(Yii::app()->user)
        && $this->isRoleMatched(Yii::app()->user)
        && $this->isSignatureMatched($user)
        && $this->isIpMatched($ip)
        && $this->isVerbMatched($verb)
        && $this->isControllerMatched($controller)
    ) {
        return $this->allow ? 1 : -1;
    } else {
        return 0;
    }
}

Способ isRequestAllowed проверяет соответствие запроса правилам. Если цепочка проверок в блоке if правдива, то данное правило используется, возвращая 1 либо -1, в зависимости от того, что делает это правило — разрешает либо воспрещает. Напротив данное правило не применимо к определенному запросу и способ возвращает 0. Дабы стало внятнее, напоминаю, как выглядят правила для фильтров:

public function filters() {
    return array(
        array(
            'EApiAccessControlFilter -error',
            'rules' => array(
                array('allow', 'users' => array('@')),
            )
        )
    );
}

permark! private $apiPublic; private $apiSecret; private $expiration; public function __construct($url, $publicKey, $secretKey, $expiration = ‘ 1 hour’) { $this->baseUrl = $url; $this->apiPublic = $publicKey; $this->apiSecret = $secretKey; $this->expiration = $expiration; } public function makeRequest($verb, $controller, $params = array()) { $ch = curl_init(); $signature = $this->generateSignature(); $url = $this->makeUrl($controller); if (!empty($params) && isset($params['id'])) { $url .= $params['id']; } curl_setopt_array($ch, array( CURLOPT_URL => $url, CURLOPT_CUSTOMREQUEST => $verb, CURLOPT_HTTPHEADER => array(‘APIKEY: ‘ . $this->apiPublic), CURLOPT_POSTFIELDS => json_encode(array( ‘signature’ => $signature, ‘expiration’ => $this->relativeTimeToAbsolute($this->expiration), )), )); $result = curl_exec($ch); curl_close($ch); return $result; } private function generateSignature() { $ttdInt = strtotime($this->expiration); $raw = json_encode(array(‘expiration’ => gmdate(‘Y-m-d\TH:i:s\Z’, $ttdInt))); $jsonPolicy64 = base64_encode($raw); $signature = base64_encode(hash_hmac( ‘sha1′, $jsonPolicy64, $this->apiSecret, true )); return $signature; } private function makeUrl($controller) { return ‘http://’ . rtrim($this->baseUrl, ‘/’) . ‘/’ . $controller . ‘/’; } private function relativeTimeToAbsolute ($relativeTime) { return date(‘M d Y, H:i:s’, strtotime($relativeTime)); } }

 

Работа с классом SimpleClient

$api = new SimpleClient('api.yiinitializr.dev', 'e4afe26b5b57083f74b2d01c7066379c', '156a17333e77a3c504018cae5ada8c3b');

$api->makeRequest('GET', 'test');
$api->makeRequest('GET', 'test', array('id' => 1));
$api->makeRequest('POST', 'test');
$api->makeRequest('PUT', 'test', array('id' => 1));
$api->makeRequest('DELETE', 'test', array('id' => 1));

 

Изменённая версия тестового контроллера

class TestController extends EApiController {
    public function actionIndex() {
        // just drop API request :) 
        $this->renderJson(json_encode(array('response' => 'index')));
    }

    public function actionView($id) {
        $this->renderJson(json_encode(array('response' => 'viewed#' . $id)));
    }

    public function actionCreate() {
        $this->renderJson(json_encode(array('response' => 'created')));
    }

    public function actionUpdate($id) {
        $this->renderJson(json_encode(array('response' => 'updated#' . $id)));
    }

    public function actionDelete($id) {
        $this->renderJson(json_encode(array('response' => 'deleted#' . $id)));
    }
}

 

Настройка Apache

Дабы Apache перестал блокировать PUT и DELETE запросы, нужно добавить в файл ./api/www/.htaccess следующие строки:

<Limit GET POST PUT DELETE>
order deny,allow
allow from all
</Limit>

Решение взято тут.

 

Подводим результаты

Вот таким нехитрым методом мы принудили нашу машину завестись. На то, Дабы осознать что к чему, мне потребовалось потратить не один день (и даже не два). В любом случае, сходственное решение будет абсолютно целесообразно в качестве стартовой позиции, базируясь на которой значительно легче сделать добротное API, не владея большими умениями в этом вопросе. Из дополнительных ссылок могу порекомендовать посмотреть Огромное начальство по Yiinitializr (неужто вы до сих пор этого не сделали?) и статью Как сделать REST API для Yii (на английском).

В комментариях предлагаю поделиться вашими соображениями по поводу реализации API на Yii, покр

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB