Usare le API di Search con lo SharePoint Framework (SPFx)
Le API di search di SharePoint Online, rispondono alla url {sitecollection}/_api/search/query ed è possibile interrogarle sia in GET, passando i parametri in querystring, oppure in POST passando un oggetto json nel body.
Ad esempio per cercare la parola "sharepoint" con il metodo GET, la url diventa:
L'esempio seguente, per SharePoint Framework (SPFx), utilizza il metodo GET per farsi ritornare tutte le site collection (parametro "Path:" e "contentclass:STS_Site") la cui url inizia con startingUrl;
Questo è lo stesso esempio ma con il metodo POST (/_api/search/postquery), utile nel caso in cui i parametri di ricerca superano la lunghezza massima della url:
Per eseguire l'esempio è necessario costruire una classe come questa:
da richiamare nella web part con:
Vedi anche è Keyword queries and search conditions for Content Search e Keyword Query Language (KQL) syntax reference
Ad esempio per cercare la parola "sharepoint" con il metodo GET, la url diventa:
Text
https://sharepoint.local/search/_api/search/query?querytext='sharepoint'
Ho aggiunto nel path della url la site collection /search/, in questo modo anche chi non ha accesso alla site collection di root può interrogare il search per cercare sulle altre site collection a cui ha accesso.
L'esempio seguente, per SharePoint Framework (SPFx), utilizza il metodo GET per farsi ritornare tutte le site collection (parametro "Path:" e "contentclass:STS_Site") la cui url inizia con startingUrl;
TypeScript
public getSitesStartingWith(startingUrl: string): Promise<ILinkItem[]> {
const url = `/search/_api/search/query?querytext='Path:${startingUrl}* AND contentclass:STS_Site'&selectproperties='Title,Path'&trimduplicates=false&rowLimit=500`;
const items: ILinkItem[] = [];
return this._spHttpClient.get(url, SPHttpClient.configurations.v1)
.then((response: SPHttpClientResponse) => {
return response.json().then((data) => {
if (data["odata.error"]) {
//se ho degli errori ritorno l'array vuoto
Log.error(Constants.LOG_SOURCE, new Error(data["odata.error"].message.value));
return items;
}
const rows = data.PrimaryQueryResult.RelevantResults.Table.Rows;
rows.forEach(c => {
const objTitle = c.Cells.filter((cell) => { return cell.Key == "Title"; })[0];
const objUrl = c.Cells.filter((cell) => { return cell.Key == "Path"; })[0];
// ritorno solo il titolo e la url
items.push({
title: objTitle.Value,
url: objUrl.Value
});
});
//custom sort: &sortlist='Title:ascending' -> non funziona da errore
items.sort((a, b) => {
if (a.title < b.title)
return -1;
if (a.title > b.title)
return 1;
return 0;
});
return items;
});
});
}
L'esempio è limitato a 500 items ritornati, se il numero degli elementi ritornati è superiore a 500 sarà necessario eseguire più query paginando i dati.
Per eseguire l'ordinamento è disponibile anche il parametro sortlist, ma non sono riuscito a farlo funzionare sul campo Title, dava sempre errore.
Visto che nel mio caso i dati ritornati erano sicuramente minori di 500 ho utilizzato il metodo sort degli array
Visto che nel mio caso i dati ritornati erano sicuramente minori di 500 ho utilizzato il metodo sort degli array
Questo è lo stesso esempio ma con il metodo POST (/_api/search/postquery), utile nel caso in cui i parametri di ricerca superano la lunghezza massima della url:
TypeScript
public postSitesStartingWith(startingUrl: string, siteUrls: string[] | null): Promise<ILinkItem[]> {
const url = '/search/_api/search/postquery';
const items: ILinkItem[] = [];
let queryText = `Path:${startingUrl}* AND contentclass:STS_Site`;
const requestBody = {
'request': {
'__metadata': { 'type': 'Microsoft.Office.Server.Search.REST.SearchRequest' },
'Querytext': queryText,
'RowLimit': 500,
'SelectProperties': {
'results': ['Title', 'Path']
},
'TrimDuplicates': 'false',
'ProcessPersonalFavorites': 'false',
//'EnableSorting' : 'false',
//'SortList': { 'results': [{ 'Property': 'Title', 'Direction': '0' }] } // da errore
}
};
const options: ISPHttpClientOptions = {
headers: { "odata-version": "3.0" }, //senza questo da errore: "Unknown Error"
body: JSON.stringify(requestBody)
};
return this._spHttpClient.post(url, SPHttpClient.configurations.v1, options)
.then((response: SPHttpClientResponse) => {
return response.json().then((data) => {
if (data["odata.error"]) {
Log.error(Constants.LOG_SOURCE, new Error(data["odata.error"].message.value));
return items;
}
const rows = data.PrimaryQueryResult.RelevantResults.Table.Rows;
rows.forEach(c => {
const objTitle = c.Cells.filter((cell) => { return cell.Key == "Title"; })[0];
const objUrl = c.Cells.filter((cell) => { return cell.Key == "Path"; })[0];
items.push({
title: objTitle.Value,
url: objUrl.Value
});
});
//custom sort: &sortlist='Title:ascending' -> non funziona da errore
items.sort((a, b) => {
if (a.title < b.title)
return -1;
if (a.title > b.title)
return 1;
return 0;
});
return items;
});
});
}
Per eseguire l'esempio è necessario costruire una classe come questa:
TypeScript
import { Log } from '@microsoft/sp-core-library';
import { SPHttpClient, SPHttpClientResponse, ISPHttpClientOptions } from '@microsoft/sp-http';
import { WebPartContext } from '@microsoft/sp-webpart-base';
export interface ILinkItem {
title: string;
url: string;
}
export default class SPDataService {
private _spHttpClient: SPHttpClient;
private _webAbsoluteUrl: string;
constructor(private context: WebPartContext) {
this._spHttpClient = context.spHttpClient;
this._webAbsoluteUrl = context.pageContext.web.absoluteUrl;
}
public getSitesStartingWith(startingUrl: string): Promise<ILinkItem[]> { ... }
public postSitesStartingWith(startingUrl: string): Promise<ILinkItem[]> { ... }
}
TypeScript
//private _dataService: IDataService;
...
this._dataService = DataService.get(this.context);
...
//cerco tutte le site collection che iniziano per "c"
this._dataService.postSitesStartingWith("http://sharepoint.local/sites/c")
.then((items) => { ... })
.catch((error) => { ... });
Vedi anche è Keyword queries and search conditions for Content Search e Keyword Query Language (KQL) syntax reference