Writing Back to an API
We have created a few different ways you can write back to the API as its likely extra flexibility is needed around how the data is formatted or sent to the API endpoint.
Identifier Column
The first concept to understand is the role of the Identifier Column with Data Sync connectors. These values are attached to the row internally within Data Sync and are a way to maintain the datasource PrimaryKey even when its not part of the Schema Map. By maintaining this Identifier Column value it makes it possible to call UPDATE/DELETE actions on the target by the PrimaryKey value.
To ensure that the Identifier Column is set you need to specify the column from the Datasource which contains the Primary Key value like this within the DataTableTransform element.
<DataTableTransform path="data">
<IdentifierColumn data-type="System.Int32" path="ProductID" />
</DataTableTransform>
Default Automatic Mode
This is the default no-code option where the data is serialized to JSON and sent to the API endpoints using the URLs and Http Method(s) defined within the Writer element.
<Datasource name="products">
<Action name="GetDataSchema">
<StaticSchemaMap>
<Column name="ProductID" data-type="System.Int32" />
<Column name="ProductName" data-type="System.String" />
<Column name="SupplierID" data-type="System.Int32" />
<Column name="CategoryID" data-type="System.Int32" />
<Column name="QuantityPerUnit" data-type="System.String" />
<Column name="UnitPrice" data-type="System.Decimal" />
<Column name="UnitsInStock" data-type="System.Int32" />
<Column name="UnitsOnOrder" data-type="System.Int32" />
<Column name="ReorderLevel" data-type="System.Int32" />
<Column name="Discontinued" data-type="System.Boolean" />
</StaticSchemaMap>
</Action>
<Action name="GetDataTable">
<PagingRequest start="0" path="data">
<Fetch url="{URL}/ListApi?skip={PagingRequest.Count}&take={PageSize}">
<DataTableTransform path="data">
<IdentifierColumn data-type="System.Int32" path="ProductID" />
</DataTableTransform>
</Fetch>
</PagingRequest>
</Action>
<Writer name="Default">
<AddItem method="POST" url="{URL}/ListApi" />
<UpdateItem method="PUT" url="{URL}/ListApi/{Identifier0}" />
<DeleteItem method="DELETE" url="{URL}/ListApi/{Identifier0}" />
</Writer>
</Datasource>
For example this mode would send a HTTP response like this when Adding an item to the datasource.
POST http://localhost:2026/ListApi
Content-Type:application/json
Accept:application/json
{"ProductID":74,"ProductName":"Longlife Tofu","SupplierID":4,"CategoryID":7,"QuantityPerUnit":"5 kg pkg.","UnitPrice":10.0,"UnitsInStock":0,"UnitsOnOrder":20,"ReorderLevel":5,"Discontinued":false}
Should the API require the data within another object the you can also specify a single path element via the path attribute.
<Writer name="Default">
<AddItem method="POST" url="{URL}/ListApi" path="data" />
<UpdateItem method="PUT" url="{URL}/ListApi/{Identifier0}" path="data"/>
<DeleteItem method="DELETE" url="{URL}/ListApi/{Identifier0}" />
</Writer>
Project Automation Callbacks
This mode allows for full control of how the API is called via a C# delegate callback on each item. In this mode we setup the Writer element with a name of Callback and then configure the callback function in Project Automation.
<Datasource name="products">
<Action name="GetDataSchema">
<StaticSchemaMap>
<Column name="ProductID" data-type="System.Int32" />
<Column name="ProductName" data-type="System.String" />
<Column name="SupplierID" data-type="System.Int32" />
<Column name="CategoryID" data-type="System.Int32" />
<Column name="QuantityPerUnit" data-type="System.String" />
<Column name="UnitPrice" data-type="System.Decimal" />
<Column name="UnitsInStock" data-type="System.Int32" />
<Column name="UnitsOnOrder" data-type="System.Int32" />
<Column name="ReorderLevel" data-type="System.Int32" />
<Column name="Discontinued" data-type="System.Boolean" />
</StaticSchemaMap>
</Action>
<Action name="GetDataTable">
<PagingRequest start="0" path="data">
<Fetch url="{URL}/ListApi?skip={PagingRequest.Count}&take={PageSize}">
<DataTableTransform path="data">
<IdentifierColumn data-type="System.Int32" path="ProductID" />
</DataTableTransform>
</Fetch>
</PagingRequest>
</Action>
<Writer name="Callback">
<AddItem url="{URL}/ListApi" />
<UpdateItem url="{URL}/ListApi/{Identifier0}" />
<DeleteItem url="{URL}/ListApi/{Identifier0}" />
</Writer>
</Datasource>
You would then enable Project Automation and within the Start()
method setup the callback methods for ADD/UPDATE/DELETE. These will then be called during the synchronisation process for you to call the API.
For convenience we pass you an object for calling HTTP methods, the HttpWebRequestHelper, with any authentication headers set. Within the ProjectAutomationItemInfo object we have the target URL in the Target property.
The Data property contains a Dictionary<string, object>
of the data converted to match the target schema.
Therefore a simple implementation which would match the Default mode would be implemented like this.
public override void Start()
{
DataSourceB.SetWriterCallback(AddItem, UpdateItem, DeleteItem);
}
public void AddItem(HttpWebRequestHelper helper, ProjectAutomationItemInfo info)
{
helper.PostRequestAsJson(info.Data, info.Target);
}
public void UpdateItem(HttpWebRequestHelper helper, ProjectAutomationItemInfo info)
{
helper.PutRequestAsJson(info.Data, info.Target);
}
public void DeleteItem(HttpWebRequestHelper helper, ProjectAutomationItemInfo info)
{
helper.DeleteRequestAsJson(null, info.Target);
}
Include All Source Columns (from Schema Map) in Request
Available from Version 6.0.3344
The default writer will only include the changed column values in UPDATE actions in the Json Body. If you need to send all the column data again you can configure the writer by setting a mode value of AllColumns this will send all column values as part of the JSON body in the request.
<Writer name="Default">
<AddItem method="POST" url="{URL}/ListApi" />
<UpdateItem method="PUT" url="{URL}/ListApi/{Identifier0}" mode="AllColumns" />
<DeleteItem method="DELETE" url="{URL}/ListApi/{Identifier0}" mode="AllColumns" />
</Writer>
Include All Source Key Columns (from Schema Map) in Request
From Version 6.0.3344 you can include all source key columns from the schema map in the JSON body using the default writer. You can do this by setting the mode AllKeys to each action.
<Writer name="Default">
<AddItem method="POST" url="{URL}/ListApi" />
<UpdateItem method="PUT" url="{URL}/ListApi/{Identifier0}" mode="AllKeys" />
<DeleteItem method="DELETE" url="{URL}/ListApi/{Identifier0}" mode="AllKeys" />
</Writer>
Include Identifier Values in Request
Available from Version 6.0.3344
To send only the Identifier column values set the mode to AllIdentifiers and provide a comma separated list of column names in the identifier-columns attribute to use for the Identifier column values.
<Writer name="Default">
<AddItem method="POST" url="{URL}/ListApi" />
<UpdateItem method="PUT" url="{URL}/ListApi/{Identifier0}" mode="AllIdentifiers" identifier-columns="ProductID" />
<DeleteItem method="DELETE" url="{URL}/ListApi/{Identifier0}" mode="AllIdentifiers" identifier-columns="ProductID" />
</Writer>