BC OData transactional $batch requests limitation
Overview
I recently had the requirement to create multiple records in BC so far so easy. After creating a simple request to create on record it was only a little search until I stumbled about Using OData transactional $batch requests.
Transactional $batch requests are useful in scenarios where a single business operation spans multiple requests, because they prevent adverse effects if parts of the operation fail. Also, they can improve performance by reducing the number of requests the client needs to do when errors occur.
This was exactly the improvement I was looking for. Little did I know what kind of pitfalls there are, at least in 25.*
When they work fine
As long as the error is caused by the business logic layer
everything is fine.
You get an error in the response, and everything is rolled back as expected.
What do I mean with business logic layer
:
- Errors caused due to field properties, for example the value should be greater 0
- AL Code
When they don’t work
Since I was new to the world of $batch
processing in BC I ran into two limitations with my first two test cases.
- Assigning a string to an integer property
- Creating two records with the same primary key
Both tests failed utterly and even in different ways.
Invalid JSON
I thought this would be the easiest way to test the transactional batch processing.
- One request with a valid JSON
- Second request with an invalid JSON, assign a string to an integer property.
Expectation:
- Processing is aborted, with the faulty request
- I get an error for the failed request
- Everything is rolled back
Actual result:
- ✅ Processing is aborted, with the faulty request
- ✅ I get an error for the failed request
- ❌ Everything is rolled back
Instead of rolling back everything, the first request was processed and committed to the database.
Duplicate key
This was the second case I tested, after the first one failed.
- One request
- Second request with the same primary key values
Expectation:
- Processing is aborted, with the faulty request
- I get an error for the failed request
- Everything is rolled back
Actual result:
- ❌ Processing is aborted, with the faulty request
- ❌ I get an error for the failed request
- ✅ Everything is rolled back
This is also a very interesting
behavior. The $batch
request returns with a success status code, both requests have a success status code, but the data was not committed to the database.
If there’s another request in the $batch
then we get the error from the previous request. But this is only true, if the following requests targets the same table. If the request would target another table, we won’t get the error.
Resolution / workaround
Invalid JSON
There’s no workaround for this. Let’s just hope, that your dynamic generated JSON Body fails already on the first request.
Duplicate key
Add a get request after each post/patch request. This is surely not the way I would like to implement it, but in a dynamic generated JSON Body there’s no other way.
From single to $batch request
Single endpoint example
- Endpoint:
/api/CosmoConsult/xyz/v2.0/apiDrawingDimensions?company=XYZ
- Method:
Post
- Body:
{ "drawingNo": "000-DKR2", "expectedValue": "expected value 1", "version": 17, "ITP": "ABC", "no": "Some number 1" }
$batch example
Single endpoint example
- Endpoint options:
/api/v2.0/$batch
/api/CosmoConsult/xyz/v2.0/$batch
- Method:
Post
- Body:
{ "requests": [ { "method": "POST", "id": "Operation-1", "url": "apiDrawingDimensions?company=XYZ", "headers": { "Content-Type": "application/json", "prefer": "return-no-content" }, "body": { "drawingNo": "000-DKR2", "expectedValue": "expected value 1", "version": 17, "ITP": "ABC", "no": "Some number 1" } }, { "method": "Get", "id": "Operation-1-Get", "url": "apiDrawingDimensions?company=XYZ&$top=1", "headers": { "Content-Type": "application/json", "prefer": "return-no-content" } }, ] }
Comments