{
"Add Comment": {
"prefix": "TriComment",
"body": [
"//TRI ${1:Your Name here} $CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE $CURRENT_HOUR:$CURRENT_MINUTE:$CURRENT_SECOND ${2|+,-,Start,End,++|}"
],
"description": "TRI Add Comment"
}
}
{
"Add Comment": {
"prefix": "TriComment",
"body": [
"//TRI ${1:Your Name here} $CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE $CURRENT_HOUR:$CURRENT_MINUTE:$CURRENT_SECOND ${2|+,-,Start,End,++|}"
],
"description": "TRI Add Comment"
}
}
The $batch endpoint is available on all API endpoints. For the Business Central SaaS environment you can use this URL:
https://{{baseurl}}/api/v2.0/$batch
Everything I describe here also works for custom APIs. The URL will then look like:
https://{{baseurl}}/api/[publisher]/[group]/[version]/$batch
Because the request body will be JSON the Content-Type header of the request must be set to appication/json. If the response should be JSON as well (and you want that!), then the Accept header must also be set to application/json. If you leave the Accept header out, then the response will be multipart/mixed. Here is the basic structure of the request, without the body. I leave out the Authorization header, but you need to add that obviously.
POST {{baseurl}}/api/v2.0/$batch Content-Type: application/json Accept: application/json
The requests array must contain one ore more operations, and each of them must contains an id, the method and a URL and optionally also headers and a body. Here is an example of an operation to insert a single journal line.
{
"method": "POST",
"id": "r1",
"url": "companies({{companyId}})/journals({{journalId}})/journalLines",
"headers": {
"Content-Type": "application/json"
},
"body": {
"accountId": "{{accountId}}",
"postingDate": "2020-10-20",
"documentNumber": "SALARY2020-10",
"amount": -3250,
"description": "Salary to Bob"
}
}
{
"requests": [
{
"method": "POST",
"id": "r1",
"url":
"companies({{companyId}})/journals({{journalId}})/journalLines",
"headers": {
"Content-Type":
"application/json"
},
"body": {
"accountId":
"{{accountId}}",
"postingDate":
"2020-10-20",
"documentNumber":
"SALARY2020-12",
"amount": -3250,
"description": "Salary
to Bob"
}
},
{
"method": "POST",
"id": "r2",
"url":
"companies({{companyId}})/journals({{journalId}})/journalLines",
"headers": {
"Content-Type":
"application/json"
},
"body": {
"accountId":
"{{accountId}}",
"postingDate":
"2020-10-20",
"documentNumber":
"SALARY2020-12",
"amount": -3500,
"description": "Salary
to John"
}
},
{
"method": "POST",
"id": "r3",
"url":
"companies({{companyId}})/journals({{journalId}})/journalLines",
"headers": {
"Content-Type":
"application/json"
},
"body": {
"accountId":
"{{accountId2}}",
"postingDate":
"2020-10-20",
"documentNumber":
"SALARY2020-12",
"amount": 6750,
"description": "Salaries
December 2020"
}
}
]
}
As you can see, each operation has a corresponding result in the response, identified by the id. You should always use the id of the individual operation to find the corresponding result. Don’t assume that the results will always be in the same order as the request! They may seem to be in the same order, but the OData standard describes that the results can be in any order.
Each operation result has a status, which is the HTTP status that you would normally get for a single request. It includes the response headers and response body of the individual operation. The response of the batch request itself will always have status 200 if the server was able to read the batch request. Even if the batch request has operations that couldn’t be processed because of an error condition, the batch response status will still be 200. So don’t only look at the response status of the batch request, you need to read the response body to find out the results of each operation. Only when the batch request body is malformed, or you are not authorized, then the whole batch request will fail and you will get a status 500 (malformed batch request) or status 401 (not authorized).
So far it’s really simple, isn’t it? In the next blog posts in this series, I will cover topics like:
local procedure TrySplitTextWithoutDamagingWords(FullText: Text; MaximumCaractorLength:Integer; var MaximumText: Text; var RemainingText: Text) IsRemainingToSplit: Boolean
var
SpcPos: Integer;
MaxSpcPos: Integer;
CheckText: Text;
begin
FullText := DelChr(FullText, '<>', ' ');
if (FullText = '') or (MaximumCaractorLength = 0) or (StrLen(FullText) <= MaximumCaractorLength) then begin
MaximumText := FullText;
RemainingText := '';
exit(false);
end;
MaximumText := CopyStr(FullText, 1, MaximumCaractorLength);
RemainingText := CopyStr(FullText, MaximumCaractorLength + 1, StrLen(FullText));
if CopyStr(FullText, MaximumCaractorLength+1, 1)<>' 'then begin
CheckText := MaximumText;
repeat begin
SpcPos := StrPos(CheckText, ' ');
MaxSpcPos += SpcPos;
CheckText := CopyStr(CheckText, SpcPos + 1, MaximumCaractorLength);
end until SpcPos = 0;
if MaxSpcPos > 0 then begin
MaximumText := CopyStr(FullText, 1, MaxSpcPos - 1);
RemainingText := CopyStr(FullText, MaxSpcPos + 1, StrLen(FullText));
end;
end;
exit(StrLen(RemainingText) > MaximumCaractorLength);
end;
There are four parameters and a boolean type return value.
I create three local variables (FullText: Text, SplitText: Text, and RemainingText: Text) and pass them as follows (The maximum character length is 26).
FullText:='NAVUSER is the best site for learning Microsoft Dynamics Navision and Dynamics 365 Business Central.';
TrySplitTextWithoutDamagingWords(FullText,26,SplitText,RemainingText);
Message(SplitText);
FullText:='NAVUSER is the best site for learning Microsoft Dynamics Navision and Dynamics 365 Business Central.';
RemainingText:=FullText;
repeat
TrySplitTextWithoutDamagingWords(RemainingText,26,SplitText,RemainingText);
Message(SplitText);
until RemainingText='';
Storing passwords directly in a table is a bad idea from a security point of view. For secure storage of passwords, the Service Password system table was previously used. In Business Central 15.0, it has been removed.
We are offered to use a new data type - Isolated Storage. Here we'll look at a practical example of using this functionality to store passwords securely.In our example, we will use Module DataScope.
}