Precedentemente ho mostrato un esempio su come usare l'API Rest di
SharePoint Online per effettuare delle chiamate in
batch con
Power Automate.
La stessa cosa è fattibile anche con
SharePoint 2016 o
SharePoint 2019 on-premises con
JavaScript usato nella pagina
SharePoint.
Scrittura
Ad esempio per
inserire nuovi item si può usare, ed inviare, un body come questo in
POST--batch_c02f1b8d-deb1-486b-87db-d8ff6c7190cb
Content-Type: multipart/mixed;boundary=changeset_6d3d8d17-488d-418e-a3a5-a8e4510d41ad
Content-Lenght: 570
Content-Transfer-Encoding: binary
--changeset_6d3d8d17-488d-418e-a3a5-a8e4510d41ad
Content-Type: application/http
Content-Transfer-Encoding: binary
POST /_api/web/lists/getbytitle('listName')/items HTTP/1.1
Content-Type: application/json;odata=nometadata
{"Title":"Batch 1"}
--changeset_6d3d8d17-488d-418e-a3a5-a8e4510d41ad
Content-Type: application/http
Content-Transfer-Encoding: binary
POST /_api/web/lists/getbytitle('listName')/items HTTP/1.1
Content-Type: application/json;odata=nometadata
{"Title":"Batch 2"}
--changeset_6d3d8d17-488d-418e-a3a5-a8e4510d41ad--
--batch_c02f1b8d-deb1-486b-87db-d8ff6c7190cb--
Notare i tag --changeset_YYY usati come separatore tra le due insert o più in generale tra due o più update.
Mentre la chiusura è fatta tramite gli stessi tag seguiti da un doppio meno (--changeset_YYY-- e --batch_XXX--)
Rispetto all'esempio
precedente, voglio evidenziare che le
url possono essere anche relative ( /_api/web/lists/getbytitle('listName')/items) oltre che assolute.
La chiamata
JavaScript è simile a questa
$.ajax({
type: "POST", // sempre solo in POST
url: "/_api/$batch", // url delle chiamata batch
data: dataBatch, // corpo della chiamata
contentType: "multipart/mixed;boundary=batch_c02f1b8d-deb1-486b-87db-d8ff6c7190cb",
headers: {
"accept": "application/json;odata=nometadata", // nometadata in alternativa a verbose, per non passare anche il tipo dell'item
"X-RequestDigest": $("#__REQUESTDIGEST").val(), // digest necessario per i POST
},
cache: false,
success: function (result) {
console.log("Result", result);
},
error: function (xhr, status) {
console.log("error", xhr, status);
}
});
Da notare che la url della API è
relativa (/_api/$batch) in quanto questo esempio funziona solo all'interno di una pagina
SharePoint.
il
Content-Type della chiamata deve essere di tipo
multipart/mixed;boundary.
Per semplicità di esposizione l'esempio usa
JQuery per fare le chiamate
AJAX.
La variabile
dataBatch andrà valorizzata in questo modo
let dataChangesets = `
--changeset_6d3d8d17-488d-418e-a3a5-a8e4510d41ad
Content-Type: application/http
Content-Transfer-Encoding: binary
POST /_api/web/lists/getbytitle('listName')/items HTTP/1.1
Content-Type: application/json;odata=nometadata
{"Title":"Batch 1"}
--changeset_6d3d8d17-488d-418e-a3a5-a8e4510d41ad
Content-Type: application/http
Content-Transfer-Encoding: binary
POST /_api/web/lists/getbytitle('listName')/items HTTP/1.1
Content-Type: application/json;odata=nometadata
{"Title":"Batch 2"}
`;
let dataBatch = `--batch_c02f1b8d-deb1-486b-87db-d8ff6c7190cb
Content-Type: multipart/mixed;boundary=changeset_6d3d8d17-488d-418e-a3a5-a8e4510d41ad
Content-Lenght: ${dataChangesets.length}
Content-Transfer-Encoding: binary
${dataChangesets}
--changeset_6d3d8d17-488d-418e-a3a5-a8e4510d41ad--
--batch_c02f1b8d-deb1-486b-87db-d8ff6c7190cb--
`;
La proprietà nell'header Content-Lenght viene calcolata tramite la variabile ${dataChangesets.length}.
Per un esempio di risposta vedi l'esempio in
Creare item SharePoint in Batch con Power Automate.
Lettura
La stessa API REST (/_api/$batch) può essere usata anche per fare
più letture in contemporanea (batch) su una lista
SharePoint.
In questo caso il corpo della richiesta HTTP in
POST cambia
--batch_c02f1b8d-deb1-486b-87db-d8ff6c7190cb
Content-Type: application/http
Content-Transfer-Encoding: binary
GET /_api/web/lists/getbytitle('CalendarioCorsiFormazione_TipoCorso')/items(35) HTTP/1.1
Accept: application/json;odata=nometadata
--batch_c02f1b8d-deb1-486b-87db-d8ff6c7190cb
Content-Type: application/http
Content-Transfer-Encoding: binary
GET /_api/web/lists/getbytitle('CalendarioCorsiFormazione_TipoCorso')/items(13) HTTP/1.1
Accept: application/json;odata=nometadata
--batch_c02f1b8d-deb1-486b-87db-d8ff6c7190cb--
La prima cosa da evidenziare è che non va usato il separatore per i changesets.
Le varie chiamate in GET vanno divise con il separatore ---batch_XXX.
Anche se facciamo delle letture in GET, la chiamata principale (/_api/$batch) è sempre in POST.
A questo punto è semplice valorizzare la variabile
dataBatchlet dataBatch= `--batch_c02f1b8d-deb1-486b-87db-d8ff6c7190cb
Content-Type: application/http
Content-Transfer-Encoding: binary
GET /_api/web/lists/getbytitle('CalendarioCorsiFormazione_TipoCorso')/items(35) HTTP/1.1
Accept: application/json;odata=nometadata
--batch_c02f1b8d-deb1-486b-87db-d8ff6c7190cb
Content-Type: application/http
Content-Transfer-Encoding: binary
GET /_api/web/lists/getbytitle('CalendarioCorsiFormazione_TipoCorso')/items(13) HTTP/1.1
Accept: application/json;odata=nometadata
--batch_c02f1b8d-deb1-486b-87db-d8ff6c7190cb--
`;
mentre la chiamata
HTTP in
JavaScript non cambia, è identica alla precedente.
Variante
Per semplicità si può semplificare la costruzione del body tramite un ciclo
forEach.
Se tutte le letture sono sulla stessa lista si possono creare queste variabili
let listName = "MiaLista";
let itemsIds = [35, 12];
// template singola chiamata, esempio di lettura in GET
// con dei placeholder nella forma @nomeTag@
let template = `--batch_c02f1b8d-deb1-486b-87db-d8ff6c7190cb
Content-Type: application/http
Content-Transfer-Encoding: binary
GET /_api/web/lists/getbytitle('@listName@')/items(@id@) HTTP/1.1
Accept: application/json;odata=nometadata
`;
e costruire la stringa del body
var dataBatch = "";
itemsIds.forEach(id => dataBatch += template.replace("@listName@", listName).replace("@id@", id));
dataBatch += "--batch_c02f1b8d-deb1-486b-87db-d8ff6c7190cb--\r\n";
da come risultato
--batch_c02f1b8d-deb1-486b-87db-d8ff6c7190cb
Content-Type: application/http
Content-Transfer-Encoding: binary
GET /_api/web/lists/getbytitle('MiaLista')/items(35) HTTP/1.1
Accept: application/json;odata=nometadata
--batch_c02f1b8d-deb1-486b-87db-d8ff6c7190cb
Content-Type: application/http
Content-Transfer-Encoding: binary
GET /_api/web/lists/getbytitle('MiaLista')/items(12) HTTP/1.1
Accept: application/json;odata=nometadata
--batch_c02f1b8d-deb1-486b-87db-d8ff6c7190cb--
Se invece le letture degli item
sono su più liste, si può fare un
array di oggettilet items = [
{listName: "Lista 1", id: 35},
{listName: "Lista 2", id:12}
];
il codice si modifica l'eggermente
var dataBatch = "";
items.forEach(item => dataBatch += template.replace("@listName@", item.listName).replace("@id@", item.id));
dataBatch += "--batch_c02f1b8d-deb1-486b-87db-d8ff6c7190cb--\r\n";
risultato
--batch_c02f1b8d-deb1-486b-87db-d8ff6c7190cb
Content-Type: application/http
Content-Transfer-Encoding: binary
GET /_api/web/lists/getbytitle('Lista 1')/items(35) HTTP/1.1
Accept: application/json;odata=nometadata
--batch_c02f1b8d-deb1-486b-87db-d8ff6c7190cb
Content-Type: application/http
Content-Transfer-Encoding: binary
GET /_api/web/lists/getbytitle('Lista 2')/items(12) HTTP/1.1
Accept: application/json;odata=nometadata
--batch_c02f1b8d-deb1-486b-87db-d8ff6c7190cb--