PortiBlog

Search REST API in SharePoint-hosted apps

10 juli 2015

Om data met behulp van de Search Rest API op te halen vanuit een SharePoint hosted app zijn er twee mogelijkheden:

  • Een request doen op het endpoint "/_api/search/query"
  • Een request doen op het endpoint "/_api/search/postquery"

Het grootste verschil tussen deze beide methoden is dat bij de eerste het request een Http-GET betreft, terwijl bij de tweede een Http-POST gedaan wordt.
In deze post geef ik van beide methoden een voorbeeld en laat ik zien wat de voor en nadelen zijn. Deze voorbeelden zijn gebaseerd op een SharePoint hosted app die buiten JQuery geen extra scripts bevat.

/_api/search/query

Zoals gezegd betreft het request een http-get. Zowel de query als eventuele extra parameters worden hierbij in de querystring meegegeven. Omdat er sprake is van een cross-domain call moet de SP.RequestExecutor gebruikt worden voor het uitvoeren van request. (Of er moet een OAuth access token met het request worden meegestuurd)

Om de SP.RequestExecutor te kunnen gebruiken moet het script "SP.RequestExecutor.js" uit de SharePoint-hive geladen worden. Dit gebeurt met de jQuery functie "getScript", waarbij een callback functie wordt meegegeven. Deze callback functie (getData) bevat de code die het request gaat uitvoeren.


var scriptbase = _spPageContextInfo.webAbsoluteUrl + "/_layouts/15/";
jQuery.getScript(scriptbase + "SP.RequestExecutor.js", getData);

In de callback handler wordt een SP.RequestExecutor geïnstantieerd, waarbij de URL van het hostweb wordt meegegeven. Daarna wordt de request-url opgebouwd, waarbij de zoekopdracht en eventuele extra parameters (in dit geval de selectproperties) in de querystring gespecificeerd worden. Merk op dat de selectproperties 'Latitude' en 'Longitude' custom managed properties zijn en dat alle managed properties die hier opgegeven worden 'Retrieveable' moeten zijn.

Vervolgens wordt met behulp van de functie 'executeAsync' het request naar de rest-service uitgevoerd. Aan de functie 'executeAsync' wordt een JSON object meegegeven met de data die benodigd is voor het opbouwen van het request. De parameters 'success' en 'error' specificeren de callback functies die het resultaat van de query verder afhandelen.


function getData() {
    var executor =
        new SP.RequestExecutor(_spPageContextInfo.webAbsoluteUrl);

    var queryText = "Airplane ContentType=Picture";
    var searchUrl = _spPageContextInfo.webAbsoluteUrl
                    + "/_api/search/query?querytext='"
                    + queryText
                    + "'&selectproperties='Title,Latitude,Longitude'";

    executor.executeAsync({
        url: searchUrl,
        method: "GET",
        dataType: "json",
        headers: {
            Accept: "application/json;odata=verbose"
        },
        success: handleQueryResult,
        error: handleError
    });
}

De onderstaande code bevat de callback functies voor het afhandelen van een geslaagd of gefaald request. Wanneer een request slaagt wordt "handleQueryResult". De data van de Http response wordt als parameter meegegeven aan deze functie. De responde body bevat de zoekresultaten, in de vorm van een JSON string. Met behulp van JSON.parse wordt op basis van deze string een JSON object gemaakt. Dit JSON object bevat alle zoekresultaten.

Omdat de zoekresultaten in een dynamisch opgebouwde tabel zitten; dat wil zeggen dat er niet per item een JSON object met properties voorhanden is; is het lastig om de juiste data uit het object te halen, zeker wanneer men gebruik maakt van databinding. Om deze reden is het handig om de zoekresultaten om te zetten naar een array van JSON objecten die per item de verschillende properties met de bijbehorende waarden bevatten. Dit gebeurt met de functie 'convertToArray' waarvan de code onderaan deze post staat.

Tot slot wordt een popup box getoond die een aantal properties uit het eerste item van het zoekresultaat bevat.


function handleQueryResult(response)
{
    var responseData = JSON.parse(response.body);
    var result =
        convertToArray(responseData.d.query.PrimaryQueryResult
                       .RelevantResults.Table);
    if(result.length != 0)
    {
        alert('query result: ' + result[0].Title +
              '\nLatitude: ' + result[0].Latitude +
              '\nLongitude: ' + result[0].Longitude);
    }
}

function handleError(response, errorCode, errorMessage) {
    alert('Something went wrong');
}

/_api/search/postquery

Bij het gebruik van "postquery" wordt een request met een http-post gedaan. Het belangrijkste verschil ten opzichte van de eerste methode is dat de zoekopdracht en eventuele extra parameters in de body van het http-request worden meegestuurd. Vooral wanneer er een uitgebreide zoekopdracht met veel aanvullende parameters moet worden gedaan, heeft deze methode als voordeel dat er geen eindeloos lange (en onoverzichtelijke) querystring hoeft te worden opgebouwd. In plaats daarvan wordt alle data in een JSON object gestopt. Een bijkomend voordeel van de http-post is dat er geen rekening gehouden hoeft te worden met het feit dat er een cross-domain call gedaan wordt.

In de onderstaande code wordt een JSON object aangemaakt die zoekopdracht bevat. De feitelijke zoekopdracht bestaat uit de waarde van property 'QueryTemplate', waarbij '{searchterms}' vervangen wordt door de waarde van de property 'Querytext'.


var postData = {
    'request': {
        '__metadata': { 'type': 'Microsoft.Office.Server.Search.REST.SearchRequest' },
        'Querytext': 'Airplane',
        'QueryTemplate': '{searchterms} ContentType=Picture',
        'SelectProperties': {
            'results': ['Title', 'Latitude', 'Longitude',
                        'PublishingImage', 'PictureURL',
                        'PictureThumbnailURL', 'Path']
        }
    }
};

Vervolgens wordt met behulp van jQuery het request naar de rest service uitgevoerd. Ook hier wordt de data waarmee het request wordt opgebouwd meegegeven in de vorm van een JSON object. Het hierboven gespecificeerde JSON-object met de zoekopdracht wordt omgezet in een string en in het request gestopt. Omdat het request een http-post betreft, moet het 'RequestDigest' of 'FormDigest' als http-header worden meegestuurd. Het RequestDigest wordt met jQuery uit de pagina opgehaald. Eveneens is een callback functie gepecificeerd om een geslaagde aanroep verder af te handelen.


var queryUrl = _spPageContextInfo.webAbsoluteUrl
               + "/_api/search/postquery";

jQuery.ajax({
    data: JSON.stringify(postData),
    contentType: "application/json",
    url: queryUrl,
    type: "POST",
    dataType: "json",
    headers: {
        "accept": "application/json;odata=verbose",
        "content-type": "application/json;odata=verbose",
        "X-RequestDigest": jQuery("#__REQUESTDIGEST").val()
    },
    success: handlePostQueryResult
});

De callback functie lijkt sterk op die van de eerste variant. Echter is de opbouw van het response object anders en kan het zoekresultaat direct uit het response gehaald worden.


function handlePostQueryResult(response) {
    var result = convertToArray(response.d.postquery.PrimaryQueryResult
                                .RelevantResults.Table);
    if (result.length != 0) {
        alert('postquery result: ' + result[0].Title + '\n' +
              'Latitude: ' + result[0].Latitude + '\n' +
              'Longitude: ' + result[0].Longitude);
    }
}

In deze post heb ik laten zien hoe met behulp van de Search REST API een zoekopdracht kan worden gedaan en hoe het zoekresultaat eenvoudig gebruikt kan worden. Voor een overzicht van de vele mogelijkheden die de API biedt om de zoekopdracht te 'fine tunen' verwijs ik naar de MSDN pagina: SharePoint Search REST API overview.

Hieronder staat de functie die gebruikt wordt om de tabel met zoekresultaten in een array met objecten om te zetten.


function convertToArray(table) {
    var result = [];

    jQuery.each(table.Rows.results, function (index, row) {
        var item = {};
        jQuery.each(row.Cells.results, function (index, cell) {
            item[cell.Key] = cell.Value;
        });
        result.push(item);
    })

    return result;
}

 

Submit a comment

Dit vind je vast ook interessant.