Работа с API SharePoint из локального SPFx Workbench
При работе с Framework (SPFx) разработчик может использовать как локальный сценарий, так и удаленную отладку.
Во время запуска gulp serve
стартует локальный сервер со средой исполнения веб-частей. Локальный воркбенч доступен по ссылке https://localhost:4321/temp/workbench.html
, он представляет собой страницу, которая немного похожа на Modern UI SharePoint'а, однако это просто локально хостящаяся страница на ней нет возможности работы с данными из SharePoint.
В локальном режиме предполагается создание искусственных ответов от API в виде mock-данных, подготовленных заранее и лежащих прямо в отладочной части кода. В локальном ворбенче работает горячая перезагрузка страницы по мере изменений в проекте, это очень удобная возможность.
Зачастую mock-данных недостаточно, так же их подготовка, актуализация и сверка по формату с настоящими ответами от API допольно трудоемка.
SPFx так же можно отлаживать непосредственно на странице SharePoint в рамках удаленного воркбенча, рамполагающегося по пути [SHAREPOINT_WEB_URL]/_layouts/15/workbench.aspx
. Можно запустить gulp serve --nobrowser
(--nobrowser
блокирует автоматическое открытие страницы локального ворбенча) и размещать разрабатываемые веб-части в ворбенче. Либо даже использовать специальные отладочные параметры вставляемые на любой странице. Такой режим уже полноценно позволяет работать с API.
На этом моменте можно спросить "Ладно, буду использовать удаленный ворбенч или отладочную адресную строку. Зачем вообще тогда локальный ворбенч?". На самом деле очень логичный и хороший вопрос. Но, поверьте, всегда есть какие-то случаи и сценарии применения, где бы не помешала бы опция "локально, но с API". Совершенно случайно, такая опция есть, давайте рассмотрим.
Настройка SPFx проекта для использования прокси
Для начала нам нужен SPFx проект.
1. В SPFx проекте устанавливаем API прокси.
npm install sp-rest-proxy --save-dev
sp-rest-proxy зависимость уровня разработки, позволяет аутентифицироваться и маршрутизировать запросы в API SharePoint без проблем с аутентификацией и CORS.
2. Создаем proxy.js
где-нибудь в проекте со следующим содержимым:
const CertificateStore = require('@microsoft/gulp-core-build-serve/lib/CertificateStore');
const RestProxy = require('sp-rest-proxy');
const settings = {
port: 4323,
protocol: 'https',
ssl: {
cert: CertificateStore.default.instance.certificateData,
key: CertificateStore.default.instance.keyData
}
};
const restProxy = new RestProxy(settings);
restProxy.serve();
[ Скачать скрипт ]
Для того, чтобы можно было обращаться к прокси со страницы воркбенча, прокси должен использовать SSL и быть запущен на HTTPS, соответственно. Переиспользуем SSL сертификаты из состава SPFx (тем самым gulp trust-dev-cert
и gulp untrust-dev-cert
распространяются не только на SPFx ворбенч, но и для прокси).
3. Сздаем npm
дазачу для запуска прокси, например: "proxy": "node ./proxy"
.
4. Для подключения в SharePoint запускаем node ./proxy
или только что созданную задачу npm run proxy
.
Во время первого запуска в консоли должен появиться мастер подключения к SharePoint, где указывает Site URL и прочие желаемые авторизационные параметры. Подробности можно узнать в репозитории проекта.
5. Настроить задачу запуска прокси и локального веб-сервера одновременно, например с помощью concurrently или npm-run-all.
Настройка concurrently
:
5.1 Установить зависимость:
npm install concurrently --save-dev
5.2 Добавить задачу запуска в package.json:
"scripts": {
...
"serve": "concurrently --kill-others "npm run proxy" "gulp serve""
...
}
Теперь при запуска задачи будет стартовать и прокси и локальный сервер SPFx:
npm run serve
На этом настрока проекта завершена и можно рассмотреть аспекты, связанные с разработкой.
Определение режима работы веб-части
Благодаря использованию прокси, SPFx решение может обращаться в API даже будучи запущенным локально. Все, что нам требуется реализовать, так это определение режима и переключение между адресами.
Предположим, что сайт SharePoint расположен по адресу https://contoso.sharepoint.com/sites/site/my_web
.
SPFx веб-части, по большому счету, все равно, где она будет размещена. Фактический адрес сайта предоставлябется через SPFx контекст: в объекте this.context.pageContext.web
есть absoluteUrl
, serverRelativeUrl
, пр. Запроса к API должны динамически определять нужный эндпойнт.
В локальном режиме, напротив, SPFx ничего не знает о том, где расположен SharePoint. И мы ответствтенны за определение и указание правильного адреса. Однако, с прокси, этот адрес задан в настройках и чаще всего он будет всегда одинаковый https://localhost:4323
, относительный путь до веба при этом должен быть определен где-то в настройках.
В локальном режиме веб-часть должна сформировать путь до API эндпойнтов в виде https://localhost:4323/sites/site/my_web/_api/...
. При этом, всегда нужно оперировать с абсолютными путями.
Когда это понятно, становится очевидно, что нужно определять режим "локальный" или "удаленный". В SPFx есть соответствующий хелпер (нет даже необходимости в чем-то на подобии window.location.href.indexOf('https://localhost:') === 0
):
import { Environment, EnvironmentType } from '@microsoft/sp-core-library';
if (Environment.type === EnvironmentType.Local) {
// Local mode
} else {
// Online mode
}
Используя режимы, мы можем задавать нужные корректные эндпойнты.
Бонус - настройка PnPjs
Как многие знают, я причастен к проекту PnPjs и предпочитаю использовать данную библиотеку на проектах.
PnPjs прекрасно работает совместно с SPFx, помимо этого рад сообщить, что и в связке с API Proxy все хорошо. Требуемая настройка проста:
import { Web, setup } from '@pnp/sp';
import { proxyUrl, webRelativeUrl } from './../settings';
// settings.ts should be created with corresponding exports
...
let web: Web;
if (Environment.type === EnvironmentType.Local) {
web = new Web(`${proxyUrl}${webRelativeUrl}`);
} else {
// On SharePoint page sp-pnp-js should be configured with
setup({ spfxContext: this.context });
// or a Web object should be created with explicit web URL
web = new Web(this.context.pageContext.web.absoluteUrl);
}
// Then universal pnp code and dealing with SPFx specifics
/*
web.lists.get()
.then(...).catch(...);
*/
...
Пример
По следующей ссылке представлен пример проекта, в котором настроено все вышеописанное.
Опубликовано: 17.12.2018
Автор: Андрей Кольтяков