Sharepoint Rest API - Apply filter on expanded fields - Status 400 - rest

I am using Sharepoint rest API to get specific files in a group of folders. For this, I am applying filter on the expanded field. The problem is when I apply filter, it says the "Field or property does not exist"
I've tried to get the data without applying filter and it's coming correctly. Also, I am able to apply filter on the fields which are not under the expand parameter.
Below code is working in postman:
https://sp.foo.net/sites/spdsdfrn/_api/web/GetFolderByServerRelativeUrl('Shared Documents/abc/2019')/Folders?$expand=Files&$select=Files/Name&$filter=Files/Name eq 'abc.xlsx'
Below is the relevant part of the output:
{
"d": {
"results": [
{
"__metadata": {
"id": "https://sp.foo.net/sites/spdsdfrn/_api/web/GetFolderByServerRelativeUrl('Shared Documents/abc/2019/folder1')",
"uri": "https://sp.foo.net/sites/spdsdfrn/_api/web/GetFolderByServerRelativeUrl('Shared Documents/abc/2019/folder1')",
"type": "SP.Folder"
},
"Files": {
"results": [
{
"__metadata": {
"id": "https://sp.foo.net/sites/spdsdfrn/_api/web/GetFolderByServerRelativeUrl('Shared Documents/abc/2019/folder1/abc.xlsx')",
"uri": "https://sp.foo.net/sites/spdsdfrn/_api/web/GetFolderByServerRelativeUrl('Shared Documents/abc/2019/folder1/abc.xlsx')",
"type": "SP.File"
},
"Name": "abc.xlsx"
},
{
"__metadata": {
"id": "https://sp.foo.net/sites/spdsdfrn/_api/web/GetFolderByServerRelativeUrl('Shared Documents/abc/2019/folder1/def.xlsx')",
"uri": "https://sp.foo.net/sites/spdsdfrn/_api/web/GetFolderByServerRelativeUrl('Shared Documents/abc/2019/folder1/def.xlsx')",
"type": "SP.File"
},
"Name": "def.xlsx"
}
]
}
},
.........
.........
..........
Below code is not working in postman:
https://sp.foo.net/sites/spdsdfrn/_api/web/GetFolderByServerRelativeUrl('Shared Documents/abc/2019')/Folders?$expand=Files&$select=Files/Name&$filter=Files/Name eq 'abc.xlsx'
Below is the error output I am getting with status code 400 (bad request):
{
"error": {
"code": "-1, Microsoft.SharePoint.Client.InvalidClientQueryException",
"message": {
"lang": "en-US",
"value": "Field or property \"Name\" does not exist."
}
}
}
I've seen many solutions on the internet and they suggest that it should work in this way. Also, I've seen to check the internal names as they might differ but it's same "Name" in this case.
Is it some bug or I am missing something?

This looks like a typo:
"Field or property \"Names\" does not exist."
As your URL references "Name" not "Names".
Your second URL does not have the file type (.xlsx)
&$filter=Files/Name eq 'abc'
Otherwise...
Your URL includes "/folder". This returns a list of folders. Are you looking for a file in a particular folder, or all files by that name in any folder?
This will return a file in a particular folder:
https://sp.foo.net/sites/spdsdfrn/_api/web/GetFolderByServerRelativeUrl('Shared Documents/abc/2019')/files?$select=Name&$filter=Name eq 'abc.xlsx'
Technically speaking... It's a "server relative", not "site relative" URL. But starting with the library name seems to work.
https://sp.foo.net/sites/spdsdfrn/_api/web/GetFolderByServerRelativeUrl('Shared Documents/abc/2019')/Folders
probably should be:
https://sp.foo.net/sites/spdsdfrn/_api/web/GetFolderByServerRelativeUrl('/sites/spdsdfrn/Shared Documents/abc/2019')/Folders

You can use GetItems method in combination with setting FolderServerRelativeUrl property and Scope.
Example code:
<script src="https://code.jquery.com/jquery-1.12.4.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
var fileName="abc.xlsx";
var libraryTitle="Documents";
var folderRelativeUrl="Shared Documents/abc/2019";
var viewXml = "<View Scope='RecursiveAll'><Query><Where><Eq><FieldRef Name='FileLeafRef'/><Value Type='File'>"+fileName+"</Value></Eq></Where></Query></View>";
var url = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('"+libraryTitle+"')/getitems?$select=*,FileDirRef,FileRef";
var query = {
'query' : {
'__metadata': { 'type': 'SP.CamlQuery' },
'ViewXml' : viewXml,
'FolderServerRelativeUrl': folderRelativeUrl
}
};
$.ajax({
url: url,
method: "POST",
data: JSON.stringify(query),
headers: {
"X-RequestDigest": $("#__REQUESTDIGEST").val(),
"Accept": "application/json; odata=verbose",
"content-type": "application/json; odata=verbose"
},
success: function (data) {
alert(JSON.stringify(data.d.results));
},
error: function (err) {
alert(JSON.stringify(err));
}
});
});
</script>
Or we can use the REST API below.
/_api/web/lists/getbytitle('Documents')/items?$select=File&$expand=File&$filter=FileLeafRef eq 'abc.xlsx'

Related

How to create multiple entities using a single OData POST to a Business Central Web Service?

I tried to POST an array of objects and, as expected, it isn't that easy. In my case I want to insert multiple Transfer Order Lines in the same request.
// Request Body
[
{
"documentNo": "1002",
"itemNo": "1968-S",
"quantity": 3
},
{
"documentNo": "1002",
"itemNo": "1968-S",
"quantity": 113
}
]
// Response
{
"error": {
"code": "BadRequest",
"message": "Invalid Request Body CorrelationId: a2606676-3f8f-4753-aaee-be91a621f070."
}
}
Is it possible to do what I want without sending a request for every Line entity I want to add?
You need to create a structure like this:
url: api/2.0/$batch
Body:
```lang-json
{
"requests":
[
{
"method": "POST",
"id":"R1",
"url": "companies(id)/APIEntitySetName",
"headers":
{
"content-Type": "application/json"
},
"body":
{}
},
{
another line
}
]
}
```

Implement different response with WireMock when no request(s) match

I'm trying to stub a RESTful API. One of the resources return the details when the resource is (indeed) found, or an HTTP 404 (Not Found) when, eventually, there is no resource for the given URL.
This is my simplified stub/mapping:
{
"mappings": [
{
"name": "Retrieve Items",
"request": {
"headers": {
"accept": {
"caseInsensitive": true,
"equalTo": "application/json"
}
},
"method": "GET",
"urlPathPattern": "/api/items/[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}"
},
"response": {
"bodyFileName": "items-api/responses/retrieve/{{ request.pathSegments.[2] }}.json",
"headers": {
"content-type": "application/json"
},
"status": 200
}
}
]
}
Then I have several JSON files (in /home/wiremock/__files/items-api/responses/retrieve/ to match the requests against — but I can't find a way to implement the HTTP 404 (Not Found) scenario:
{
"timestamp": {{ now }},
"status": 404,
"error": "Not Found",
"message": null,
"path": "{{ request.path }}"
}
With this config I get back (the expected, but not useful for my use case) response from WireMock that the file name uuid-sent-in-request.json is not found.
Is there a way to implement this behavior currently?
Tom's answer will work as well. I think the benefits to his solution are that they aren't tied to specific request URLs, but my suggestion is to have a specific mapping for the files that will match with their specific JSON files, and a catch-all mapping for un-matched files. By assigning the requests with JSON responses a higher priority, WireMock will check those first, and if the request does not match any of the values specified in that mapping, will then go on to check if the second mapping matches, and return a 404.
{
"mappings": [
{
"name": "Retrieve Items - Success",
"priority": 1, // arbitrary number lower than the second priority
"request": {
"headers": {
"accept": {
"caseInsensitive": true,
"equalTo": "application/json"
}
},
"method": "GET",
"urlPathPattern": "/api/items/(UUID1|UUID2|UUID3|UUID4)"
},
"response": {
"bodyFileName": "items-api/responses/retrieve/{{ request.pathSegments.[2] }}.json",
"headers": {
"content-type": "application/json"
},
"status": 200
}
},
{
"name": "Retrieve Items - 404 Not Found",
"priority": 5, // arbitrary number that is higher than 1
"request": {
"headers": {
"accept": {
"caseInsensitive": true,
"equalTo": "application/json"
}
},
"method": "GET",
"urlPathPattern": "/api/items/[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}"
},
"response": {
"status": 404
}
}
]
}
Currently you would need to write a ResponseDefinitionTransformer to get the behaviour you're looking for.
It would need to check whether the ResponseDefinition passed in the parameter required a file, then if so check whether the file exists by doing something like:
try {
fileSource.getBinaryFileNamed(bodyFileName).readContents();
} catch (FileNotFoundException e) {
return WireMock.notFound().withBody("custom body");
}
// Otherwise return the unmodified response definition

Wiremock verify - How to match the request with time parameter

I have time (messageId) parameter in my request. When i try to wiremock its not matching as expected. Please let me know how can we match like these scenarios
EX:
messageId = current date and time in millisec
com.github.tomakehurst.wiremock.client.VerificationException: No requests exactly matched. Most similar request was: expected:<
POST
/xxx/v2/yyy?apikey=test_key&messageId=1614515075245&calculatePromotions=false&origin=yy&siteCode=123&workstationId=0
but was:<
POST
/xxx/v2/yyy?apikey=test_key&messageId=1614515078010&calculatePromotions=false&origin=yy&siteCode=123&workstationId=0
You can match using regex on query parameters, which should solve your issue.
{
"request": {
"urlPath": "/xxx/v2/yyy",
"method": "POST",
"queryParameters": {
"api_key": {
"equalTo": "test_key"
},
"messageId": {
"matches": ".*"
},
"calculatePromotions": {
"equalTo": false
},
"origin": {
"equalTo": "yy"
},
"siteCode": {
"equalTo": 123
},
"workstationId": {
"equalTo": 0
}
}
},
"response": {
"status": 200
}
}

Wiremock Capture path param and return in the response body

I am trying to create dynamic mocks using WireMock. I have a situation where if I specify URL like :
http://localhost:8089/api/account/abc#abc.com
then I should receive response like:
{
"account" : "abc#abc.com"
}
In brief, the path param is returned in the response body. I am able to make the request URL generic by using urlPathPattern set to /api/account/([a-z]*) however, I am not sure how should I capture abc#abc.com and return this in the response using regular expressions.
In WireMock the regular expressions can be used to recognize the email format in the Request Matching. For the purpose of this example I used a very crude example. Your production implementation may require a more robust approach.
This request:
http://localhost:8181/api/account/someone#somewhere.net
Is matched by this rule:
{
"request": {
"method": "GET",
"urlPathPattern": "/api/account/([a-z]*#[a-z]*.[a-z]*)"
},
"response": {
"status": 200,
"jsonBody": {
"account": "{{request.path.[2]}}"
},
"transformers": ["response-template"],
"headers": {
"Content-Type": "application/json"
}
}
}
And returns this response:
{
"account": "someone#somewhere.net"
}
It makes use of a Response Template processing functionality in WireMock. The Request Model variables [{{request.path.[2]}}] can be used to obtain sections from the request.
The same can be done using WireMock.Net - Response-Templating
The rule looks like:
{
"Request": {
"Path": {
"Matchers": [
{
"Name": "RegexMatcher",
"Pattern": "^/api/account/([a-z]*#[a-z]*.[a-z]*)$"
}
]
},
"Methods": [
"get"
]
},
"Response": {
"StatusCode": 200,
"BodyAsJson": {
"account": "{{request.PathSegments.[2]}}"
},
"UseTransformer": true,
"Headers": {
"Content-Type": "application/json"
}
}
}

Add event to calendar on SharePoint through REST API

I'm trying to add a calendar event to a SharePoint Calendar through REST API but i can't seems to find the relevant resources to achieve this.
If i understand correctly, the calendar in SharePoint is a List of events object, as such I should be able to add the event via ListItem object?
Sorry if this sounds wrong as I'm not familiar with SharePoint structure.
Thanks
This is the example for OAuth token Authentication but REST part is anyway like this.
var dataObj = {
"Subject": "Birthday Party"
"Body": {
"ContentType": "Text",
"Content": "Birthday Party for Cathy",
},
"Start": {
"dateTime": "2016-07-03T09:00:00Z",
"timeZone": "Asia/Tokyo"
},
"End": {
"dateTime": "2016-07-04T11:00:00Z",
"timeZone": "Asia/Tokyo"
},
"Location": {
"DisplayName": "Conference Room 1"
},
"ShowAs": "Busy",
"Attendees": [
{
"EmailAddress": { "Name": "Alex Darrow", "Address": "darrow.alex#company.com" },
"Type": "Required"
}
]
};
var url = "https://graph.microsoft.com/v1.0/me/events/";
var data = JSON.stringify(dataObj);
$.ajax({
url: url,
type: "POST",
data: data,
beforeSend: function (XMLHttpRequest) {
XMLHttpRequest.setRequestHeader("Accept", "application/json;odata.metadata=full;odata.streaming=true");
XMLHttpRequest.setRequestHeader('Authorization', 'Bearer ' + accessToken);
XMLHttpRequest.setRequestHeader("content-type", "application/json;odata=verbose");
},
success: function (result, textStatus, jqXHR) {
//Success
},
error: function (data) {
//
}});