Как подключить api к excel
Argument ‘Topic id’ is null or empty
Сейчас на форуме
© Николай Павлов, Planetaexcel, 2006-2023
info@planetaexcel.ru
Использование любых материалов сайта допускается строго с указанием прямой ссылки на источник, упоминанием названия сайта, имени автора и неизменности исходного текста и иллюстраций.
| ООО «Планета Эксел» ИНН 7735603520 ОГРН 1147746834949 |
ИП Павлов Николай Владимирович ИНН 633015842586 ОГРНИП 310633031600071 |
Получение и обработка данных с помощью пользовательских функций
Одним из способов, которыми пользовательские функции расширяют возможности Excel, является получение данных из расположений, отличных от книги, таких как веб-сайт или сервер (через WebSocket). Вы можете запрашивать внешние данные через API, например Fetch или с помощью XmlHttpRequest (XHR), стандартного веб-API, который отправляет HTTP-запросы для взаимодействия с серверами.
Обратите внимание, что настраиваемые функции доступны в Excel на следующих платформах.
- Office для Windows
- Подписка на Microsoft 365
- Розничный бессрочный Office 2016 и более поздних версий
В настоящее время пользовательские функции Excel не поддерживаются в следующих приложениях:
- Office для iPad
- корпоративные бессрочные версии Office 2019 или более ранних версий
Функции, которые возвращают данные из внешних источников
Если пользовательская функция извлекает данные из внешнего источника, например, сайта, она должна:
- Возвращает JavaScript Promise в Excel.
- Promise Разрешите с окончательным значением с помощью функции обратного вызова.
Пример получения данных
В следующем примере webRequest кода функция обращается к гипотетическому внешнему API, который отслеживает количество людей, которые в настоящее время находятся на Международной космической станции. Функция возвращает JavaScript Promise и использует fetch для запроса информации из гипотетического API. Полученные данные преобразуются в JSON, names а свойство преобразуется в строку, которая используется для разрешения обещания.
При разработке собственных функций может потребоваться выполнение действия, если веб-запрос не завершается своевременно. Также можно рассмотреть совмещение нескольких запросов API.
/** * Requests the names of the people currently on the International Space Station. * Note: This function requests data from a hypothetical URL. In practice, replace the URL with a data source for your scenario. * @customfunction */ function webRequest() < let url = "https://www.contoso.com/NumberOfPeopleInSpace"; // This is a hypothetical URL. return new Promise(function (resolve, reject) < fetch(url) .then(function (response)< return response.json(); >) .then(function (json) < resolve(JSON.stringify(json.names)); >) >) >При использовании метода fetch не создаются вложенные обратные вызовы, что в некоторых случаях может быть предпочтительнее, чем использование метода XHR.
Пример XHR
В следующем примере кода функция вызывает API GitHub для обнаружения количества звезд, getStarCount предоставленных репозиторию конкретного пользователя. Это асинхронная функция, которая возвращает JavaScript Promise . При получении данных из веб-вызова выполняется разрешение обещания, которое возвращает данные в ячейку.
/** * Gets the star count for a given Github organization or user and repository. * @customfunction * @param userName string name of organization or user. * @param repoName string name of the repository. * @return number of stars. */ async function getStarCount(userName: string, repoName: string) < const url = "https://api.github.com/repos/" + userName + "/" + repoName; let xhttp = new XMLHttpRequest(); return new Promise(function(resolve, reject) < xhttp.onreadystatechange = function() < if (xhttp.readyState !== 4) return; if (xhttp.status == 200) < resolve(JSON.parse(xhttp.responseText).watchers_count); >else < reject(< status: xhttp.status, statusText: xhttp.statusText >); > >; xhttp.open("GET", url, true); xhttp.send(); >); >Создание функции потоковой передачи
Пользовательские функции потоковой передачи позволяют выводить данные в ячейки, которые повторно обновляются, не требуя от пользователя явно что-либо обновлять. Такие функции (например, функция из руководства по пользовательским функциям) могут быть полезны для проверки данных, обновляемых в реальном времени, из веб-службы.
Чтобы объявить функцию потоковой передачи, можно использовать один из следующих двух параметров.
- Тег @streaming JSDoc.
- Параметр CustomFunctions.StreamingInvocation вызова.
Следующий пример кода — это пользовательская функция, которая добавляет число к результату каждую секунду. Обратите внимание на указанные ниже аспекты этого кода.
- Excel отображает каждое новое значение автоматически с помощью метода setResult .
- Второй параметр ввода, invocation , не отображается для конечных пользователей в Excel, когда они выбирают функцию в меню «Автозаполнение».
- Обратный onCanceled вызов определяет функцию, которая выполняется при отмене функции.
- Потоковая передача не обязательно связана с выполнением веб-запроса. В этом случае функция не выполняет веб-запрос, но по-прежнему получает данные через заданные интервалы, поэтому для нее требуется использовать параметр потоковой передачи invocation .
/** * Increments a value once a second. * @customfunction INC increment * @param incrementBy Amount to increment * @paraminvocation */ function increment(incrementBy, invocation) < let result = 0; const timer = setInterval(() =>< result += incrementBy; invocation.setResult(result); >, 1000); invocation.onCanceled = () => < clearInterval(timer); >; > Пример возврата динамического массива разлива из функции потоковой передачи см. в разделе Возврат нескольких результатов из пользовательской функции: примеры кода.
Отмена функции
Excel отменяет выполнение функции в следующих ситуациях.
- Когда пользователь редактирует или удаляет ячейку, ссылающуюся на функцию.
- Когда изменяется один из аргументов (входных параметров) функции. В этом случае после отмены выполняется новый вызов функции.
- Когда пользователь вручную вызывает пересчет. В этом случае после отмены выполняется новый вызов функции.
Также можно настроить стандартное значение потоковой передачи, чтобы обрабатывать случаи выполнения запроса, когда вы находитесь в автономном режиме.
Существует также категория функций, называемых отменяемыми функциями @cancelable , которые используют тег JSDoc. Отменяемые функции позволяют завершать веб-запрос в середине запроса.
Функция потоковой передачи @cancelable не может использовать тег, но функции потоковой передачи могут включать функцию обратного onCanceled вызова. Только асинхронные пользовательские функции, возвращающие одно значение, могут использовать @cancelable тег JSDoc. Дополнительные сведения о теге см. в @cancelable этой Autogenerate JSON metadata: @cancelable статье.
Использование параметра вызова
Параметр invocation является по умолчанию последним в любой пользовательской функции. Параметр invocation предоставляет контекст ячейки (например, ее адрес и содержимое) и позволяет использовать setResult метод и onCanceled событие, чтобы определить, что функция делает при потоковой передаче ( setResult ) или отмене ( onCanceled ).
См. раздел Параметр вызова , чтобы узнать о других потенциальных возможностях использования аргумента invocation и о том, как он соответствует объекту Вызова .
Получение данных через WebSockets
В пределах пользовательской функции можно использовать WebSockets для обмена данными через постоянное соединение с сервером. С помощью WebSocket пользовательская функция может открыть соединение с сервером, а затем автоматически получать сообщения от сервера при возникновении определенных событий без необходимости явного опроса данных на сервере.
Пример WebSockets
Следующий примера кода устанавливает соединение WebSocket, а затем заносит в журнал каждое входящее сообщение от сервера.
let ws = new WebSocket('wss://bundles.office.com'); ws.onmessage(message) < console.log(`Received: $`); > ws.onerror(error)< console.err(`Failed: $`); >Дальнейшие действия
- Ознакомьтесь с разными типами параметров, которые могут использоваться функциями.
- Узнайте, как пакетно обрабатывать несколько вызовов API.
См. также
- Пересчитываемые значения в функциях
- Создание метаданных JSON для пользовательских функций
- Создание метаданных JSON вручную для пользовательских функций
- Создание пользовательских функций в Excel
- Руководство по пользовательским функциям в Excel
Как Excel и VBA помогают отправлять тысячи HTTP REST API запросов
Работая в IoT-сфере и плотно взаимодействуя с одним из основных элементов данной концепции технологий – сетевым сервером, столкнулся вот с какой проблемой (задачей): необходимо отправлять много запросов для работы с умными устройствами на сетевой сервер. На сервере был реализован REST API с оболочкой Swagger UI, где из графической оболочки можно было отправлять только разовые запросы. Анализ сторонних клиентов, типа Postman или Insomnia показал, что простого визуального способа поместить в скрипт массив из необходимого перечня идентификаторов устройств (или любых других элементов сервера), для обращения к ним – не нашлось.
Так как большая часть работы с выгрузками и данными была в Excel, то решено было вспомнить навыки, полученные на учебе в университете, и написать скрипт на VBA, который бы мою задачку решал.
- получать информацию по устройствам с различными параметрами фильтрации (GET);
- применять изменения в конфигурации по устройствам: имя, профиль устройства, сетевые лицензии и пр. (PUT);
- отправлять данные для конфигурации и взаимодействия с устройствами (POST).
И сегодня я расскажу вам про то, как с помощью Excel, пары формул и самописных функций на VBA можно реализовать алгоритм, отправляющий любое необходимое количество REST-API запросов с использованием авторизации Bearer Token.
Данная статья будет полезная тем, кто воспользуется данным решением под Windows, но еще больше она будет полезна тем людям, которые хотят использовать данное решение на MacOS (с Excel x64) . Как вы уже догадались, ниже будут рассмотрены два варианта реализации под разные системы, так как с MacOS есть нюанс.
Часть 1. Реализация решения под Windows
GET
Начнем с самого простого: GET – запросов. В данном примере необходимо получить ответ (информацию) от сервера по заданному списку устройств.
Для реализации GET – запросов нам дано:
1) Ссылка, в которой указываются параметры запроса.
2) Заголовки запроса + Токен авторизации (Bearer Token)
—header ‘Accept: application/json’ —header ‘Authorization: Bearer
3) Параметр, указываемый в ссылке (в данном примере это идентификаторы устройств – DevEUI):
Имея такие данные на входе, делаем в Excel лист-шаблон, который заполняем в соответствии с тем, что имеем:
- столбец А уходит вот значения параметров
- столбец F уходит под ссылку-родителя
- столбец H уходит под заголовки, где в ячейке H1 единоразово для текущего листа указывается токен:
=СЦЕП(«—header ‘Accept: application/json’ —header ‘Authorization: Bearer «;$H$1;»‘»)
- столбец I уходит под URL (ссылки-дети, на основе ссылки-родителя)

- столбец J уходит под результат (ответ от сервера)
Далее, нам необходимо реализовать подпрограмму(макрос) отправки GET-запросов. Состоит она из четырех частей:
- цикла, который считает количество строк для работы по листу, пробегая по столбцу А с 2 по первую пустую ячейку, чтобы у цикла был конец.
- функции, для работы с REST API (используется стандартная, библиотека Msxml2.XMLHTTP.6.0, встроенная в Windows., поэтому сложностей с реализацией не возникает. Для MacOS есть альтернатива)
- временной задержки, в случае если нужно отправлять запросы не сразу, после получения ответа, а задав время ожидания
- таймером, который показывает время выполнения всего макроса после завершения Код:
Sub GET_Request() Dim i As Integer Dim j As Integer Dim objHTTP As Object Dim Json As String Dim result As String Dim URL As String Dim Token As String a = Timer i = 1 Do While Not IsEmpty(Cells(i, 1)) i = i + 1 Loop i = i - 1 'MsgBox i For j = 2 To i Json = Range("D" & j) URL = Range("I" & j) Token = Range("H1") Set objHTTP = CreateObject("Msxml2.XMLHTTP.6.0") objHTTP.Open "GET", URL, False objHTTP.setRequestHeader "Content-type", "application/json" objHTTP.setRequestHeader "Accept", "application/json" objHTTP.setRequestHeader "Authorization", "Bearer " + Token objHTTP.Send (Json) result = objHTTP.responseText Range("J" & j).Value = result Set objHTTP = Nothing 'Application.Wait (Now + TimeValue("0:00:01")) Next j MsgBox Timer - a End SubПривязываем подпрограмму к кнопкам для удобства и выполним скрипт. Получается:

Таким образом, скрипт проходит по столбцу I, забирая из значения каждой ячейки URL, для тех строк, где в столбце А есть значения (которые и подставляются в URL). Для удобства также сделаны кнопки очистки полей и подсветка запросов условным форматированием, в случае успешного ответа на запрос.
PUT
Чуть-чуть усложним задачу и перейдем к PUT-запросам. В данном примере необходимо изменить профиль устройства, чтобы сервер по-другому с ним взаимодействовал.
К исходным данным для GET – запроса добавляется тело запроса с ключем-значением (п4). Итого дано:
1) Ссылка, в которой указываются параметры запроса.
2) Заголовки запроса + Токен авторизации (Bearer Token)
—header ‘Content-Type: application/json’ —header ‘Accept: application/json’ —header ‘Authorization: Bearer
3) Параметр, указываемый в ссылке (в данном примере это внутренние идентификаторы устройств – hRef):
4) Тело запроса, с ключом и значением:
Немного дополняем новый PUT-лист в Excel по сравнению с GET (остальное без изменений):
- новый столбец B теперь отвечает за ключ deviceProfileId (ячейка B1), а все значения ниже за его возможные значения)
- столбец D отвечает за формирование итогового тела сообщения в формате JSON.
Немного поменяем макрос и вынесем его в отдельную подпрограмму:
Sub PUT_Request() Dim i As Integer Dim j As Integer Dim objHTTP As Object Dim Json As String Dim result As String Dim URL As String Dim Token As String a = Timer i = 1 Do While Not IsEmpty(Cells(i, 1)) i = i + 1 Loop i = i - 1 'MsgBox i For j = 2 To i Json = Range("D" & j) URL = Range("I" & j) Token = Range("H1") Set objHTTP = CreateObject("Msxml2.XMLHTTP.6.0") objHTTP.Open "PUT", URL, False objHTTP.setRequestHeader "Content-type", "application/json" objHTTP.setRequestHeader "Accept", "application/json" objHTTP.setRequestHeader "Authorization", "Bearer " + Token objHTTP.Send (Json) result = objHTTP.responseText Range("J" & j).Value = result Set objHTTP = Nothing 'Application.Wait (Now + TimeValue("0:00:01")) Next j MsgBox Timer - a End SubПривяжем макрос к кнопке и выполним.
Логика абсолютно аналогична GET запросу.

POST
Для POST запросов все аналогично PUT. Только немного меняется код в части типа запроса. В данном примере на устройство отправляется команда-конфигурация с указанием тела посылки (payload_hex) и порта (fport) для конкретного устройства.
Sub PUT_Request() Dim i As Integer Dim j As Integer Dim objHTTP As Object Dim Json As String Dim result As String Dim URL As String Dim Token As String a = Timer i = 1 Do While Not IsEmpty(Cells(i, 1)) i = i + 1 Loop i = i - 1 'MsgBox i For j = 2 To i Json = Range("D" & j) URL = Range("I" & j) Token = Range("H1") Set objHTTP = CreateObject("Msxml2.XMLHTTP.6.0") objHTTP.Open "PUT", URL, False objHTTP.setRequestHeader "Content-type", "application/json" objHTTP.setRequestHeader "Accept", "application/json" objHTTP.setRequestHeader "Authorization", "Bearer " + Token objHTTP.Send (Json) result = objHTTP.responseText Range("J" & j).Value = result Set objHTTP = Nothing 'Application.Wait (Now + TimeValue("0:00:01")) Next j MsgBox Timer - a End SubПолучившаяся таблица выглядит следующим образом:

На этом часть для Windows заканчивается. Здесь все оказалось довольно просто: стандартная библиотека, простенький алгоритм перебора значений в цикле.
Часть 2. Реализация решения под MacOS и Excel 64-bit
В виду того, что работал я на двух машинах под управлением разных ОС, хотелось, чтобы решение было универсальным. В итоге, собрав по крупицам информацию по интернет-форумам с данной тематикой у меня вышло следующее решение. Принцип работы его остается схожим, а изменения были внесены в часть, где использовалась стандартная библиотека WindowsMsxml2.XMLHTTP.6.0, которой в MacOS не было по понятным причинам.
Чтобы обойти данное ограничение, был выбран единственный рабочий подход через cUrl, exec и функции. Данное решение точно работает под версией MacOS 13 и Excel 16.78. Функция ниже, в том или ином виде, встречается на различных форумах, однако на текущих версиях софта – не работает. В итоге, после небольших правок получили рабочий вариант:
Была отлажена функция вызова ExecShell:
Option Explicit Private Declare PtrSafe Function popen Lib "/usr/lib/libc.dylib" (ByVal Command As String, ByVal Mode As String) As LongPtr Private Declare PtrSafe Function pclose Lib "/usr/lib/libc.dylib" (ByVal file As LongPtr) As Long Private Declare PtrSafe Function fread Lib "/usr/lib/libc.dylib" (ByVal outStr As String, ByVal size As LongPtr, ByVal items As LongPtr, ByVal stream As LongPtr) As Long Private Declare PtrSafe Function feof Lib "/usr/lib/libc.dylib" (ByVal file As LongPtr) As LongPtr Function execShell(Command As String, Optional ByRef exitCode As Long) As String Dim file As LongPtr file = popen(Command, "r") If file = 0 Then Exit Function End If While feof(file) = 0 Dim chunk As String Dim read As Long chunk = Space(500) read = fread(chunk, 1, Len(chunk) - 1, file) If read > 0 Then chunk = Left$(chunk, read) execShell = execShell & chunk End If Wend exitCode = pclose(file) End FunctionИ написаны отдельные функции для работы с различным методами GET / PUT / POST, которые на входе принимают URL и параметры):
Function HTTPGet(sUrl As String, sQuery As String) As String Dim sCmd As String Dim sResult As String Dim lExitCode As Long sCmd = "curl -X GET " & sQuery & "" & " " & sUrl sResult = execShell(sCmd, lExitCode) HTTPGet = sResult End Function Function HTTPPost(sUrl As String, sQuery1 As String, sQuery2 As String) As String Dim sCmd As String Dim sResult As String Dim lExitCode As Long sCmd = "curl -X POST " & sQuery1 & "" & " -d " & sQuery2 & "" & " " & sUrl sResult = execShell(sCmd, lExitCode) HTTPPost = sResult End Function Function HTTPPut(sUrl As String, sQuery1 As String, sQuery2 As String) As String Dim sCmd As String Dim sResult As String Dim lExitCode As Long sCmd = "curl -X PUT " & sQuery1 & "" & " -d " & sQuery2 & "" & " " & sUrl sResult = execShell(sCmd, lExitCode) HTTPPut = sResult End FunctionТак как мы заменяем библиотеку Msxml2.XMLHTTP.6.0 – поменялась реализация макросов в этой части: мы заменили Msxml2 на написанные выше функции и получили следующее:
'GET-запросы Sub SendGETRequest() Dim i As Integer Dim j As Integer Dim result As String Dim URL As String Dim Auth As String a = Timer 'Подсчет заполненных ячеек первого столбца i = 1 Do While Not IsEmpty(Cells(i, 1)) i = i + 1 Loop i = i - 1 'Цикл, который отправляет запрос от 2 до последнего элемента For j = 2 To i URL = Range("I" & j) Auth = Range("H" & j) result = HTTPGet(URL, Auth) Range("J" & j).Value = result 'Application.Wait (Now + TimeValue("0:00:01")) Next j MsgBox Timer - a End Sub 'PUT-запросы Sub SendPUTRequest() Dim i As Integer Dim j As Integer Dim result As String Dim URL As String Dim Auth As String Dim Message As String a = Timer 'Подсчет заполненных ячеек первого столбца i = 1 Do While Not IsEmpty(Cells(i, 1)) i = i + 1 Loop i = i - 1 'Цикл, который отправляет запрос от 2 до последнего элемента For j = 2 To i Message = Range("D" & j) URL = Range("I" & j) Auth = Range("H" & j) result = HTTPPut(URL, Auth, Message) Range("J" & j).Value = result 'Application.Wait (Now + TimeValue("0:00:01")) Next j MsgBox Timer - a End Sub 'POST-запросы Sub SendPOSTRequest() Dim i As Integer Dim j As Integer Dim result As String Dim URL As String Dim Auth As String Dim Message As String a = Timer 'Подсчет заполненных ячеек первого столбца i = 1 Do While Not IsEmpty(Cells(i, 1)) i = i + 1 Loop i = i - 1 'Цикл, который отправляет запрос от 2 до последнего элемента For j = 2 To i Message = Range("D" & j) URL = Range("I" & j) Auth = Range("H" & j) result = HTTPPost(URL, Auth, Message) Range("J" & j).Value = result 'Application.Wait (Now + TimeValue("0:00:01")) Next j MsgBox Timer – aИтог
В итоге, у меня получилось аналогичное windows по работе и функционалу решение для MacOS 13 Ventura с использованием Excel 64-bit (версия 16.80).
На просторах интернета я не нашел какого-то сборного и единого описания, только фрагменты кода и подходов, которые в большинстве случаев не работали полностью или частично. Поэтому решил объединить все в рабочее решение и выложить на хабр для истории.
На текущий момент я все еще не встретил иного решения, которое бы позволяло в пару кликов копипастить тысячи идентификаторов и параметров из excel и массово их отправлять на сервер. Надеюсь, кому-то пригодится 🙂
Если такие сторонние решения есть, а я не в курсе, и все можно было сделать проще, быстрее и изящнее – делитесь опытом в комментариях.
Файл-пример, который можно потыкать, пока жив сервер и «бессрочный» токен:
Рекомендации по работе с API Excel
В этой статье приведены рекомендации по работе с API Excel в Microsoft Graph.
Наиболее эффективным способом управления сеансами
Если у вас есть несколько вызовов в течение определенного периода времени, рекомендуется создать сеанс и передать идентификатор сеанса с каждым запросом. Чтобы представить сеанс в API, используйте заголовок workbook-session-id: . Это позволяет наиболее эффективно использовать API-интерфейсы Excel.
В следующем примере показано, как добавить новое число в таблицу, а затем найти одну запись в книге с помощью этого подхода.
Шаг 1. Создание сеанса
Запрос
POST https://graph.microsoft.com/v1.0/me/drive/items//workbook/createSession Content-type: application/json
// Code snippets are only available for the latest version. Current version is 5.x // Dependencies using Microsoft.Graph.Drives.Item.Items.Item.Workbook.CreateSession; var requestBody = new CreateSessionPostRequestBody < PersistChanges = true, >; // To initialize your graphClient, see https://learn.microsoft.com/en-us/graph/sdks/create-client?from=snippets&tabs=csharp var result = await graphClient.Drives[""].Items[""].Workbook.CreateSession.PostAsync(requestBody);// THE CLI IS IN PREVIEW. NON-PRODUCTION USE ONLY mgc drives items workbook create-session post --drive-id --drive-item-id --body '\ 'import ( "context" msgraphsdk "github.com/microsoftgraph/msgraph-sdk-go" graphdrives "github.com/microsoftgraph/msgraph-sdk-go/drives" //other-imports ) graphClient := msgraphsdk.NewGraphServiceClientWithCredentials(cred, scopes) requestBody := graphdrives.NewCreateSessionPostRequestBody() persistChanges := true requestBody.SetPersistChanges(&persistChanges) createSession, err := graphClient.Drives().ByDriveId("drive-id").Items().ByDriveItemId("driveItem-id").Workbook().CreateSession().Post(context.Background(), requestBody, nil)GraphServiceClient graphClient = GraphServiceClient.builder().authenticationProvider( authProvider ).buildClient(); Boolean persistChanges = true; graphClient.me().drive().items("").workbook() .createSession(WorkbookCreateSessionParameterSet .newBuilder() .withPersistChanges(persistChanges) .build()) .buildRequest() .post();const options = < authProvider, >; const client = Client.init(options); const workbookSessionInfo = < persistChanges: true >; await client.api('/me/drive/items//workbook/createSession') .post(workbookSessionInfo);setPersistChanges(true); $result = $graphServiceClient->drives()->byDriveId('drive-id')->items()->byDriveItemId('driveItem-id')->workbook()->createSession()->post($requestBody)->wait();graph_client = GraphServiceClient(credentials, scopes) request_body = CreateSessionPostRequestBody( persist_changes = True, ) result = await graph_client.drives.by_drive_id('drive-id').items.by_drive_item_id('driveItem-id').workbook.create_session.post(request_body)Отклик
Ниже приведен успешный ответ.
HTTP/1.1 201 Created Content-type: application/json
Шаг 2. Добавление новой строки в таблицу
Запрос
POST https://graph.microsoft.com/v1.0/me/drive/items//workbook/tables/
/rows/add Content-type: application/json workbook-session-id: Snippet not available// THE CLI IS IN PREVIEW. NON-PRODUCTION USE ONLY mgc drives items workbook tables rows add post --drive-id --drive-item-id --workbook-table-id --body '\ 'Snippet not availableSnippet not availableconst options = < authProvider, >; const client = Client.init(options); const workbookTableRow = < values: [[“east”, “pear”, 4]] >; await client.api('/me/drive/items//workbook/tables//rows/add') .post(workbookTableRow); Snippet not availableSnippet not availableОтклик
HTTP/1.1 200 OK Content-type: application/json
Шаг 3. Поиск значения в обновленной таблице
Запрос
POST https://graph.microsoft.com/v1.0/me/drive/items//workbook/functions/vlookup Content-type: application/json workbook-session-id: < "lookupValue":"pear", "tableArray":, "colIndexNum":2, "rangeLookup":false >// Code snippets are only available for the latest version. Current version is 5.x // Dependencies using Microsoft.Graph.Drives.Item.Items.Item.Workbook.Functions.Vlookup; using Microsoft.Graph.Models; var requestBody = new VlookupPostRequestBody < LookupValue = "pear", TableArray = new Json < AdditionalData = new Dictionary< < "Address" , "Sheet1!B2:C7" >, >, >, ColIndexNum = 2, RangeLookup = false, >; // To initialize your graphClient, see https://learn.microsoft.com/en-us/graph/sdks/create-client?from=snippets&tabs=csharp var result = await graphClient.Drives[""].Items[""].Workbook.Functions.Vlookup.PostAsync(requestBody, (requestConfiguration) => < requestConfiguration.Headers.Add("workbook-session-id", ""); >);// THE CLI IS IN PREVIEW. NON-PRODUCTION USE ONLY mgc drives items workbook functions vlookup post --drive-id --drive-item-id --body ',\ "colIndexNum":2,\ "rangeLookup":false\ >\ 'import ( "context" abstractions "github.com/microsoft/kiota-abstractions-go" msgraphsdk "github.com/microsoftgraph/msgraph-sdk-go" graphdrives "github.com/microsoftgraph/msgraph-sdk-go/drives" graphmodels "github.com/microsoftgraph/msgraph-sdk-go/models" //other-imports ) graphClient := msgraphsdk.NewGraphServiceClientWithCredentials(cred, scopes) headers := abstractions.NewRequestHeaders() headers.Add("workbook-session-id", "") configuration := &graphdrives.DriveItemItemItemWorkbookFunctionsVlookupRequestBuilderPostRequestConfiguration < Headers: headers, >requestBody := graphdrives.NewVlookupPostRequestBody() lookupValue := "pear" requestBody.SetLookupValue(&lookupValue) tableArray := graphmodels.NewJson() additionalData := map[string]interface<> < "address" : "Sheet1!B2:C7", >tableArray.SetAdditionalData(additionalData) requestBody.SetTableArray(tableArray) colIndexNum := int32(2) requestBody.SetColIndexNum(&colIndexNum) rangeLookup := false requestBody.SetRangeLookup(&rangeLookup) vlookup, err := graphClient.Drives().ByDriveId("drive-id").Items().ByDriveItemId("driveItem-id").Workbook().Functions().Vlookup().Post(context.Background(), requestBody, configuration)Snippet not availableconst options = < authProvider, >; const client = Client.init(options); const workbookFunctionResult = < lookupValue: 'pear', tableArray: , colIndexNum: 2, rangeLookup: false >; await client.api('/me/drive/items//workbook/functions/vlookup') .post(workbookFunctionResult);setLookupValue('pear'); $tableArray = new Json(); $additionalData = [ 'Address' => 'Sheet1!B2:C7', ]; $tableArray->setAdditionalData($additionalData); $requestBody->setTableArray($tableArray); $requestBody->setColIndexNum(2); $requestBody->setRangeLookup(false); $requestConfiguration = new VlookupRequestBuilderPostRequestConfiguration(); $headers = [ 'workbook-session-id' => '', ]; $requestConfiguration->headers = $headers; $result = $graphServiceClient->drives()->byDriveId('drive-id')->items()->byDriveItemId('driveItem-id')->workbook()->functions()->vlookup()->post($requestBody, $requestConfiguration)->wait();graph_client = GraphServiceClient(credentials, scopes) request_body = VlookupPostRequestBody( lookup_value = "pear", table_array = Json( additional_data = < "address" : "Sheet1!B2:C7", >), col_index_num = 2, range_lookup = False, ) request_configuration = VlookupRequestBuilder.VlookupRequestBuilderPostRequestConfiguration() request_configuration.headers.add("workbook-session-id", "") result = await graph_client.drives.by_drive_id('drive-id').items.by_drive_item_id('driveItem-id').workbook.functions.vlookup.post(request_body, request_configuration = request_configuration)Отклик
HTTP code: 200 OK content-type: application/json
Шаг 4. Закрытие сеанса после завершения всех запросов
Запрос
POST https://graph.microsoft.com/v1.0/me/drive/items//workbook/closeSession Content-type: application/json workbook-session-id:
// Code snippets are only available for the latest version. Current version is 5.x // Dependencies using Microsoft.Graph.Drives.Item.Items.Item.Workbook.CloseSession; var requestBody = new CloseSessionPostRequestBody < >; // To initialize your graphClient, see https://learn.microsoft.com/en-us/graph/sdks/create-client?from=snippets&tabs=csharp await graphClient.Drives[""].Items[""].Workbook.CloseSession.PostAsync(requestBody, (requestConfiguration) => < requestConfiguration.Headers.Add("workbook-session-id", ""); >);// THE CLI IS IN PREVIEW. NON-PRODUCTION USE ONLY mgc drives items workbook close-session post --drive-id --drive-item-id --body '\ 'import ( "context" abstractions "github.com/microsoft/kiota-abstractions-go" msgraphsdk "github.com/microsoftgraph/msgraph-sdk-go" graphdrives "github.com/microsoftgraph/msgraph-sdk-go/drives" //other-imports ) graphClient := msgraphsdk.NewGraphServiceClientWithCredentials(cred, scopes) headers := abstractions.NewRequestHeaders() headers.Add("workbook-session-id", "") configuration := &graphdrives.DriveItemItemItemWorkbookCloseSessionRequestBuilderPostRequestConfiguration < Headers: headers, >requestBody := graphdrives.NewCloseSessionPostRequestBody() graphClient.Drives().ByDriveId("drive-id").Items().ByDriveItemId("driveItem-id").Workbook().CloseSession().Post(context.Background(), requestBody, configuration)GraphServiceClient graphClient = GraphServiceClient.builder().authenticationProvider( authProvider ).buildClient(); LinkedList requestOptions = new LinkedList(); requestOptions.add(new HeaderOption("workbook-session-id", "")); graphClient.me().drive().items("").workbook() .closeSession() .buildRequest( requestOptions ) .post();const options = < authProvider, >; const client = Client.init(options); const closeSession = < >; await client.api('/me/drive/items//workbook/closeSession') .post(closeSession);'', ]; $requestConfiguration->headers = $headers; $graphServiceClient->drives()->byDriveId('drive-id')->items()->byDriveItemId('driveItem-id')->workbook()->closeSession()->post($requestBody, $requestConfiguration)->wait();graph_client = GraphServiceClient(credentials, scopes) request_body = CloseSessionPostRequestBody( ) request_configuration = CloseSessionRequestBuilder.CloseSessionRequestBuilderPostRequestConfiguration() request_configuration.headers.add("workbook-session-id", "") await graph_client.drives.by_drive_id('drive-id').items.by_drive_item_id('driveItem-id').workbook.close_session.post(request_body, request_configuration = request_configuration)Отклик
HTTP/1.1 204 No ContentРабота с API- интерфейсами, которые занимают много времени
Вы можете заметить, что для выполнения некоторых операций требуется неопределенное время; например, открытие большой книги. Легко достичь времени ожидания ответа на эти запросы. Чтобы устранить эту проблему, мы предоставляем шаблон длительных операций. При использовании этого шаблона вам не нужно беспокоиться о времени ожидания запроса.
В настоящее время для создания сеанса API Excel в Microsoft Graph включен шаблон длительной операции. Этот шаблон включает в себя следующие шаги:
- Добавьте в Prefer: respond-async запрос заголовок, чтобы указать, что это длительная операция при создании сеанса.
- Длительная операция возвращает 202 Accepted ответ вместе с заголовком Location для получения состояния операции. Если создание сеанса завершается в течение нескольких секунд, он возвращает обычный ответ сеанса создания вместо того, чтобы использовать шаблон длительной операции.
- 202 Accepted С помощью ответа можно получить состояние операции в указанном расположении. Значения состояния операции: notStarted , running , succeeded и failed .
- После завершения операции вы можете получить результат создания сеанса по указанному URL-адресу в успешном ответе.
В следующем примере создается сеанс с использованием шаблона длительных операций.
Первоначальный запрос на создание сеанса
Запрос
POST https://graph.microsoft.com/v1.0/me/drive/items//workbook/createSession Prefer: respond-async Content-type: application/json
// Code snippets are only available for the latest version. Current version is 5.x // Dependencies using Microsoft.Graph.Drives.Item.Items.Item.Workbook.CreateSession; var requestBody = new CreateSessionPostRequestBody < PersistChanges = true, >; // To initialize your graphClient, see https://learn.microsoft.com/en-us/graph/sdks/create-client?from=snippets&tabs=csharp var result = await graphClient.Drives[""].Items[""].Workbook.CreateSession.PostAsync(requestBody, (requestConfiguration) => < requestConfiguration.Headers.Add("Prefer", "respond-async"); >);// THE CLI IS IN PREVIEW. NON-PRODUCTION USE ONLY mgc drives items workbook create-session post --drive-id --drive-item-id --body '\ 'import ( "context" abstractions "github.com/microsoft/kiota-abstractions-go" msgraphsdk "github.com/microsoftgraph/msgraph-sdk-go" graphdrives "github.com/microsoftgraph/msgraph-sdk-go/drives" //other-imports ) graphClient := msgraphsdk.NewGraphServiceClientWithCredentials(cred, scopes) headers := abstractions.NewRequestHeaders() headers.Add("Prefer", "respond-async") configuration := &graphdrives.DriveItemItemItemWorkbookCreateSessionRequestBuilderPostRequestConfiguration < Headers: headers, >requestBody := graphdrives.NewCreateSessionPostRequestBody() persistChanges := true requestBody.SetPersistChanges(&persistChanges) createSession, err := graphClient.Drives().ByDriveId("drive-id").Items().ByDriveItemId("driveItem-id").Workbook().CreateSession().Post(context.Background(), requestBody, configuration)GraphServiceClient graphClient = GraphServiceClient.builder().authenticationProvider( authProvider ).buildClient(); LinkedList requestOptions = new LinkedList(); requestOptions.add(new HeaderOption("Prefer", "respond-async")); Boolean persistChanges = true; graphClient.me().drive().items("").workbook() .createSession(WorkbookCreateSessionParameterSet .newBuilder() .withPersistChanges(persistChanges) .build()) .buildRequest( requestOptions ) .post();const options = < authProvider, >; const client = Client.init(options); const workbookSessionInfo = < persistChanges: true >; await client.api('/me/drive/items//workbook/createSession') .post(workbookSessionInfo);setPersistChanges(true); $requestConfiguration = new CreateSessionRequestBuilderPostRequestConfiguration(); $headers = [ 'Prefer' => 'respond-async', ]; $requestConfiguration->headers = $headers; $result = $graphServiceClient->drives()->byDriveId('drive-id')->items()->byDriveItemId('driveItem-id')->workbook()->createSession()->post($requestBody, $requestConfiguration)->wait();graph_client = GraphServiceClient(credentials, scopes) request_body = CreateSessionPostRequestBody( persist_changes = True, ) request_configuration = CreateSessionRequestBuilder.CreateSessionRequestBuilderPostRequestConfiguration() request_configuration.headers.add("Prefer", "respond-async") result = await graph_client.drives.by_drive_id('drive-id').items.by_drive_item_id('driveItem-id').workbook.create_session.post(request_body, request_configuration = request_configuration)Отклик
Шаблон длительных операций возвращает ответ, аналогичный 202 Accepted приведенному ниже.
HTTP/1.1 202 Accepted Location: https://graph.microsoft.com/v1.0/me/drive/items//workbook/operations/ Content-type: application/json
В некоторых случаях, если создание завершается успешно в течение нескольких секунд, оно не будет входить в шаблон длительной операции. Вместо этого он возвращается в виде обычного сеанса создания, и успешный запрос вернет 201 Created ответ.
HTTP/1.1 201 Created Content-type: application/json
В следующем примере показан ответ при сбое запроса.
Примечание. Объект отклика, показанный здесь, может быть сокращен для удобочитаемости.
HTTP/1.1 500 Internal Server Error Content-type: application/json < "error":< "code": "internalServerError", "message": "An internal server error occurred while processing the request.", "innerError": < "code": "internalServerErrorUncategorized", "message": "An unspecified error has occurred.", "innerError": < "code": "GenericFileOpenError", "message": "The workbook cannot be opened." >> > >Опрос состояния длительного сеанса создания
С помощью шаблона длительных операций можно получить состояние создания в указанном расположении с помощью следующего запроса. Рекомендуемый интервал для опроса состояния составляет около 30 секунд. Максимальный интервал должен быть не более 4 минут.
Запрос
GET https://graph.microsoft.com/v1.0/me/drive/items//workbook/operations/
Отклик
Ниже приведен ответ, если операция имеет состояние running .
HTTP/1.1 200 OK Content-type: application/json < "id": , "status": "running" >Ниже приведен ответ, если состояние операции — succeeded .
HTTP/1.1 200 OK Content-type: application/json < "id": , "status": "succeeded", "resourceLocation": "https://graph.microsoft.com/v1.0/me/drive/items//workbook/sessionInfoResource(key='') >Ниже приведен ответ, если состояние операции — failed .
HTTP/1.1 200 OK Content-type: application/json < "id": , "status": "failed", "error": < "code": "internalServerError", "message": "An internal server error occurred while processing the request.", "innerError": < "code": ""internalServerErrorUncategorized", "message": "An unspecified error has occurred.", "innerError": < "code": "GenericFileOpenError", "message": "The workbook cannot be opened." >> > >Дополнительные сведения об ошибках см. в разделе Коды ошибок и сообщения.
Получение сведений о сеансе
Запрос
С состоянием succeeded можно получить сведения о созданном сеансе с resourceLocation помощью запроса, аналогичного приведенному ниже.
GET https://graph.microsoft.com/v1.0/me/drive/items//workbook/sessionInfoResource(key='')
Отклик
Ниже приведен отклик.
HTTP/1.1 200 OK Content-type: application/json
Получение сведений о сеансе зависит от первоначального запроса. Вам не нужно получать результат, если исходный запрос не возвращает текст ответа.
Уменьшение ошибок регулирования
API Excel в Microsoft Graph влияют на использование ресурсов нескольких служб зависимостей. Влияние может отличаться в разных запросах: например, можно ожидать, что обновление короткой строки в одной ячейке небольшой книги будет потреблять меньше ресурсов, чем добавление большой таблицы со сложными формулами в большую книгу.
Даже при использовании одного и того же API параметры и целевые книги могут привести к значительным различиям. Поэтому регулирование API Excel не определяется с простыми и универсальными номерами ограничений, так как они приводят к более строгим ограничениям. Приведенные ниже рекомендации помогут быстрее выполнять задачи с меньшим количеством ошибок регулирования.
заголовок Retry-After
Во многих случаях ответ регулирования включает заголовок Retry-After . Соблюдение значения заголовка и задержка аналогичных запросов помогут клиенту восстановиться после регулирования. Дополнительные сведения об обработке ответов на ошибки из API Excel в Microsoft Graph см. в статье Обработка ошибок для API Excel в Microsoft Graph.
Регулирование и параллелизм
Другим фактором, связанным с регулированием, является параллелизм запросов. Не рекомендуется увеличивать параллелизм при использовании API Excel (например, при параллелизации запросов к одной книге), особенно для запросов на запись. Вместо этого, если нет конкретных проблем, таких как значительные сетевые издержки по сравнению с очень коротким временем выполнения запроса, рекомендуется последовательное использование в наиболее распространенном случае: для каждой книги отправляется только следующий запрос после успешного получения ответа на текущий запрос.
Одновременные запросы на запись в одну книгу обычно не выполняются параллельно (хотя в некоторых случаях они выполняются); скорее, они часто являются причиной регулирования, истечения времени ожидания (когда запросы помещаются в очередь на серверах), конфликт слияния (при задействовании параллельных сеансов) и других типов сбоев. Они также усложняют обработку ошибок; Например, при получении ответа о сбое невозможно подтвердить состояние других ожидающих запросов, что затрудняет определение или восстановление состояния книги.
См. также