О том, что такое
RESTful приложение и почему это круто можно почитать на
Wiki,
хабре или даже в
статье ibm. Фактически, RESTful приложение - это приложение, построенное на вызове удаленных REST
веб сервисов, выполняющих
CRUD функции (
Create,
Read,
Update,
Delete - создать, прочитать, обновить и удалить соответственно). Каждый REST сервис характеризуется URI, по которому он вызывается, и некоторым набором принимаемых и возвращаемых параметров.
Особенность REST подхода состоит в активном использовании HTTP методов для выполнения CRUD функций: вместо использования URI адресов типа
/user/23/
/user/23/?action=delete
/user/23/?action=update
предлагается использовать стандартный адрес
/user/23/, обращение к которому ведется с использованием HTTP команд
GET,
DELETE,
PUT. Для создания нового элемента используется HTTP команда
POST (в нашем примере к адресу
/user/ - ID создаваемого элемента до момента создания мы, как правило, не знаем). Для приложений, функциональность которых не выходит за рамки CRUD, а можно уверенно сказать, что это большинство современных веб приложений, RESTful подход является лучшим выбором для создания веб сервисов сервисов и API.
В данной статье я предлагаю рассмотреть создание простейшего RESTful приложения с использованием
ExtJS 3 на клиентской стороне. Серверную часть можно написать на любой любимой технологии - будь то Java, PHP, Python или что-то еще.
В этой статье подразумевается, что Ext уже подключен, также рекомендуется использование связки Firefox +
Firebug для отладки Javascript и просмотра http заголовков запросов и ответов. Итак, поехали!
Будем использовать хранилище (Store) с настроенным HttpProxy. Дело в том, что HttpProxy поддерживает api для установки методов загрузки, обновления и удаления данных в хранилищах Store:
var myProxy = new Ext.data.HttpProxy({
api: {
read: {url: 'app/users/', method: 'GET'},
create: {url: 'app/users/', read: 'POST'},
update: {url: 'app/users/', method: 'PUT'},
destroy: {url: 'app/users/', method: 'DELETE'}
}
});
Как видим, можно настроить разные URI адреса для действий чтения, обновления и т.д., однако это плохо согласуется с идеологией REST, поэтому мы будем использовать один адрес с разными передаваемыми параметрами и разными HTTP методами. Стоит отметить, что по умолчанию используется метод POST, поэтому в каждом случае следует вручную указывать параметр
method.
Сконфигурируем JsonReader и JsonWriter:
var myReader = new Ext.data.JsonReader({
successProperty: 'success', // json элемент со статусом
// результата (false or true)
idProperty: 'id',
root: 'data', // корневой элемент с данными
}, [
{name: 'id'},
{name: 'email', allowBlank: false},
{name: 'first', allowBlank: false},
{name: 'last', allowBlank: false}
]);
var myWriter = new Ext.data.JsonWriter({
encode: true, // важно! кодировать Store
writeAllFields: false // сохранять только измененные поля
});
Теперь можно сконфигурировать само хранилище. Фактически, мы указываем здесь reader, writer и proxy:
var myStore = new Ext.data.Store({
id: 'user',
proxy: myProxy,
reader: myReader,
writer: myWriter,
idProperty: 'id', // важно! Id элементов хранилища
autoSave: true // при изменении хранилища будет автоматически
// сформирован запрос на его сохранение
});
Теперь при изменении хранилища - то есть изменении записей в хранилище - будет автоматически посылаться запрос к серверу для сохранения всех модификаций. Если по каким-то причинам мы хотим отправлять запрос на сохранение текущего состояния хранилища сами, необходимо установить конфигурационный параметр
autoSave хранилища в false; в таком случае запрос на сохранение будет сформирован при вызове метода
save() хранилища:
myStore.save();
Обратите внимание на параметр
idProperty хранилища; в случае некорректной установки этого параметра при сохранении измененного элемента все равно будет создан запрос на создание
нового элемента вместо сохранения
существующего (POST вместо PUT). Это связано с тем, что каждая запись в хранилище однозначно идентифицируется параметром
id, который должен быть связан с реальным идентификатором нашей записи (
id в JsonReader - как правило, идентификатор записи в базе данных).
Также обратите внимание, что если используется mapping в параметрах fields для JsonReader - в
idProperty нужно указывать реальное название параметра в Json данных, а не название колонки данных в Ext'е. Для тех, кто не в курсе - маппинг это сопоставление имен параметров в Json данных и имен этих же параметров в Ext для манипуляции с ними, при желании можно задавать разные имена. Иными словами, мы могли бы так настроить JsonReader:
var myReader = new Ext.data.JsonReader({
successProperty: 'success', // json элемент со статусом
// результата (false or true)
idProperty: 'id',
root: 'data', // корневой элемент с данными
}, [
{name: 'ExtIdentificator', mapping: 'realJsonId'},
{name: 'email', allowBlank: false},
{name: 'first', allowBlank: false},
{name: 'last', allowBlank: false}
]);
Для
idParamater в таком случае надо указывать
realJsonId.
Итак, теперь мы умеем сохранять данные хранилища. Но как модифицировать эти данные? Как правило, хранилище используется либо для загрузки данных с сервера с последующим использованием в формах или других элементах страницы, либо для загрузки данных в таблицу Grid. В случае использования EditorGridPanel данные таблицы и данные хранилища полностью синхронизированы, то есть при изменении данных таблицы автоматически меняется и хранилище, с ним связанное. Это первый способ изменения данных хранилища.
Другой способ - ручной. Например, мы хотим обновить данные первого пользователя в хранилище myStore:
myStore.getAt(0).data.items[0].name = 'Alexey';
myStore.getAt(0) возвращает первую запись (Record) хранилища; свойство
data записи хранит в себе все данные записи.
Таким образом, изменив одним из описанных способов хранилище, мы имеем возможность сохранить новое состояние хранилища либо автоматически (путем настройки хранилища
autoSave: true), либо вручную путем вызова метода хранилища
save().
Пример использования JsonWriter можно посмотреть
здесь.