Форум dkLab и Denwer
Здесь общаются Web-разработчики.
Генеральный спонсор:
Хостинг «Джино»

Класс запроса для REST-сервера с поддержкой нескольких форматов данных. (din70)
Author Message
din70
Заглянувший



Joined: 20 Feb 2013
Posts: 1
Карма: 0
   поощрить/наказать

Location: Одесса, Украина

PostPosted: Sun Mar 03, 2013 8:49 pm (написано за 9 минут 8 секунд)
   Post subject: Класс запроса для REST-сервера с поддержкой нескольких форматов данных.
Reply with quote

Класс Request: класс запроса для REST-сервера с автоматическим распознаванием формата передаваемых данных и выводом результата в запрашиваемом формате.
Класс разработан на основе класса JsHttpRequest (C) Dmitry Koterov, en.dklab.ru.
Русский язык корректно работает только с кодировкой utf8 — из класса убрано все, что касается перекодировки данных. Поскольку современные браузеры на сегодняшний день все поддерживают эту кодировку, это не критично.
Класс наследует от класса SPL ArrayObject, что позволяет получить доступ к ДАННЫМ запроса как через обращение к полю объекта, так и через обращение как к элементу ассоциативного массива - это бывает полезно. Доступ к ПАРАМЕТРАМ запроса (поля $method, $requestFormat, $controller, $action, $id, $responceFormat, $params, $RESULT) осуществляется только как к полям объекта и при переборе свойств объекта, например, через foreach эти поля не включаются.

Обращение к API осуществляется http-запросом по URL http://<host>/[<skiped elements>/]<key>/[<response format>/]<controller>/[<action>/][<ID>/][?<GET parameters>], где
<skiped elements> - любые элементы URL, пропускаются классом Request при анализе данных;
<key> - ключевой элемент URL, с которого начинается разбор параметров запроса; указывается как элемент 'skipurito' конструктора класса Request;
<response format> - запрашиваемый формат передачи данных ответа (необязательно). Если не указан или указан неверно, но конструктор распознал формат передаваемых в запросе данных, то будет использован этот формат. Если же формат передаваемых в запросе данных не распознан (например, все необходимые данные переданы методами GET или через POST-параметры), то будет использован формат по умолчанию.
Передача параметров осуществляется GET-параметрами URL, методом POST, а также через COOKIES.
Данные, переданные методами GET, POST, а также через COOKIES, получаются через глобальную переменную $_REQUEST, и, соответственно, имеют приоритеты при наложении имен друг перед другом как описано в www.php.net/manual/ru/ini.core.php#ini.request-order, за некоторыми исключениями:
1. форматированные данные передаются через POST-переменную с именем request или просто в теле POST-запроса;
2. параметр с именем requestid зарезервирован и может быть использован только для передачи идентификатора запроса. Передаваемый ответ на запрос будет иметь параметр requestid с тем же значением, что и запрос.
3. Форматированные данные, переданные в теле запроса, имеют приоритет перед данными, переданными методами GET, POST, а также через COOKIES. т.е. значения, переданные в теле форматированных данных, затирают значения, переданные через переменные GET, POST и COOKIES.
<controller> - имя контроллера (в парадигме MVC);
<action> - запрашиваемое действие (в той же парадигме);
<ID> - идентификатор объекта, над которым действие должно быть выполнено, (в терминологии REST). Целое число.
<GET parameters> - любые параметры (кроме зарезервированных имен request и requestid).

Конструктору класса передается контекст выполнения запроса в виде ассоциативного массива.
Параметры контекста:
    'restful' - определяет, рассматривать ли запрос как RESTfull-запрос. Проверить значение этого параметра можно методом isRestful() объекта. В поле $request->method доступно значение метода, которым был послан запрос.
    'skipurito' - определяет ту часть URI, которую необходимо пропустить до того, как начать разбор URI запроса для выделения из него формата ответа, контроллера, метода и ID элемента.
    'formatters' - ассоциативный массив парсеров/форматеров, реализующих интерфейс RequestFormatParser, для доступных форматов данных в виде
        'formatName' => (RequestFormatParser) $formater
    позволяет:
    - автоматически распознать формат, в котором передаются данные запроса, и включить эти данные в запрос;
    - вывести результат обработанного запроса в одном из доступных форматов.
    Выбор формата для вывода результата осуществляется по следующим правилам:
    1. если формат указан явно в URL (например, localhost/xml/user/getinfo/2376), и этот формат имеется в списке переданных конструктору форматеров, то используется он;
    2. иначе если каким-либо форматером распознаны переданные в запросе данные, то для ответа используется формат, в котором были переданы данные запроса;
    3. иначе (например, если все необходимые данные были переданы через $_GET, $_POST и $_COOKIE) для передачи ответа используется формат, указанный в параметре 'defaultformat' контекста.
    Список форматеров открыт для расширения. На текущий момент доступны форматеры html (только вывод), JSON и XML. Новый парсер/форматер можно легко добавить, реализовав интерфейс RequestFormatParser.
    'defaultformat' - формат вывода результата по умолчанию. Если не задан явно, то устанавливается первый из перечисленных в списке 'formatters'. Если список 'formatters' пуст, устанавливается 'html', при это проверяется наличие этого форматера и при необходимости он добавляется.

Свойства объекта:
$method // Использованный HTTP-метод доступа к серверу
$requestFormat // Распознанный формат данных запроса
$controller // распознанный контроллер
$action // распознанное действие
$id // распознанный ID субъекта действия
$responceFormat = null // Распознанный формат вывода результата

Методы объекта:
1. Конструктор.
public function __construct($params)

2. Использовать ли обработку запроса как RESTful?
return bool
public function isRestful()

3. Get IP client address
return string
public function getIp()

4. «Магический» метод преобразования к строковому типу
public function __toString()


Примеры использования.
Файл test.php
Code (php): скопировать код в буфер обмена
<?php
// no cache
header (www.php.net/header)("Expires: Thu, 01 Jan 1970 00:00:00 GMT");
header (www.php.net/header)("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT");
header (www.php.net/header)("Pragma: no-cache");
header (www.php.net/header)("Cache-Control: max-age=0, no-cache, must-revalidate");

require_once 'include/request.php';
$request = new Request(
        array (www.php.net/array)(
                'restful' => false,        //
                                                //
                'skipurito' => 'test',        //
                                                //
                                                //
                'formatters' => array (www.php.net/array)(
                        'html'        =>        new HtmlRequestParser(),
                        'xml'        =>                new XmlRequestParser(),
                        'json'        =>        new JsonRequestParser()
                ),
                'defautformat' => 'html'        //
        )
);

$_RESULT=array (www.php.net/array)('success'        =>        true);        //
                                                //
                                                //
echo (www.php.net/echo) "This is debug info:\n";
//
foreach ($request as $key => $value) {
        $_RESULT[$key] = $value;
        echo (www.php.net/echo) $key, "\t=>\t", var_export (www.php.net/var_export)($value, TRUE), "\n";
}
?>
Пример 1.
Запрос
POST sandbox.tv/test/xml/channels/?id=45&numpos=100

Заголовок запроса:
Code (any language): скопировать код в буфер обмена
Accept-Language ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Charset utf-8,windows-1251;q=0.7,*;q=0.7
Accept-Encoding gzip,deflate
Keep-Alive 115
Connection keep-alive
X-Requested-With XMLHttpRequest
Cookie requestid=XXXXX; uid=12345; numpos=10
Content-Type application/x-www-form-urlencoded; charset=UTF-8
Тело запроса (данные POST):
Code (any language): скопировать код в буфер обмена
numpos=50&uid=222&request={"request":{"pager":{"onpage":14,"number":3},"numpos":4,"channels":["3","33","333"],"action":"getlist"}}
Заголовок ответа:
Code (any language): скопировать код в буфер обмена
Status HTTP/1.1 200 OK
Server nginx
Date Wed, 20 Feb 2013 04:01:39 GMT
Content-Type application/xml; charset=UTF-8
Connection close
X-Powered-By PHP/5.3.8
Expires Thu, 01 Jan 1970 00:00:00 GMT
Last-Modified Thu, 01 Jan 1970 00:00:00 GMT
Pragma no-cache
Cache-Control max-age=0, no-cache, must-revalidate
Тело ответа, как и запрашивалось, приходит в формате XML (обрамленное тэгом <api /> - это особенность моего форматера, Вы можете использовать свой вариант):
Code (xml): скопировать код в буфер обмена
<?xml version="1.0" encoding="UTF-8"?>
<api>
        <response>
                <success>1</success>
                <id>45</id>
                <numpos>4</numpos>
                <uid>12345</uid>
                <pager>
                        <onpage>14</onpage>
                        <number>3</number>
                </pager>
                <channels>3</channels>
                <channels>33</channels>
                <channels>333</channels>
                <action>getlist</action>
        </response>
        <text>This is debug info: id =&gt; '45' numpos =&gt; 4 uid
        =&gt; '12345' pager =&gt; array ( 'onpage' =&gt; 14,
        'number' =&gt; 3, ) channels =&gt; array ( 0 =&gt; '3',
        1 =&gt; '33', 2 =&gt; '333', ) action =&gt; 'getlist'
        </text>
        <requestid>XXXXX</requestid>
</api>
Обратите внимание на то, что значение параметра uid передается и методом POST (222), и через COOKIES (12345). Но в ответе мы видим, что используется именно то значение (12345), которое стоит в COOKIES – так установлено у меня на сервере. В Вашем случае результаты могут быть другими, значение зависит от параметра request-order в файле php.ini.
Также значение параметра numpos передается как методом GET (100), так и методом POST (50), и через COOKIES (10), а еще присутствует в форматированных данных, переданных в запросе (4). В ответе сервера мы видим, что используется значение 4, указанное в форматированных данных — это уже особенность класса Request. Форматированные данные имеют приоритет перед всеми остальными источниками данных запроса.

Пример 2.
Изменим URL запроса — уберем явный формат ответа:
POST sandbox.tv/test/channels/?id=45&numpos=100

Заголовок ответа:
Code (any language): скопировать код в буфер обмена
Server nginx
Date Wed, 20 Feb 2013 04:05:58 GMT
Content-Type text/html; charset=UTF-8
Connection close
X-Powered-By PHP/5.3.8
Expires Thu, 01 Jan 1970 00:00:00 GMT
Last-Modified Thu, 01 Jan 1970 00:00:00 GMT
Pragma no-cache
Cache-Control max-age=0, no-cache, must-revalidate
Тело ответа (поскольку формат ответа не указан явно и формат запроса распознался как JSON, для ответа используется именно он):
Code (JavaScript): скопировать код в буфер обмена
{"response":{"success":true,"id":"45","numpos":4,"uid":"12345","pager":{"onpage":14,"number":3},"channels":["3","33","333"],"action":"getlist"},"text":"This is debug info:\nid\t=>\t'45'\nnumpos\t=>\t4\nuid\t=>\t'12345'\npager\t=>\tarray (\n  'onpage' => 14,\n  'number' => 3,\n)\nchannels\t=>\tarray (\n  0 => '3',\n  1 => '33',\n  2 => '333',\n)\naction\t=>\t'getlist'\n","requestid":"XXXXX"}
Пример 3.
Изменим тело запроса, не меняя URL из предыдущего примера, — передадим данные методом POST без форматированных данных:
Code (any language): скопировать код в буфер обмена
numpos=50&uid=222
Заголовок ответа:
Code (any language): скопировать код в буфер обмена
Server nginx
Date Wed, 20 Feb 2013 04:10:17 GMT
Content-Type text/html; charset=UTF-8
Connection close
X-Powered-By PHP/5.3.8
Expires Thu, 01 Jan 1970 00:00:00 GMT
Last-Modified Thu, 01 Jan 1970 00:00:00 GMT
Pragma no-cache
Cache-Control max-age=0, no-cache, must-revalidate
Тело ответа (поскольку формат ответа не указан явно и формат данных запроса не распознан, для ответа используется форматер по умолчанию, в нашем случае - HTML):
Code (html): скопировать код в буфер обмена
<pre> (december.com/html/4/element/pre.html)<h1> (december.com/html/4/element/h1.html)Default html formater</h1>
<h2> (december.com/html/4/element/h2.html)response</h2>
array (
  'success' => true,
  'id' => '45',
  'numpos' => '10',
  'uid' => '12345',
)
<h2> (december.com/html/4/element/h2.html)text</h2>
'This is debug info:
id        =>        \'45\'
numpos        =>        \'10\'
uid        =>        \'12345\'
'
<h2> (december.com/html/4/element/h2.html)requestid</h2>
'XXXXX'
</pre>
Обратите внимание на то, что значение параметра numpos изменилось и равно 10, что соответствует значению, переданному через COOKIES (напоминаю, что это зависит от значения параметра request-order в файле php.ini.

Пример 4.
Изменим URL запроса на
POST sandbox.tv/test/html/channels/?id=45&numpos=100
(укажем явно формат ответа HTML)

и снова изменим тело запроса, не трогая заголовков — поместим туда данные в формате XML:
Code (xml): скопировать код в буфер обмена
<request>
        <pager>
                <onpage>14</onpage>
                <number>3</number>
        </pager>
        <numpos>4</numpos>
        <channels>3</channels>
        <channels>33</channels>
        <channels>333</channels>
        <action>getlist</action>
</request>
В результате получим ответ:
Code (html): скопировать код в буфер обмена
<pre> (december.com/html/4/element/pre.html)<h1> (december.com/html/4/element/h1.html)Default html formater</h1>
<h2> (december.com/html/4/element/h2.html)response</h2>
array (
  'success' => true,
  'id' => '45',
  'numpos' => '4',
  'uid' => '12345',
  'pager' =>
  array (
    'onpage' => '14',
    'number' => '3',
  ),
  'channels' =>
  array (
    0 => '3',
    1 => '33',
    2 => '333',
  ),
  'action' => 'getlist',
)
<h2> (december.com/html/4/element/h2.html)text</h2>
'This is debug info:
id        =>        \'45\'
numpos        =>        \'4\'
uid        =>        \'12345\'
pager        =>        array (
  \'onpage\' => \'14\',
  \'number\' => \'3\',
)
channels        =>        array (
  0 => \'3\',
  1 => \'33\',
  2 => \'333\',
)
action        =>        \'getlist\'
'
<h2> (december.com/html/4/element/h2.html)requestid</h2>
'XXXXX'
</pre>
Обратите внимание, что значение параметра numpos снова приняло значение 4, поскольку форматированные данные имеют приоритет над данными, полученными из $_REQUEST.

Примеры работают в среде Nginx + PHP 5.3 (FastCGI) с включением в раздел server конфигурационного файла nginx.conf строк:
Code (any language): скопировать код в буфер обмена
        location /test/ {
                rewrite ^/test/(.*)$        /test.php        last;
        }
Для Apache нужно использовать что-то типа mod_rewrite, но, к сожалению, я не знаю точно, как им пользоваться и не имел возможности поэкспериментировать.

Для выполнения запросов использовался RESTClient 2.3.3 (rest-client.googlecode.com/).

Класс создан и успешно используется около года в проекте разработки REST API видеосервиса.


request.zip
 Description:
Класс Request: класс запроса для REST-сервера с автоматическим распознаванием формата передаваемых данных и выводом результата в запрашиваемом формате.

Download
 Filename:  request.zip
 Filesize:  8.43 KB
 Downloaded:  322 Time(s)

Back to top
View user's profile Send private message
Александр Михалицын
Модератор



Joined: 23 May 2008
Posts: 1299
Карма: 83
   поощрить/наказать


PostPosted: Sun Mar 03, 2013 9:52 pm (спустя 1 час 3 минуты)
   Post subject:
Reply with quote


М

Перенесено из форума: Тестовый форум.
Перенесено в форум: Склад готовых решений :: PHP.
Back to top
View user's profile Send private message Send e-mail
Display posts from previous:   
Post new topic   Reply to topic All times are GMT + 3 Hours
Page 1 of 1    Email to a Friend.
You cannot post new topics in this forum. You cannot reply to topics in this forum. You cannot edit your posts in this forum. You cannot delete your posts in this forum. You cannot vote in polls in this forum. You cannot attach files in this forum. You can download files in this forum.
XML