This sample demonstrates how to read and write JSON to update server and serverUrl in the flow JSON file before publishing.
JSON transformers for flows should use the JsonContentTransformerBase<IPublishableFlow> base class, which handles opening the flow file, parsing the JSON, and persisting the modified JSON back to the file.
JSON transformers require additional resource overhead to execute, so care should be taken when developing them.
- Due to encryption, JSON transformers require the file to be loaded into memory to modify. For large flow files, this can require significant memory.
- Implementing the
NeedsJsonTransforming/needs_json_transforming method can reduce overhead by letting the transformer skip loading flow files that do not require changes.
JSON transformers are provided with "raw" JSON and no file format validation is performed by the SDK.
Care should be taken when modifying flow files that the changes do not result in content that is valid JSON but invalid by the file format.
File format errors can lead to migration errors during publishing, and can also cause errors that are only apparent after the migration is complete and reported success.
To update flow connection server values in Python, you can use the following transformer class:
from tableau_migration import (
IPublishableFlow,
JsonContentTransformerBase
)
class FlowConnectionServerJsonTransformer(JsonContentTransformerBase[IPublishableFlow]):
def needs_json_transforming(self, ctx: IPublishableFlow) -> bool:
# Returning false prevents the transform method from running.
# Implementing this method potentially allows flows to migrate
# without loading the file into memory, improving migration speed.
return len(ctx.connections) > 0
def transform(self, ctx: IPublishableFlow, json_obj: dict) -> None:
# Changes to the JSON are saved back to the flow file before publishing.
for _, connection in json_obj.get("connections", {}).items():
attrs = connection.get("connectionAttributes", {})
if attrs.get("server") == "https://old-server":
attrs["server"] = "https://new-server"
Registration
plan_builder.transformers.add(FlowConnectionServerJsonTransformer)
See hook registration for more details.
To update placeholder server values in flow connection attributes and flow nodes in C#, you can use the following transformer class:
/// <summary>
/// Sample JSON transformer that updates placeholder server and serverUrl in prep flow connection attributes and nodes. These may differ depending on your Tableau Server configuration
/// and require custom tranformation, such as private network and self-hosted server configurations.
/// Demonstrates using <see cref="JsonContentTransformerBase{TPublish}"/> for flows with performance guidance.
/// </summary>
public class FlowConnectionServerJsonTransformer : JsonContentTransformerBase<IPublishableFlow>
{
private const string PlaceholderServerUrl = "https://source-server";
private const string DestinationServerUrl = "https://destination-server";
protected override bool NeedsJsonTransforming(IPublishableFlow ctx)
{
/*
* Returning false prevents TransformAsync from running and avoids loading the flow file.
* Only transform flows that have connections; flows with no connections have nothing to update.
*/
return ctx.Connections.Count > 0;
}
public override Task TransformAsync(IPublishableFlow ctx, JsonNode json, CancellationToken cancel)
{
// Changes to the JSON are saved back to the flow file before publishing.
// Update server and serverUrl in nodes (e.g. output nodes have serverUrl; nodes may have connectionAttributes.server).
if (json["nodes"] is JsonObject nodesObject)
{
foreach (var nodePair in nodesObject)
{
if (nodePair.Value is not JsonObject nodeObj)
continue;
if (nodeObj["serverUrl"]?.GetValue<string>() == PlaceholderServerUrl)
nodeObj["serverUrl"] = DestinationServerUrl;
if (nodeObj["connectionAttributes"] is JsonObject nodeAttrs)
{
if (nodeAttrs["server"]?.GetValue<string>() == PlaceholderServerUrl)
nodeAttrs["server"] = DestinationServerUrl;
}
}
}
// Update connectionAttributes in top-level connections (server).
if (json["connections"] is not JsonObject connectionsObject)
return Task.CompletedTask;
foreach (var connectionPair in connectionsObject)
{
if (connectionPair.Value is not JsonObject connectionObj ||
connectionObj["connectionAttributes"] is not JsonObject attrs)
continue;
if (attrs["server"]?.GetValue<string>() == PlaceholderServerUrl)
attrs["server"] = DestinationServerUrl;
}
return Task.CompletedTask;
}
}
Registration
To register the transformer in C#, follow the guidance provided in the documentation.
_planBuilder.Transformers.Add<FlowConnectionServerJsonTransformer, IPublishableFlow>();
Dependency Injection
Learn more about dependency injection here.
services.AddScoped<FlowConnectionServerJsonTransformer>();