PUT operations allow you to update new record in an external system and with RESTwithUS you can update it based on Business Central data.
Some APIs use PATCH keyword instead of PUT for update operations (it should be noted in the API service documentation). In that case, just use PATCH instead of PUT in all cases.
Let's have a simple example of a PUT API Endpoint on URL https://test.api.com/v3/Customer, which allows you to update the data of selected Customer. You need to provide the selected Customer id in GET parameter id
, so the final URL may for example look like https://test.api.com/v3/Customer?id=1 and JSON request body is as following:
If the Customer was updated without an error, the endpoint returns his data including the Customer id
in an external system:
For the sake of simplicity let's say that you are storing Business Central Customer No. in no
node. And there are more fields like customer name
, address
, city
etc.
To call this API endpoint you need to create a new Operation.
If you are creating your own AL extension that should implement connection with some API provider, the recommended way to start is to add your operation to Operation ID RWU
enum:
enumextension 50002 "Test Operation ID RWU" extends "Operation ID RWU"
{
value(50008; "TestProvider_UpdateCustomer")
{
Caption = 'Update Customer (Test Provider)';
}
}
Tip: You can skip this step for testing purposes and call your operations with provider description instead of enum ID. However, this is not recommended for production applications.
Now select your API provider from the list and open Operations:
Create a new PUT operation pointing to your API endpoint:
PUT
./Customer
in the Endpoint field – i.e. the part of the URL without Provider URL (see Setting up API Provider).Open
, meaning you can update the operation.With PUT operations you are usually sending a JSON request and then receiving a JSON response, plus you need to provide the record id in URL parameters or URL itself.
To update specific Customer record you need to send its identifier in URL parameter id
(the final URL may then look like https://test.api.com/v3/Customer?id=1). So select your operation from the list and open Related / URL Parameters:
Now fill in request URL parameters which is just id
in this case:
id
parameter with code. So let's use the variable named CustomerId
(with a syntax {{VariableName}}
) and let's make it required, so the final syntax is {{!CustomerId}}
.Tip: If you have URL like https://test.api.com/v3/Customer/1, i.e. the
id
is sent directly in the URL string, you can use similar approach. Just include the variable in the operation Endpoint field:
The code to set the variable is the same.
To create request body and fill the JSON nodes from Business Central tables and fields select your operation from the list and open Request Body:
Initially, the request body is empty, so use function Payload / Import Payload, paste an example of a JSON request and press OK:
RESTwithUS will generate request structure for you and you just need to map it to Business Central tables and fields:
The root
node contains Customer record, so let's connect it with the Customer table in Business Central. Set Type to Table
and Object ID to the ID of Customer Table: 18
.
Set up fields which are both in the Business Central record and a record in an external system.
Let's say that the node phones
is optional – if a Customer does not have any phone number, there is no value. With default settings this may throw an error, but you can mark the node as optional by setting MinOccurs to Zero
.
Tip: You can set request node values with code using
ADD_VALUE
orADD_VARIABLE
functions, too (see API Script Functions Reference or Using RESTwithUS Variables).
To create a response body and map the JSON data to Business Central tables and fields select your operation from the list and open Response Body:
Initially, the response body is empty, so use function Payload / Import Payload, paste an example of JSON response and press OK:
RESTwithUS will generate response structure for you and you just need to map it to Business Central tables and fields:
The recommended way on how to proceed is to use Entities and define the JSON schema in one place (see guideline Working with Entities). But let's now just create a simple PUT response and map it to Business Central fields.
The root
node contains Customer record, so let's connect it with Customer table in Business Central. Set Type to Table
and Object ID to the ID of Customer Table: 18
.
If you want to store connections between records in Business Central and an external system, it must be done at Entity level. First go to provider Entities and create a new entity called Customer
(if you haven't done that already for another operation):
Now map the JSON response to the entity:
a. Select the Customer
entity in the Entity ID field on the root
node.
b. Set id
node to Mapping Type External ID
and select the Entity ID, too. (External ID
marks node which contains the record ID in an external system.)
c. Set name
node to Mapping Type Description
and select the Entity ID, too. (This is just for easier visual searching in connections.)
Set up fields which are both in Business Central record and a record in an external system.
Mark the node phones
as optional like in the request body.
Tip: You do not need to match all fields to Business Central counterparts. In this example, you basically need only the
no
node to get the right connection. Since you do not saveaddress
orcountryCode
values back to Business Central you may as well leave them unmatched.
The last thing that might need to be done is to update the Connection. With PUT operations you are always working with existing records, so you should already have an existing connection saved in Business Central. In this connection you have the id
from an external system saved as the External ID – and in this example, you have set the name
column as Ext. Description.
The External ID usually does not change at all, but someone might rename the customer in an external system and it would be nice to see the change in connections too.
All connection mappings are done on the nodes with Type Table
. Select the root
node then and open Home / Details:
First you need to select the Connection Operation. You are updating an existing connection, so let's set the Update
option here.
Now you need to fill in the Table View field which defines, how to search for the matching record in Business Central. You can write it manually, or you can use helper function Process / Generate Table View:
In this scenario you are matching the records by the Customer No.
so select the No.
key and press OK. RESTwithUS will generate a Table View based on the selected table key:
As you can see, this is a simple table view expression meaning:
{{Field1}}
(field number 1 from current table) – and previously you have defined that Field 1
of a Customer table is in the JSON node no
.Let's run the operation for the first time and try to update data of existing customer from Business Central data. You will need just a few lines of a code for that using the API Script RWU codeunit. Just don't forget to Release both the entity and the operation before running the code.
var
Customer: Record "Customer";
APIScriptRWU: Codeunit "API Script RWU";
EntityID: Enum "Entity ID RWU";
ProviderID: Enum "Provider ID RWU";
OperationID: Enum "Operation ID RWU";
MappingId: Text;
Customer.GET('01121212'); //Get customer record
MappingId := APIScriptRWU.MAPPING(ProviderID::TestProvider, EntityID::TestProvider_Customer, Customer); //Get id of the customer in an external system from RESTwithUS connection
//For BC 18 and newer use record SystemId instead
//MappingId := APIScriptRWU.MAPPING(ProviderID::TestProvider,EntityID::TestProvider_Customer, Customer.SystemId);
IF MappingId = '' THEN //If there is no connection yet, throw error
Error('Customer does not exist in an external system.');
APIScriptRWU.INIT(OperationID::TestProvider_UpdateCustomer); //Set the identifier for saving Batch Entries
APIScriptRWU.ENDPOINT(ProviderID::TestProvider,OperationID::TestProvider_UpdateCustomer); //Select the provider and his operation
APIScriptRWU.ADD_VARIABLE('','CustomerId',MappingId); //Set the CustomerId variable in URL parameters
APIScriptRWU.ADD_VALUE('/',Customer); //Add the selected Customer record to the root node
APIScriptRWU.ADD_VALUE('/phones','123456789'); //Add first phone number to phones node
APIScriptRWU.ADD_VALUE('/phones','999999999'); //Add second phone number to phones node
APIScriptRWU.EXECUTE(); //Start the operation
In this example, you are adding phone numbers manually with ADD_VALUE
function. But with a different setup you can fill the array from a table too – see the details of Simple Array JSON Data Type.
Tip: For more API Script functions see guideline API Script Functions Reference.
For testing purposes you can call the provider and operation by their description. However, this is not recommended for production applications:
APIScriptRWU.INIT('TEST_PROVIDER_UPDATE_CUSTOMER');
APIScriptRWU.ENDPOINT('Test Provider','Update Customer');
Now you can check the result. First go to Operations, select the operation from the list and open Related / Batch Entries from the menu:
Here you can see all the details about the operation run like:
root
node values.CustomerId
.root
and phones
nodes in request.Tip: You set the Batch Code value with
INIT
function and you can use whatever string you want. Just remember that each new call of an operation deletes all previous Batch Entries with the same Batch Code. For more details see guideline Batch Entries.
Connections are maintained on Entity level. To check them select your API Provider and choose Entities from the menu:
You can click the number in marked columns to see the connection details:
As you can see, the customer 01121212
has a healthy connection and the Ext. Description contains the customer name from JSON response.
Tip: For more details about connections see guideline Connections.
In a real project we recommend merging POST and PUT/PATCH operations into one function, that will:
Example of such function:
procedure RefreshCustomer(Customer: Record Customer)
var
APIScriptRWU: Codeunit "API Script RWU";
EntityID: Enum "Entity ID RWU";
ProviderID: Enum "Provider ID RWU";
OperationID: Enum "Operation ID RWU";
MappingId: Text;
begin
//Try to get external record id from connections
MappingId := APIScriptRWU.MAPPING(ProviderID::TestProvider,EntityID::TestProvider_Customer, Customer);
//For BC 18 and newer use record SystemId instead
//MappingId := APIScriptRWU.MAPPING(ProviderID::TestProvider,EntityID::TestProvider_Customer, Customer.SystemId);
//Connection not found, create the record
if MappingId = '' then begin
APIScriptRWU.INIT(OperationID::TestProvider_CreateCustomer);
APIScriptRWU.ENDPOINT(ProviderID::TestProvider,OperationID::TestProvider_CreateCustomer);
APIScriptRWU.ADD_VALUE('/',Customer);
APIScriptRWU.EXECUTE();
end
//Connection found, update the record data
else begin
APIScriptRWU.INIT(OperationID::TestProvider_UpdateCustomer);
APIScriptRWU.ENDPOINT(ProviderID::TestProvider,OperationID::TestProvider_UpdateCustomer);
APIScriptRWU.ADD_VARIABLE('','CustomerId',MappingId);
APIScriptRWU.ADD_VALUE('/',Customer);
APIScriptRWU.EXECUTE();
end;
end