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

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
}
]
}
```

Related

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 standalone dynamic response array of objects is not working with bodyPatterns and matchesJsonPath

I am using wiremock to stubbing the requests. I have created a json file to get a response:
{
"request": {
"method": "POST",
"urlPath": "/nested/transform",
"bodyPatterns": [
{
"matchesJsonPath": "$.name.[0].first"
},
{
"matchesJsonPath": "$.name.[1].first"
}
]
},
"response": {
"status": 200,
"body": "{\"firstName\": \"$(name.[0].first)\", \"lastName\": \"$(name.[1].first)\"}",
"headers": {
"Content-Type": "application/json"
},
"transformers": ["body-transformer"]
}
}
My request and response are as below:
Request
{
"name": [
{
"first": "Vijay"
},
{
"first": "Sagar"
}
]
}
Here I receive very beard response and it is not parsed as I want.
Response which is not my expected result:
{
"firstName": "[{first=Vijay}, {first=Sagar}]",
"lastName": "[{first=Vijay}, {first=Sagar}]"
}
Expected result is: I'm willing to receive the following response based on above request and stubbed json:
{"firstName": "Vijay","lastName": "Sagar"}
How can I get the expected result as I tried a lot but was unable to match response parameters?
When working with a JSON response, I prefer to use the bodyFileName as this that escaping isn't necessary.
__files/nested_json_template.json
{
"firstName": "{{jsonPath request.body '$.name.[0].first'}}",
"lastName": "{{jsonPath request.body '$.name.[1].first'}}"
}
mappings/nested_json_mapping.json
{
"request": {
"method": "POST",
"urlPath": "/nested/transform",
"bodyPatterns": [
{
"matchesJsonPath": "$.name.[0].first"
},
{
"matchesJsonPath": "$.name.[1].first"
}
]
},
"response": {
"status": 200,
"bodyFileName": "nested_json.json",
"headers": {
"Content-Type": "application/json"
},
"transformers": ["response-template"]
}
}

Mapping by request's body use two matches

I has http request with body:
endpoint = http://127.0.0.1:54400/json
reqBody:
{
"action": "Handler:GET_DICTIONARY",
"locale": "ro",
"data": {"dictionary_type":"MTS"}
}
I need to get stubbed response.
Here my Wiremock mapping:
{
"request": {
"method": "POST",
"bodyPatterns": [
{
"contains": "Handler:GET_DICTIONARY"
}
]
},
"response": {
"headers": {
"Content-Type": "application/json"
},
"status": 200,
"fixedDelayMilliseconds": 3000,
"bodyFileName": "t2a/micb/webclient/_mts_response.json"
}
}
But I has many another requests that content request's body with text:
"Handler:GET_DICTIONARY"
So as result I need to mapping also by
"dictionary_type":"MTS"
because text
and
"dictionary_type":"MTS" AND "Handler:GET_DICTIONARY" create UNIQUE request.
So how I can mapping by request's body use this two matches?
I would suggest to add "matchesJsonPath" in addition to your "contains"
"bodyPatterns": [
{
"matchesJsonPath": "$.data[?(#.dictionary_type == 'MTS')]"
}
]
That will guarantee that all the request with dictionary_type = MTS will mapped to that response.

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"
}
}
}

Fetching multiple event details in Office 365

I need to fetch information related to eventId from office 365 for multiple events.
Is there a way I can get that info in a single REST call?
I want specific events only (based on eventId's only)
A batch request may be what you are looking for.
See json Batching Documentation for more information
Keep in mind that batching is currently limited to 20 requests per message (known issues)
Example:
You will need to send a POST Message to the batch endpoint
https://graph.microsoft.com/v1.0/$batch
inside the body you will need to include your requests:
Note: do not include the server url (https://graph.microsoft.com/v1.0/) in the url property or the request will fail with "BadRequest - Invalid request Uri".
Request-Body:
{
"requests": [
{
"id": "1",
"method": "GET",
"url": "/me/calendarview?startdatetime=2018-03-01T18:31:34.206Z&enddatetime=2018-03-12T18:31:34.206Z"
},
{
"id": "2",
"method": "GET",
"url": "/me/events/{someEventId}"
},
]
}
When the server has processed all requests an response array containing the results will be sent back:
Server-Response:
{
"responses": [
{
"id": "2",
"status": 200,
"headers": {
"OData-Version": "4.0",
"Content-Type": "application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8",
"ETag": "W/\"Z+ICSvkiAfZX7XWQAZ6IH==\""
},
"body": {
// the event object
}
},
{
"id": "1",
"status": 200,
"headers": {
"OData-Version": "4.0",
"Content-Type": "application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8"
},
"body": {
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('aUserID')/calendarView",
"value": [
// list of found event-objects
]
}
}
]
}