Recently Microsoft released a new API endpoint for retrieving SharePoint listitem data. With this RenderListDataAsStream API you can now retrieve both managed metadata field values and lookup field values very easily.
I was using the SharePoint items REST API endpoint like this:
{SiteCollectionUrl}/_api/web/lists/GetByTitle('Documents')/Items?$select=Id,FileLeafRef,Title,ServerRedirectedEmbedUri,Editor/Title,MavProject/Title,MavCategory,TaxCatchAll/ID,TaxCatchAll/Term,Modified&$expand=Editor,MavProject,TaxCatchAll
While I was using this only for retrieving data from lists on the site collection root level, it seemed to work just fine. With the $expand I managed to get the Editor’s name, the Project title and the term label by using the special field TaxCatchAll. Until I got a phone call from a customer that he got some errors and was not seeing his documents with the metatdata anymore.
After some thorough testing, troubleshooting and debugging I could confirm it was not working indeed and that the problem was not getting any data from the TaxCatchAll field. I searched around on the net and hit the blog post by Elio Struyf Using the SharePoint RenderListDataAsStream API to fetch lookup and single managed metadata field values. Interesting!
I decided to refactor my code. Now, couple of things to bear in mind. First, the RenderListDataAsStream API is using a POST method, not a GET. So you cannot test it directly in the browser. Second, (afaik) you can only get the fields exposed by views. Since I also required the ServerRedirectedEmbedUri field, I had to solve that problem also. Third and last, the response is of a different structure. You might need to change some logic as well to map the values to your model.
C# snippet:
var filter = $@"<Query><Where><BeginsWith><FieldRef Name =""ContentTypeId"" /><Value Type =""ContentTypeId"">{Common.documentContentTypeId}</Value></BeginsWith></Where><OrderBy><FieldRef Name=""Created"" Ascending=""FALSE"" /></OrderBy></Query><RowLimit Paged=""FALSE"">5</RowLimit>"; var apiUrl = $"{url}/_api/web/lists/GetByTitle('{getDocumentsRequest.LibraryName}')/RenderListDataAsStream"; var camlQuery = $@"<View><ViewFields><FieldRef Name=""ID"" /><FieldRef Name=""Title"" /><FieldRef Name=""FileLeafRef"" /><FieldRef Name=""MavProject"" /><FieldRef Name=""MavCategory"" /><FieldRef Name=""Editor"" /><FieldRef Name=""Modified"" /></ViewFields>{filter}</View>"; var bodyRequest = JsonConvert.SerializeObject(new { parameters = new { RenderOptions = 2, ViewXml = camlQuery } }); var authenticationHeader = RestUtility.GetAuthenticationHeader(url); var requestHeader = new Dictionary<string, string> { { "Accept", "application/json;odata=nometadata" } }; var result = await RestUtility.ExecutePostQuery<JObject>(apiUrl, authenticationHeader, bodyRequest, requestHeader, HttpMethod.Post);
So, basically I define a (good old) CAML query and pass that into my body request. After the call the JSON result looks like this:
{{ "Row": [ { "ID": "3", "PermMask": "0x3008031061", "FSObjType": "0", "HTML_x0020_File_x0020_Type": "", "UniqueId": "{86F08A9E-21D1-4329-AB0A-4F4A44F22DBF}", "ProgId": "", "NoExecute": "0", "ContentTypeId": "0x0101007442F1819EDBDA4F86864C1AF568BEC60033987CB06F38A8428A68D8F82C9354B3", "FileRef": "/sites/octavie-test/Shared Documents/Microsoft Azure Infographic 2015 2.5.pdf", "FileRef.urlencode": "%2Fsites%2Foctavie%2Dtest%2FShared%20Documents%2FMicrosoft%20Azure%20Infographic%202015%202%2E5%2Epdf", "FileRef.urlencodeasurl": "/sites/octavie-test/Shared%20Documents/Microsoft%20Azure%20Infographic%202015%202.5.pdf", "FileRef.urlencoding": "/sites/octavie-test/Shared%20Documents/Microsoft%20Azure%20Infographic%202015%202.5.pdf", "ItemChildCount": "0", "FolderChildCount": "0", "SMTotalSize": "5142280", "File_x0020_Size": "1074629", "MediaServiceFastMetadata": "", "Title": "Azure Infografic", "FileLeafRef": "Microsoft Azure Infographic 2015 2.5.pdf", "FileLeafRef.Name": "Microsoft Azure Infographic 2015 2.5", "FileLeafRef.Suffix": "pdf", "MavProject": [ { "lookupId": 2, "lookupValue": "Project B", "isSecretFieldValue": false } ], "MavProject.": "2;#Project B", "MavCategory": { "__type": "TaxonomyFieldValue:#Microsoft.SharePoint.Taxonomy", "Label": "Azure", "TermID": "dcc41962-ba2c-4e1f-a38e-787a0c507052" }, "MavCategory.": "2;#Azure", "Editor": [ { "id": "11", "title": "Octavie van Haaften", "email": "octavie@domain.nl", "sip": "", "picture": "" } ], "Editor.id": "11", "Editor.title": "Octavie van Haaften", "Editor.span": "<remove-for-readability>", "Editor.email": "octavie@domain.nl", "Editor.sip": "", "Editor.jobTitle": "", "Editor.department": "", "Editor.picture": "https://domain-my.sharepoint.com:443/User%20Photos/Profilepictures/octavie_domain_nl_MThumb.jpg?t=63647737140", "Modified": "30-3-2018 08:57", "Modified.": "2018-03-30 08:57:17", "Created": "30-3-2018 08:56", "ContentVersion": "1", "_VirusStatus": "0", "ecb.dispex": "return DispEx(this,event,'TRUE','FALSE','','','1','','','','','11','0','','0x3008031061','','')" } ], "FirstRow": 1, "FolderPermissions": "0x3008031061", "LastRow": 1, "RowLimit": 5, "FilterLink": "?", "ForceNoHierarchy": "1", "HierarchyHasIndention": "" }}
You can now see that the data from both MavProject and MavCategory are directly available! Cool stuff!
More information about the RenderListDataAsStream API and what RenderOptions are available: