REST в SharePoint 2013 и немного CRUD с помощью REST + JS

Были у меня статьи по клиентским CRUD операциям с помощью JSOM и SPServices, настало время REST'а.

Данная статья будет посвящена введению в SharePoint 2013 REST API и, по традиции, основным операциям с элементами списков.

Конечной точкой для вызова веб-сервисов в SharePoint 2013 является client.svc.

Обращаться к веб-сервису можно как по полному пути /_vti_bin/client.svc/, так и по алиасу /_api/, что является рекомендуемым способом. При обращении к веб-сервису данные с сервера возможно получить в двух форматах:

  • Atom-pub (XML);
  • JSON.

Формат по-умолчанию - Atom.

Например, если обратиться в браузере к /_api/web/lists/getByTitle('Подразделения'), то мы увидем нечто подобное:

Кстати, IE по-умолчанию пытается прочитать канал и отобразить лентой, чтобы увидить честный XML надо выставить настройку: Свойства браузера -> Содержание -> Веб-каналы и веб-фрагменты -> Параметры -> Включить показ ленты чтения веб-канала (опция должна быть выключена).

Общую архитектуру демонстрирует следующая схема:

Как видно из схемы, HTTP запрос, отправляемый на сервис, должен соответствовать формату OData. Подробности лучше всего описаны на сайте odata.org, ссылка внизу статьи.

Перед описанием CRUD операций приведу пару примеров получения информации в строке браузера. Иногда при разработке это довольно удобно для проверки данных.

  • http://[SharePoint Site]/_api/lists/ - извлечение всех списков на сайте
  • http://[SharePoint Site]/_api/lists/getByTitle('Подразделения') - извлечение информации по заданному списку;
  • http://[SharePoint Site]/_api/lists/getByTitle('Подразделения')/items - получение всех элементов списка;
  • http://[SharePoint Site]/_api/lists/getByTitle('Подразделения')/items(3) - получение элемента списка с ИД равным 3;
  • http://[SharePoint Site]/_api/lists/getByTitle('Подразделения')/items(3)?$select=ID,Title - явное указание перечня получаемых атрибутов элемента списка.

Получаемые элементы удобным образом можно фильтровать и упорядочивать. Да и вообще REST/OData - это круто!

Обращение в виде GET запроса в адресной строке хорошо для отладки, теперь о программных способах работы с помощью JavaScript. К слову, ничто не помещает работать с REST из C#.

При программном обращении мы получаем возможность задать формат данных. Я предпочитаю JSON, т.к. он нативен для JS.

Формат задается путем указания заголовков:

  • ACCEPT = application/json;odata=verbose
  • или такой (для Atom) - ACCEPT = application/atom+xml

Теперь к практике.

Обращаться к REST будем с помощью jQuery.

Получение элементов списка

var viewListData = function viewListDataF() {

    // DisplayName списка

    var listName = 'Подразделения'; 

    // Строка получения всех элементов с ограничением возвращаемого состава полей и сортировкой

    var requestUri = _spPageContextInfo.webAbsoluteUrl +

            "/_api/web/lists/getByTitle('"+listName+"')/items/" +

            "?$select=Id,Title" +

            "&$orderby=Title";

    // Определение заголовка ACCEPT

    var requestHeaders = {

        "accept": "application/json;odata=verbose"

    };

    // Ajax вызов получения элементов списка

    $.ajax({

       url: requestUri,

       type: "GET",

       headers: requestHeaders,

       success: onDataReturned,

       error: onError

    });

};

// Функция выполнится в случае успеха

var onDataReturned = function onDataReturnedF(data) {

    // Переменная будет содержать JSON объект

    var oDataResults = data.d.results;

    console.log(oDataResults);

};

// Функция выполнится в случае ошибки

var onError = function onErrorF(error) {

    // Возвращаемый объект не полностью объект

    // в responseText содержится не объект, а текст, поэтому необходимо выполнить парсинг

    var message = JSON.parse(error.responseText);

    alert("Error: " + message.error.message.value);

};

viewListData();

Создание нового элемента

Создание элементов немного сложнее получения, т.к. необходимо знать:

  • Тип элемента списка;
  • REQUESTDIGEST - дайджест "защиты от дурака".

Дайджест запроса можно получить так: $('#__REQUESTDIGEST').val().

Код типа элемента, в случае, если он не является InternalListName+"ListItem", можно подглядеть в /_api/web/lists/getByTitle('<Имя списка>')/items/.

Тип запроса - POST.

var newListItem = function newListItemF() {

    var itemTitleVal = 'Новый элемент';

    var listName = 'Подразделения'; 

    var internalListName = 'Departments';

    // Строка получения всех элементов с ограничением возвращаемого состава полей и сортировкой

    var requestUri = _spPageContextInfo.webAbsoluteUrl +

            "/_api/web/lists/getByTitle('"+listName+"')/items/";

    // Определение заголовка ACCEPT

    var requestHeaders = {

        "accept": "application/json;odata=verbose",

        "content-type": "application/json;odata=verbose",

        "X-RequestDigest": $('#__REQUESTDIGEST').val()

    };

    var itemData = {

        __metadata: { "type": "SP.Data."+internalListName+"ListItem" },

        Title: itemTitleVal

    };

    var requestBody = JSON.stringify(itemData);
    // Ajax вызов получения элементов списка

    $.ajax({

       url: requestUri,

       type: "POST",

       contentType: "application/json",

       headers: requestHeaders,

       data: requestBody,

       success: onSuccess,

       error: onError

    });

};

// Функция выполнится в случае успеха

var onSuccess = function onSuccessF(data) {

    // Переменная будет содержать JSON объект

    var oDataResults = data.d.results;

    console.log(oDataResults);

};

// Функция выполнится в случае ошибки

var onError = function onErrorF(error) {

    // Возвращаемый объект не полностью объект

    // в responseText содержится не объект, а текст, поэтому необходимо выполнить парсинг

    var message = JSON.parse(error.responseText);

    alert("Error: " + message.error.message.value);

};

newListItem();

Изменение элемента

По прежнему нужны:

  • Тип элемента списка;
  • REQUESTDIGEST.

Необходимо задать заголовок X-HTTP-Method = MERGE.

var updateListItem = function updateListItemF() {

    var itemId = 23;

    var itemTitleVal = 'Измененный элемент';

    var listName = 'Подразделения'; 

    var internalListName = 'Departments';

    // Строка получения всех элементов с ограничением возвращаемого состава полей и сортировкой

    var requestUri = _spPageContextInfo.webAbsoluteUrl +

            "/_api/web/lists/getByTitle('"+listName+"')/items("+itemId+")/";

    // Определение заголовка ACCEPT

    var requestHeaders = {

        "accept": "application/json;odata=verbose",

        "content-type": "application/json;odata=verbose",

        "X-RequestDigest": $('#__REQUESTDIGEST').val(),

        "X-HTTP-Method": "MERGE",

        "If-Match": "*"

    };

    var itemData = {

        __metadata: { "type": "SP.Data."+internalListName+"ListItem" },

        Title: itemTitleVal

    };

    var requestBody = JSON.stringify(itemData);    // Ajax вызов получения элементов списка

    $.ajax({

       url: requestUri,

       type: "POST",

       contentType: "application/json",

       headers: requestHeaders,

       data: requestBody,

       success: onSuccess,

       error: onError

    });

};

// Функция выполнится в случае успеха

var onSuccess = function onSuccessF(data) {

    alert('Элемент обновлен');

};

// Функция выполнится в случае ошибки

var onError = function onErrorF(error) {

    // Возвращаемый объект не полностью объект

    // в responseText содержится не объект, а текст, поэтому необходимо выполнить парсинг

    var message = JSON.parse(error.responseText);

    alert("Error: " + message.error.message.value);

};

updateListItem();

Удаление элемента

var deleteListItem = function deleteListItemF() {

    var itemId = 23;

    var listName = 'Подразделения'; 

    var internalListName = 'Departments';

    // Строка получения всех элементов с ограничением возвращаемого состава полей и сортировкой

    var requestUri = _spPageContextInfo.webAbsoluteUrl +

            "/_api/web/lists/getByTitle('"+listName+"')/items("+itemId+")/";

    // Определение заголовка ACCEPT

    var requestHeaders = {

        "accept": "application/json;odata=verbose",

        "content-type": "application/json;odata=verbose",

        "X-RequestDigest": $('#__REQUESTDIGEST').val(),

        "If-Match": "*"

    };    // Ajax вызов получения элементов списка

    $.ajax({

       url: requestUri,

       type: "DELETE",

       contentType: "application/json",

       headers: requestHeaders,

       success: onSuccess,

       error: onError

    });

};

// Функция выполнится в случае успеха

var onSuccess = function onSuccessF(data) {

    alert('Элемент удален');

};

// Функция выполнится в случае ошибки

var onError = function onErrorF(error) {

    // Возвращаемый объект не полностью объект

    // в responseText содержится не объект, а текст, поэтому необходимо выполнить парсинг

    var message = JSON.parse(error.responseText);

    alert("Error: " + message.error.message.value);

};

deleteListItem();

На самом деле вариативность действий шире, чем в описанных примерах, но базовую суть они отображают.

См. так же:


Опубликовано: 04.02.2014
Автор: Андрей Кольтяков