PnP JS Core - заслуживает ли внимания?

Довольно длительное время мы игнорировали PnP-JS-Core и предпочитали старый добрый JSOM или REST запросы с помощью jQuery.ajax или SP.RequestExecutor. "Зачем использовать дополнительные обертки над API, которые могут быть дополнительным узлом в отказоустойчивости решения?", вот такой вопрос лично я задавал сам себе и откладывал знакомство с PnP-JS-Core.

Но, вот недавно предоставилась возможность изучить библиотеку на факт целесообразности использовать ее на проектах. С первого же взгяда создалось довольно позитивное впечатление. Предже всего, используется комплекс документов, который плотно прижился в нашей команде. Помимо этого, открыв страницу контрибьютеров проекта, я увидел большое число знакомых лиц, не зная до этого о их причастности. Для начала не плохо.

Что же это такое?

PnP-JS-Core является одним из проектов "Office 365 Developer Patterns and Practices" (инфраструктура проектов с отрытым исходным кодом Microsoft и сообщества с библиотеками, примерами и документации) для работы SharePoint с помощью JavaScript.

По сути дела, библиотека представляет собой обертку SharePoint REST API и набор "хелперов". PnP JS Core предоставляет fluent-подход по формированию обращений к REST методам, облегчая процесс разработки.

Стек и проект

Реализация библиотеки выполнена с использованием полюбившимися подходами и инструментарием: TypeScript, Gulp, NPM, Typings, Git, Serve... все, что так знакомо и привычно. Довольно просто разобраться в структуре проекта, логике и даже, по необходимости, расширить возможности по своим требованиям.

Разбираться в исходниках, впрочем, совсем не обязательно, но часто проще разобраться с задачей, глядя в код или примеры. В итоге, разобраться с PnP-JS-Core и начать ее использовать не составляет большого труда.

Использование

Установить PnP-JS-Core можно как с помощью NPM/YARN так и Bower. Библиотека может быть использована, как в составе проекта на TypeScript, так и для непосредственного подключения на странице с использованием в Valila JavaScript.

PnP-JS-Core использует протокол fetch и ES6 "промисы" (promises), поэтому для того, чтобы добавить поддержку аутсайдерам браузеров (я про IE), необходимо не забыть загрузить "полифилы" (polyfills) на страницу. Если упастить это из виду, проигнорировав упоминание в документации, то можно удивится, "что же в IE-то ничего не работает?", что это еще за сообщения в консоли "'Headers' is undefined?"”. Но, спокойно, с добавленными es-promise и fetch polyfills, библиотека отлично работает в IE и Edge.

Синтаксис

PnP-JS-Core использует базовый объект pnp (если используется подключение через импорт в TypeScript) и $pnp (если добавлять pnp.js в виде ссылки на странице для написания пода на чистом JS, например, в консоли или сниппетах).

REST запросы с использованием PnP строятся с использованием "флюент" (fluent) API цепочки-построители/хелперы с инициацией "промиса" запроса в конце выражения.

Например, для построения обращения к REST интерфейсу /_api/web/lists/getByTitle('Мой список')/items на PnP необходимо написать следующий под:

$pnp.sp.web 
  .lists.getByTitle('Мой список').items 
  .get() 
  .then(function(items) { 
    // результаты запроса в массиве `items`
  });

$pnp.sp.web.lists.getByTitle('Мой список').items – данный конструктор построить обращение, аналогичное вышеупомянутому URI.

Очень сильно в процессе написания кода помогает IntelliSense, поэтому не обязательно помнить на изусть возможные методы и свойства, в принципе, можно вообще не подозревать о наличии REST API (шутка конечно, лучше иметь представление о структуре интерфейса), но для случаев забывчивости очень даже полезно иметь такую помощь.

Я все же крайне рекомендую четко представлять структуру REST API SharePoint и планировать получение преимуществ от использования PnP только после, либо совмещать библиотеку и понимание, что она выполняет на фоне.

После того, как составлена цепочка обращения к API, необходимо использовать метод get, который инициирует обращение запроса на сервер. Метод Get и некоторые другие возвращают "промис", у него необходимо вызывать методы then и catch для обработки результатов выполнения.

"Флюент" API, на самом деле, отличный помощник. Предоставляющий в том числе и параметры запросов, такие как, $select$filter$extend$top и др. в виде "хелперов". Тем не менее, не все REST API обернуто в библиотеку, часто возникают случаи отсутствия, особенно, нововведений.

К примеру, сходу наткнулся на отсутствие возможности получание списка по URL (web.getList('url')), который я считаю единственным правильным способом обращения к спискам и библиотекам. Руки бы отрывать тем, кто для этого использует Display Name или GUID (которые влегкую могут быть либо изменены пользователем, либо меняться от деплоя к деплою). ;) Однако, это не остановило меня от того, чтобы "форкнуть" проект, добавить метод и оформить "пулл реквест". Теперь pnp.sp.web.getList в наличии и можно обращаться к спискам по человечески /_api/web/getlist(‘/sites/site/web/list/name’).

Такие вот преимущества проектов с исходным кодом, которые к тому же и допольно активно развиваются. Как минимум не стоят на месте.

Пакетные запросы

Довольно известный факт, что REST API штука допольно "говорливая". Одним из преимуществ JSOM, например, всегда была возможность сформировать очередь из обращений к серверу и запустить ее одним физическим запросом (executeQueryAsync). Это конечно так. Но знали ли Вы, что в REST так же есть возможность формировать пакетные запросы? Оно конечно есть только SharePoint Online и SharePoint 2016. Однако, /_api/$batch - стоит того.

PnP значительно упрощает использование пакетных запросов. Запросы могут быть добавлены в очередь и вызываться пакетно следующим образом:

var batchResults = [];
var batch = new $pnp.sp.createBatch();
$pnp.sp.web.getList('/sites/dev01/lists/custom01').items.inBatch(batch).get().then(function(d) {
  batchResults.push({ 
    custom01: d 
  });
});
$pnp.sp.web.getList('/sites/dev01/lists/custom02').items.inBatch(batch).get().then(function(d) {
  batchResults.push({ 
    custom02: d 
  });
});
for (var i = 0, len = 10; i < len; i += 1) {
  $pnp.sp.web.getList('/sites/dev01/lists/custom03').inBatch(batch).items.add({ 
    Title: 'Item ' + i 
  });
}
batch.execute().then(function() {
  console.log("All is done!", batchResults);
});

Было очень приятно обнаружить такую простоту и мощь одновременно.

Жаль конечно, что "батчи" в REST отсутствуют в SharePoint 2013, на нем все еще подовляющее большинство проектов.

Заключение

За последние годы вокруг PnP было довольно много шумихи, на удивление, многие, кто ссылается на PnP зачастую понятия не имеют, о чем они говорят, никогда не углубляясь в подробности реализации, а только повторяя PnP как мантру. Особенно это касается провизии в PnP, которая, мягко говоря, ужасна и рядом не стояла с ближайшим конкурентом, но сейчас не об этом.

PnP-JS-Core - это не про провизию, это простая, легкая обертка над REST API, заслуживающая внимания и шанса использования в рабочих проектах. Как минимум, я дам библиотеке шанс, задейстовав PnP-JS-Core на очередном проекте.

UPD:

Попробовал PnP-JS-Core в связке с sp-rest-proxy, что-то даже работает! :)

* Такая связка конечно будет только работать для GET запросов в силу специфики реализациим sp-rest-proxy и pnp.


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