Введение
Что такое REST
REST — это принцип построения архитектуры программного обеспечения. Используется при разработке веб-сервисов.
Что такое REST API
REST API — это набор функций, к которым могут обращаться разработчики. Используя HTTP-протокол, разработчик отправляет запрос и получает ответ. Как правило, данные передаются в одном из форматов: HTML, XML или JSON.
Запрос данных. Клиент обращается к веб-сервису, используя специальный URL. URL содержит все необходимые серверу данные, для однозначной идентификации запрашиваемого объекта. Методы HTTP-протокола используются для передачи информации о том, что мы хотим сделать с указанным объектом.
Например:
- GET /articles — получить список всех публикаций
- GET /article/1236 — получить из хранилища публикацию под номером 1236
- PUT /article — добавить новую статью (данные в теле запроса)
- POST /article/1236 – изменить статью (данные в теле запроса)
- DELETE /article/33 – удалить публикацию
Создаем REST API на основе Catalyst
Краткое описание
Для реализации REST-сервиса мы будем использовать специальный модуль Catalyst::Controller::REST, который значительно упрощает разработку соответствующих web-сервисов.
Catalyst::Controller::REST вмешивается в процесс диспетчеризации поступающих запросов.
Принцип диспетчиризации поступающих запросов изменяет добавление атрибута :ActionClass(‘REST’) к объявлению Catalyst action (м.б. кто-нибудь подскажет русскоязычный аналог этого термина?).
Например, если при объявлении метода article указан :ActionClass(‘REST’)
|
1 2 3 |
sub article :Local :ActionClass('REST') { ... } |
то в дальнейшем, при обращении клиента по адресу /article методом GET, Catalyst будет передавать
управление обработчику article_GET, если использован метод POST, то обработчику article_POST. Если соответствующий обработчик не найден — Catalyst вернет клиенту ответ со статусом — 405 (Method Not Found).
|
1 2 3 |
sub article_GET { ... } |
Другой вариант объявления метода, который будет вызываться для обработки запроса GET /article
|
1 2 3 |
sub article_PUT : Action { ... } |
Если ответ со статусом 405 не нравится, и хочется отправить клиенту что-то особенное, можно переопределить метод, который вызывается для ответа в случае ошибки, и задать ему желаемое поведение:
|
1 2 3 |
sub article_not_implemented { ... } |
Практическая реализация REST API на основе Catalyst. Примеры кода
Каркас приложения у нас уже создан. См. «Как создать Catalyst-приложение с нуля».
Теперь добавим модули, которые еще не установлены, но понадобятся для создания REST API.
|
1 2 3 4 5 |
force install Catalyst::View::JSON force install Catalyst::Controller::REST force install JSON::XS |
Создаем новое представление
|
1 |
perl script/myapp_create.pl view JSON JSON |
Первый аргумент — название создаваемого представления, второй — название модуля, который мы наследуем при создании представления. Можно создавать представление, давая ему любое имя, например:
|
1 |
perl script/myapp_create.pl view MyJSONview JSON |
, но идентичное названию модуля — мне кажется более удобным для дальнейшего использования.
Для работы мы будем использовать уже знакомую БД test (см. дамп БД) и таблицу статей.
API — это не только REST. Поэтому, для всех возможных API, я создаю отдельный каталог в директории Controller. Внутри API создаю каталог REST. Там будут все модули, которые отвечают за выполнение запросов.
Модуль /lib/MyApp/Controller/API/REST.pm
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
package MyApp::Controller::API::REST; use Moose; use namespace::autoclean; BEGIN { extends 'Catalyst::Controller::REST' } __PACKAGE__->config( default => 'application/json', ); sub rest_chain :Chained :PathPrefix :CaptureArgs(0) {} __PACKAGE__->meta->make_immutable; 1; |
Модуль /lib/MyApp/Controller/API/REST/Articles.pm
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
package MyApp::Controller::API::REST::Articles; use Moose; use namespace::autoclean; BEGIN { extends 'MyApp::Controller::API::REST' } =item articles Action для всех запросов с URL /api/rest/articles =cut sub articles :Chained('../rest_chain') :PathPart('articles') :Args(0) :ActionClass('REST') { my ( $self, $c ) = @_; } =item articles_GET Обработчик запросов /api/rest/articles, метод GET . Возвращает список публикаций =cut sub articles_GET { my ( $self, $c ) = @_; my $rs = $c->model('DB::Article')->search( {} ); my %data; $data{count} = $rs->count; $data{articles} = [ map { +{ id => $_->id, name => $_->name, full => $_->full } } $rs->all ]; $self->status_ok( $c, entity => \%data ); } =item article Action для всех запросов с URL /api/rest/article/{id} =cut sub article :Chained('../rest_chain') :PathPart('article') :Args(1) :ActionClass('REST') { my ( $self, $c ) = @_; } =item article_GET Обработчик запросов /api/rest/article/{id}, метод GET . Возвращает информацию о публикации под указанным id. =cut sub article_GET { my ( $self, $c, $id ) = @_; my $article = $c->model('DB::Article')->find( {'id' => $id} ); my %data; if (defined $article) { $data{article} = { id => $article->id, name => $article->name, full => $article->full }; } else { $data{status} = '404'; } $self->status_ok( $c, entity => \%data ); } =item article_DELETE Обработчик запросов /api/rest/article/{id}, метод DELETE . Удаляет из БД публикацию с указанным id. =cut sub article_DELETE { my ( $self, $c, $id ) = @_; my $article = $c->model('DB::Article')->find( {'id' => $id} ); my %data; if (defined $article) { $article->delete(); $data{status} = '200'; } else { $data{status} = '404'; } $self->status_ok( $c, entity => \%data ); } =item article Action для всех запросов с URL /api/rest/article =cut sub article :Chained('../rest_chain') :PathPart('article') :Args(0) :ActionClass('REST') { my ( $self, $c ) = @_; } =item article_PUT Обработчик запросов /api/rest/article, метод PUT, тело запроса содержит данные для создания новой записи в БД, в формате {"name": "arrr", "full":"dadaa"} =cut sub article_PUT { my ($self, $c) = @_; my $args = $c->request->data; my %data; my $res = $c->model("DB::Article")->create({ name => $args->{name} || '', full => $args->{full} || '', }); $data{status} = '200'; $self->status_ok( $c, entity => \%data ); } __PACKAGE__->meta->make_immutable; 1; |
Все данные клиенту будут возвращаться в JSON-формате.
Представление /lib/MyApp/View/JSON.pm
В представление нужно добавить обработчик «process»:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package MyApp::View::JSON; use strict; use base 'Catalyst::View::JSON'; sub process { my($self, $c) = @_; $c->res->header('Pragma' => 'no-cache'); $c->res->header('Cache-Control' => 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0'); $self->SUPER::process( $c, @_ ); $c->res->header('Content-type' => 'application/json; charset=utf-8'); } 1; |
Проверяем работоспособность REST-сервисов
Для тестирования REST-сервисов использовала RESTClient — специальный плагин для Firefox. Очень удобно, рекомендую.
Чтобы получить список статей, надо в адресной строке web-клиента указать:
|
1 |
http://localhost:3000/api/rest/articles |
и выполнить запрос методом GET.
Чтобы отправить PUT запрос с данными, нужно передавать данные через поле «Request Body», в JSON-формате. Например:
|
1 |
{"name": "arrr", "full":"dadaa"} |
Примечание: Если REST API используется для внутренних нужд, можно ограничить доступ к нему настройками сервера. Если web-сервис должен быть доступен внешним клиентам, необходимо ввести для клиентов этапы авторизации и аутентификации.
Похожие публикации на блоге программиста
Как создать Catalyst-приложение с нуля
Работа с атрибутами Path, CaptureArgs, Args, Local, Global и Private в Catalyst
Команды Curl для отправки запросов методами GET, PUT, POST, DELETE
Полезные ссылки по теме «Perl, Catalyst и REST-сервисы»
Руководство по использованию REST API Mail.ru
search.cpan.org: Catalyst::Controller::REST
Статья интересная, хотя перлом я не интересуюсь (теперь «почти не интересуюсь»). Не совсем было понятно для чего все это делается и какой профит ожидается — об этом, возможно, стоит дописать тут:
«REST API — это набор функций, к которым могут обращаться разработчики. Используя HTTP-протокол, разработчик отправляет…»
Есть примеры, но хотелось бы узнать о том, где лично Вы применяли это на практике (если применяли) — это было бы интересно.
Про то, зачем все это нужно, в целом написано на хабре (правильную ссылку я нашел в этой статье).
Пока читать статью, гуглил и нагуглил интересных ссылок:
1 описано что такое REST и зачем оно нужно безо всяких перлов/пхп и прочих / http://habrahabr.ru/post/46032/
2 REST на php (пример использования фрэймворка Phalcon, пример мне очень понравился) / http://docs.phalconphp.ru/ru/latest/reference/tutorial-rest.html
3 Phalcon на хабре / http://habrahabr.ru/post/160311/
4 Цикл статей по C++ REST SDK (Casablanca) на MSDN / http://msdn.microsoft.com/en-us/library/jj969455.aspx