30日間の無料評価版をお試しいただけます。

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

クライアントソース置換は、プライマリー組織からの共有コンテンツを閲覧する際に、各クライアント組織に個別のデータソースを使用するためのメカニズムです。これにより、最小限の構成で、レポートやダッシュボードの単一のコピーを、各クライアントがそれぞれのデータで使用できます。

一般的なシナリオは、新しいテナントがYellowfin インスタンスにオンボーディングされ、そのテナントのデータに対するレポートを有効にする必要がある場合です。このプロセスには、いくつかの手順が含まれます。

  1. データソースをクライアント組織で作成する必要があります。
  2. 新しいクライアントデータソースは、すべての共有コンテンツが作成されたプライマリー組織にリンクされている必要があります。

クライアント組織で新しいデータソースを作成するには、2つの方法があります。既存のデータソースのコピーをインポートすることで、クライアントのデータソースを作成することができます。データソースを直接作成するエンドポイントもあります。

データソースが作成されると、クライアントデータソースをプライマリー組織のデータソースに関連付けるためのエンドポイントが1つ用意されます。

複製したインポートからデータソースを作成

新しいクライアント組織に新しいデータソースを作成する1つの方法は、既存のデータソースを複製し、新しい接続のために接続詳細を変更することです。これは、既存のデータソースをエクスポートし、エクスポートファイル自体を変更して、Yellowfinに再インポートすることで実現できます。

ソース置換を使用する場合、プライマリー組織に既にプレースホルダーデータソースがあり、そこにすべてのレポートコンテンツが存在している必要があります。このデータソースは、Yellowfin内のエクスポートUIを使用してエクスポートできます。これにより、YellowfinからYFX形式のファイルがエクスポートされます。

YFXファイルは、解凍可能なアーカイブ (zip) ファイルです。YFXファイル内には、ExportListHierarchy.json ファイルと、YFExport.xml ファイルがあります。YFExport.xml ファイルには、エクスポートされたデータソースの読み取り可能なバージョンが含まれています。

YFExport.xml ファイル内では、データベース接続設定を変更できます。ソース置換用のテナントデータソースの作成プロセスを自動化する場合は、YFExport.xml ファイルのコンテンツをテンプレートとして使用し、接続固有のデータを注入する必要がある場所にトークンを追加します。

以下のYFExport.xml ファイルの抜粋は、クライアントソース置換で使用するデータソースを自動生成するプロセスでトークンを置き換える箇所を赤で示しています。

<source>

   <id>132641</id>

   <sourceName>PostgreSQL Connection for [TENANT_NAME]</sourceName>

   <sourceDescription>PostgreSQL Connection for [TENANT_NAME]</sourceDescription>

   <databasePath>public</databasePath>

   <userName>[USERNAME]</userName>

   <password>[ENCRYPTED_PASSWORD]</password>

   <connectionTypeCode>GENERICUSER</connectionTypeCode>

   <connectionMethodCode>JDBC</connectionMethodCode>

   <connectionDriver>org.postgresql.Driver</connectionDriver>

   <databaseURL>jdbc:postgresql://[SERVER_ADDRESS]:5432/[DATABASE_NAME]></databaseURL>

   <databaseTypeCode>POSTGRESQL</databaseTypeCode>

   <minConnections>1</minConnections>

   <maxConnections>5</maxConnections>

   <connectionRefreshTime>180</connectionRefreshTime>

   <connectionTimeOut>180</connectionTimeOut>

   <accessCode>UNSECURE</accessCode>

   <maxRowCount>10000</maxRowCount>

   <maxAnalysisRowCount>0</maxAnalysisRowCount>

   <broadcastPermitted>true</broadcastPermitted>

   <subscribePermitted>true</subscribePermitted>

   <dataProfileEnabled>true</dataProfileEnabled>

   <localTimezoneCode>AUSTRALIA/LORD_HOWE</localTimezoneCode>

   <secondaryMinConnections>0</secondaryMinConnections>

   <secondaryMaxConnections>0</secondaryMaxConnections>

   <secondaryConnectionRefreshTime>0</secondaryConnectionRefreshTime>

   <secondaryConnectionTimeOut>0</secondaryConnectionTimeOut>

   <lastModifiedGMTDateTime>20240607025556.000000</lastModifiedGMTDateTime>

   <sourceUUID>7d7543c0-e9c7-4a80-ab14-73181e4d0694</sourceUUID>

   <filterList/>

   <sourceParameterList>

     <sourceParameter>

       <id>0</id>

       <parameterTypeCode>TEXT</parameterTypeCode>

       <parameterKey>DATABASE</parameterKey>

       <parameterIndex>0</parameterIndex>

       <parameterValue>[DATABASE_NAME]</parameterValue>

       <documentId>0</documentId>

       <userVisible>true</userVisible>

     </sourceParameter>

     <sourceParameter>

       <id>0</id>

       <parameterTypeCode>TEXT</parameterTypeCode>

       <parameterKey>HOSTNAME</parameterKey>

       <parameterIndex>0</parameterIndex>

       <parameterValue>[SERVER_ADDRESS]</parameterValue>

       <documentId>0</documentId>

       <userVisible>true</userVisible>

     </sourceParameter>

エクスポートファイルを自動的にトークンに挿入したら、POST /api/rpc/import-export/import-content エンドポイント Import Content を使用してREST API経由でアップロードできます。

この特定のエンドポイントは、フォームベースの送信パラダイムを使用します。2つのフォーム本体が必要であり、1つはYFX/XML ファイルコンテンツを含む「contentToProcess」という名前で、もう1つは、インポート処理に関するルールを含む「importOptions」という名前です。こちらの例では、XMLファイルに単一のデータソースが含まれていると仮定して、この importOptions ペイロードを使用できます。

[
  { "itemIndex": 0, "optionKey": "SKIP", "optionValue": false },
  { "itemIndex": 0, "optionKey": "OPTION\", "optionValue": "ADD" }
]

以下のコード例では、事前にエクスポートされたデータベースXMLテンプレートを使用して、データベースホスト、データベース名、データベースユーザーとパスワードの置換値をファイルに挿入します。その後、(クライアント参照IDで指定された) テナントにインポートされます。

Java
package rest.code.examples;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Random;
import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
import org.apache.hc.client5.http.fluent.Content;
import org.apache.hc.client5.http.fluent.Request;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.HttpEntity;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
/**
 * Import a datasource for a client org using the Yellowfin REST API
 */
public class ImportDatasourceForClientOrg {
    public static void main(String[] args) throws Exception {
 
        System.out.print(""Import Datasource for Client"");
 
        String host = ""http://localhost:8080/Yellowfin"";
        String restUsername = ""admin@yellowfin.com.au"";
        String restPassword = ""test"";
 
        String tenantClientReferenceId = ""NEWCLIENT"";
        String databaseUserName = ""postgres"";
        String encryptedPassword = ""NDliYzg3NGItMDVjJVY8ywTSdIE3D1zdGplLLBUcEFqw"";
        String serverAddress = ""localhost"";
        String databaseName = ""testdata"";
 
        String token = generateTokenForTenant(host, restUsername, restPassword, tenantClientReferenceId);
 
        Integer tenantId = retrieveTenantIpIdForTenantName(host, token, tenantClientReferenceId);
        System.out.println(""Tenant Id: "" + tenantId);
 
        // Replace tokens with values
        String modifiedFileContents = importFileContents;
        modifiedFileContents = modifiedFileContents.replace(""[USERNAME]"", databaseUserName);
        modifiedFileContents = modifiedFileContents.replace(""[TENANT_NAME]"", tenantClientReferenceId);
        modifiedFileContents = modifiedFileContents.replace(""[ENCRYPTED_PASSWORD]"", encryptedPassword);
        modifiedFileContents = modifiedFileContents.replace(""[SERVER_ADDRESS]"", serverAddress);
        modifiedFileContents = modifiedFileContents.replace(""[DATABASE_NAME]"", databaseName);
 
        HttpEntity multipartEntity = MultipartEntityBuilder
                .create()
                .setMode(HttpMultipartMode.LEGACY)
                .setCharset(Charset.forName(""UTF-8""))
                .addBinaryBody(""contentToProcess"", modifiedFileContents.getBytes(""UTF-8""), ContentType.DEFAULT_BINARY, ""YFExport.xml"")
                .addTextBody(""importOptions"", ""[{ \""itemIndex\"": 0, \""optionKey\"": \""SKIP\"", \""optionValue\"": false }, { \""itemIndex\"": 0, \""optionKey\"": \""OPTION\"", \""optionValue\"": \""ADD\"" }]"", ContentType.APPLICATION_JSON)
                .build();
 
        System.out.println(""Content-Type: "" + multipartEntity.getContentType());
        Content c = Request.post(host + ""/api/rpc/import-export/import-content"")
                .addHeader(""Authorization"", ""YELLOWFIN ts="" + System.currentTimeMillis() + "" , nonce="" + new Random().nextLong() + "", token="" + token)
                .addHeader(""Accept"", ""application/vnd.yellowfin.api-v1+json"")
                .addHeader(""Content-Type"", multipartEntity.getContentType())
                .addHeader(""cache-control"", ""no-cache"")
                .body(multipartEntity)
                .execute()
                .returnContent();
 
        System.out.println(c.asString());
 
    }
    /*
     *  This function fetches a client organization's integer id for a given clientRefCode
     */
 
    public static Integer retrieveTenantIpIdForTenantName(String host, String token, String tenantCode) throws IOException {
 
        Content c = Request.get(host + ""/api/orgs"")
                .addHeader(""Authorization"", ""YELLOWFIN ts="" + System.currentTimeMillis() + "" , nonce="" + new Random().nextLong() + "", token="" + token)
                .addHeader(""Accept"", ""application/vnd.yellowfin.api-v1+json"")
                .addHeader(""Content-Type"", ""application/json"")
                .execute().returnContent();
 
        JsonObject jsonObject = new JsonParser().parse(c.asString()).getAsJsonObject();
        JsonElement groupList = jsonObject.get(""items"");
        JsonArray groups = groupList.getAsJsonArray();
 
        for (int i=0; i < groups.size(); i++ ) {
            JsonObject group = groups.getAsJsonArray().get(i).getAsJsonObject();
            if (!group.has(""clientRefId"")) continue;
            if (tenantCode.equals(group.get(""clientRefId"").getAsString())) return group.get(""ipOrg"").getAsInt();
        }
 
        System.out.println(""Tenant could not be found for code:"" + tenantCode);
        System.exit(-1);
 
        return null;
    }
 
 
    /*
     *  This function generates an access token for a user that will grant them access to
     *  call REST API endpoints.
     */
 
    public static String generateTokenForTenant(String host, String username, String password, String tenant) throws IOException {
 
        Content c = Request.post(host + ""/api/refresh-tokens"")
                .addHeader(""Authorization"", ""YELLOWFIN ts="" + System.currentTimeMillis() + "" , nonce="" + new Random().nextLong())
                .addHeader(""Accept"", ""application/vnd.yellowfin.api-v1+json"")
                .addHeader(""Content-Type"", ""application/json"")
                .bodyString(""{ \""userName\"": \""""+ username + ""\"",\""password\"": \""""+ password + ""\"", \""clientOrgRef\"": \"""" + tenant + ""\""}"", null)
                .execute().returnContent();
 
        JsonObject jsonObject = new JsonParser().parse(c.asString()).getAsJsonObject();
        JsonElement accessToken = jsonObject.getAsJsonObject(""_embedded"").getAsJsonObject(""accessToken"").get(""securityToken"");
 
        if (accessToken!=null) {
            System.out.println(""Access Token: "" + accessToken);
        } else {
            System.out.println(""Token not retrieved successfully"");
            System.exit(-1);
        }
        return accessToken.getAsString();
 
    }
    private static String importFileContents = ""<?xml version=\""1.0\"" encoding=\""UTF-8\""?><!-- Yellowfin export file --><!-- Generated at 2024-06-07 12:56 AEST (+1000) --><data>\n""
            + ""  <info>\n""
            + ""    <exportversion>4</exportversion>\n""
            + ""    <exportsubversion>54</exportsubversion>\n""
            + ""    <transferHeaderUUID>c072afce-d02a-4b2c-ae06-c3b62c8d6ea8</transferHeaderUUID>\n""
            + ""    <appversion>9.11</appversion>\n""
            + ""    <appsubversion>0.3</appsubversion>\n""
            + ""    <buildversion>20240607</buildversion>\n""
            + ""    <exportdate>2024-06-07 12:56 AEST (+1000)</exportdate>\n""
            + ""    <systemid>9e/Rsd4Jf6UwZGq/5Q8Ej1Giviw=</systemid>\n""
            + ""  </info>\n""
            + ""  <source>\n""
            + ""    <id>132641</id>\n""
            + ""    <sourceName>PostgreSQL Connection for [TENANT_NAME]</sourceName>\n""
            + ""    <sourceDescription>PostgreSQL Connection for [TENANT_NAME]</sourceDescription>\n""
            + ""    <databasePath>public</databasePath>\n""
            + ""    <userName>[USERNAME]</userName>\n""
            + ""    <password>[ENCRYPTED_PASSWORD]</password>\n""
            + ""    <connectionTypeCode>GENERICUSER</connectionTypeCode>\n""
            + ""    <connectionMethodCode>JDBC</connectionMethodCode>\n""
            + ""    <connectionDriver>org.postgresql.Driver</connectionDriver>\n""
            + ""    <databaseURL>jdbc:postgresql://[SERVER_ADDRESS]:5432/[DATABASE_NAME]></databaseURL>\n""
            + ""    <databaseTypeCode>POSTGRESQL</databaseTypeCode>\n""
            + ""    <minConnections>1</minConnections>\n""
            + ""    <maxConnections>5</maxConnections>\n""
            + ""    <connectionRefreshTime>180</connectionRefreshTime>\n""
            + ""    <connectionTimeOut>180</connectionTimeOut>\n""
            + ""    <accessCode>UNSECURE</accessCode>\n""
            + ""    <maxRowCount>10000</maxRowCount>\n""
            + ""    <maxAnalysisRowCount>0</maxAnalysisRowCount>\n""
            + ""    <broadcastPermitted>true</broadcastPermitted>\n""
            + ""    <subscribePermitted>true</subscribePermitted>\n""
            + ""    <dataProfileEnabled>true</dataProfileEnabled>\n""
            + ""    <localTimezoneCode>AUSTRALIA/LORD_HOWE</localTimezoneCode>\n""
            + ""    <secondaryMinConnections>0</secondaryMinConnections>\n""
            + ""    <secondaryMaxConnections>0</secondaryMaxConnections>\n""
            + ""    <secondaryConnectionRefreshTime>0</secondaryConnectionRefreshTime>\n""
            + ""    <secondaryConnectionTimeOut>0</secondaryConnectionTimeOut>\n""
            + ""    <lastModifiedGMTDateTime>20240607025556.000000</lastModifiedGMTDateTime>\n""
            + ""    <sourceUUID>7d7543c0-e9c7-4a80-ab14-73181e4d0694</sourceUUID>\n""
            + ""    <filterList/>\n""
            + ""    <sourceParameterList>\n""
            + ""      <sourceParameter>\n""
            + ""        <id>0</id>\n""
            + ""        <parameterTypeCode>TEXT</parameterTypeCode>\n""
            + ""        <parameterKey>DATABASE</parameterKey>\n""
            + ""        <parameterIndex>0</parameterIndex>\n""
            + ""        <parameterValue>[DATABASE_NAME]</parameterValue>\n""
            + ""        <documentId>0</documentId>\n""
            + ""        <userVisible>true</userVisible>\n""
            + ""      </sourceParameter>\n""
            + ""      <sourceParameter>\n""
            + ""        <id>0</id>\n""
            + ""        <parameterTypeCode>TEXT</parameterTypeCode>\n""
            + ""        <parameterKey>HOSTNAME</parameterKey>\n""
            + ""        <parameterIndex>0</parameterIndex>\n""
            + ""        <parameterValue>[SERVER_ADDRESS]</parameterValue>\n""
            + ""        <documentId>0</documentId>\n""
            + ""        <userVisible>true</userVisible>\n""
            + ""      </sourceParameter>\n""
            + ""      <sourceParameter>\n""
            + ""        <id>0</id>\n""
            + ""        <parameterTypeCode>TEXT</parameterTypeCode>\n""
            + ""        <parameterKey>ISOLATIONLEVEL</parameterKey>\n""
            + ""        <parameterIndex>0</parameterIndex>\n""
            + ""        <parameterValue/>\n""
            + ""        <documentId>0</documentId>\n""
            + ""        <userVisible>true</userVisible>\n""
            + ""      </sourceParameter>\n""
            + ""      <sourceParameter>\n""
            + ""        <id>0</id>\n""
            + ""        <parameterTypeCode>TEXT</parameterTypeCode>\n""
            + ""        <parameterKey>PORT</parameterKey>\n""
            + ""        <parameterIndex>0</parameterIndex>\n""
            + ""        <parameterValue>5432</parameterValue>\n""
            + ""        <documentId>0</documentId>\n""
            + ""        <userVisible>true</userVisible>\n""
            + ""      </sourceParameter>\n""
            + ""      <sourceParameter>\n""
            + ""        <id>0</id>\n""
            + ""        <parameterTypeCode>TEXT</parameterTypeCode>\n""
            + ""        <parameterKey>SOURCECLASSNAME</parameterKey>\n""
            + ""        <parameterIndex>0</parameterIndex>\n""
            + ""        <parameterValue>com.hof.sources.JDBCSourcePlatformImplementation</parameterValue>\n""
            + ""        <documentId>0</documentId>\n""
            + ""        <userVisible>false</userVisible>\n""
            + ""      </sourceParameter>\n""
            + ""      <sourceParameter>\n""
            + ""        <id>0</id>\n""
            + ""        <parameterTypeCode>TEXT</parameterTypeCode>\n""
            + ""        <parameterKey>USESCHEMA</parameterKey>\n""
            + ""        <parameterIndex>0</parameterIndex>\n""
            + ""        <parameterValue>true</parameterValue>\n""
            + ""        <documentId>0</documentId>\n""
            + ""        <userVisible>true</userVisible>\n""
            + ""      </sourceParameter>\n""
            + ""      <sourceParameter>\n""
            + ""        <id>0</id>\n""
            + ""        <parameterTypeCode>TEXT</parameterTypeCode>\n""
            + ""        <parameterKey>YF_DRIVER_SELECTION</parameterKey>\n""
            + ""        <parameterIndex>0</parameterIndex>\n""
            + ""        <parameterValue>org.postgresql.Driver</parameterValue>\n""
            + ""        <documentId>0</documentId>\n""
            + ""        <userVisible>true</userVisible>\n""
            + ""      </sourceParameter>\n""
            + ""    </sourceParameterList>\n""
            + ""  </source>\n""
            + ""  <translationDictionary/>\n""
            + ""  <refCodeDictionary/>\n""
            + ""</data>"";
}
C#
using System.Net.Http.Headers;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
 
namespace YellowfinAPIExamples
{
    public class ImportDatasourceForClientOrg
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine(""Import Datasource for Client"");
 
            string host = ""http://localhost:8080/Yellowfin"";
            string restUsername = ""admin@yellowfin.com.au"";
            string restPassword = ""test"";
 
            string tenantClientReferenceId = ""NEWCLIENT"";
            string databaseUserName = ""postgres"";
            string encryptedPassword = ""NDliYzg3NGItMDVjJVY8ywTSdIE3D1zdGplLLBUcEFqw"";
            string serverAddress = ""localhost"";
            string databaseName = ""testdata"";
 
            string token = await GenerateTokenForTenant(host, restUsername, restPassword, tenantClientReferenceId);
 
            int tenantId = await RetrieveTenantIpIdForTenantName(host, token, tenantClientReferenceId);
            Console.WriteLine(""Tenant Id: "" + tenantId);
 
            // Replace tokens with values
            string modifiedFileContents = ImportFileContents;
            modifiedFileContents = modifiedFileContents.Replace(""[USERNAME]"", databaseUserName)
                .Replace(""[TENANT_NAME]"", tenantClientReferenceId)
                .Replace(""[ENCRYPTED_PASSWORD]"", encryptedPassword)
                .Replace(""[SERVER_ADDRESS]"", serverAddress)
                .Replace(""[DATABASE_NAME]"", databaseName);
 
            using (var httpClient = new HttpClient())
            {
                var content = new MultipartFormDataContent
                {
                    {
                        new ByteArrayContent(Encoding.UTF8.GetBytes(modifiedFileContents)), ""contentToProcess"",
                        ""YFExport.xml""
                    },
                    {
                        new StringContent(
                            ""[{ \""itemIndex\"": 0, \""optionKey\"": \""SKIP\"", \""optionValue\"": false }, { \""itemIndex\"": 0, \""optionKey\"": \""OPTION\"", \""optionValue\"": \""ADD\"" }]"",
                            Encoding.UTF8, ""application/json""),
                        ""importOptions""
                    }
                };
 
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(""YELLOWFIN"",
                    ""ts="" + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + "" , nonce="" + new Random().NextInt64() +
                    "", token="" + token);
                httpClient.DefaultRequestHeaders.Accept.Add(
                    new MediaTypeWithQualityHeaderValue(""application/vnd.yellowfin.api-v1+json""));
                httpClient.DefaultRequestHeaders.Add(""cache-control"", ""no-cache"");
 
                HttpResponseMessage response =
                    await httpClient.PostAsync(host + ""/api/rpc/import-export/import-content"", content);
                string responseBody = await response.Content.ReadAsStringAsync();
                Console.WriteLine(responseBody);
            }
        }
 
        private static async Task<int> RetrieveTenantIpIdForTenantName(string host, string token, string tenantCode)
        {
            using (var httpClient = new HttpClient())
            {
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(""YELLOWFIN"",
                    ""ts="" + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + "" , nonce="" + new Random().NextInt64() +
                    "", token="" + token);
                httpClient.DefaultRequestHeaders.Accept.Add(
                    new MediaTypeWithQualityHeaderValue(""application/vnd.yellowfin.api-v1+json""));
 
                HttpResponseMessage response = await httpClient.GetAsync(host + ""/api/orgs"");
                string responseBody = await response.Content.ReadAsStringAsync();
 
                JObject jsonObject = JsonConvert.DeserializeObject<JObject>(responseBody);
                JArray groups = (JArray)jsonObject[""items""];
 
                foreach (var group in groups)
                {
                    if (group[""clientRefId""] != null && tenantCode == group[""clientRefId""].ToString())
                    {
                        return (int)group[""ipOrg""];
                    }
                }
 
                Console.WriteLine(""Tenant could not be found for code:"" + tenantCode);
                Environment.Exit(-1);
                return 0;
            }
        }
 
        private static async Task<string> GenerateTokenForTenant(string host, string username, string password,
            string tenant)
        {
            using (var client = new HttpClient())
            {
                var request = new HttpRequestMessage(HttpMethod.Post, host + ""/api/refresh-tokens"");
                request.Headers.Add(""Authorization"",
                    ""YELLOWFIN ts="" + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + "", nonce="" +
                    new Random().NextInt64());
                request.Headers.Add(""Accept"", ""application/vnd.yellowfin.api-v1+json"");
                request.Content = new StringContent(
                    JsonConvert.SerializeObject(new
                        { userName = username, password = password, clientOrgRef = tenant }),
                    Encoding.UTF8,
                    ""application/json""
                );
 
                HttpResponseMessage response = await client.SendAsync(request);
                string responseContent = await response.Content.ReadAsStringAsync();
 
                JObject jsonObject = JsonConvert.DeserializeObject<JObject>(responseContent);
                string accessToken = jsonObject[""_embedded""][""accessToken""][""securityToken""].ToString();
 
                if (!string.IsNullOrEmpty(accessToken))
                {
                    Console.WriteLine(""Access Token: "" + accessToken);
                }
                else
                {
                    Console.WriteLine(""Token not retrieved"");
                    Environment.Exit(-1);
                }
 
                return accessToken;
            }
        }
 
        private static readonly string ImportFileContents =
            @""<?xml version=""""1.0"""" encoding=""""UTF-8""""?><!-- Yellowfin export file --><!-- Generated at 2024-06-07 12:56 AEST (+1000) --><data>
              <info>
                <exportversion>4</exportversion>
                <exportsubversion>54</exportsubversion>
                <transferHeaderUUID>c072afce-d02a-4b2c-ae06-c3b62c8d6ea8</transferHeaderUUID>
                <appversion>9.11</appversion>
                <appsubversion>0.3</appsubversion>
                <buildversion>20240607</buildversion>
                <exportdate>2024-06-07 12:56 AEST (+1000)</exportdate>
                <systemid>9e/Rsd4Jf6UwZGq/5Q8Ej1Giviw=</systemid>
              </info>
              <source>
                <id>132641</id>
                <sourceName>PostgreSQL Connection for [TENANT_NAME]</sourceName>
                <sourceDescription>PostgreSQL Connection for [TENANT_NAME]</sourceDescription>
                <databasePath>public</databasePath>
                <userName>[USERNAME]</userName>
                <password>[ENCRYPTED_PASSWORD]</password>
                <connectionTypeCode>GENERICUSER</connectionTypeCode>
                <connectionMethodCode>JDBC</connectionMethodCode>
                <connectionDriver>org.postgresql.Driver</connectionDriver>
                <databaseURL>jdbc:postgresql://[SERVER_ADDRESS]:5432/[DATABASE_NAME]></databaseURL>
                <databaseTypeCode>POSTGRESQL</databaseTypeCode>
                <minConnections>1</minConnections>
                <maxConnections>5</maxConnections>
                <connectionRefreshTime>180</connectionRefreshTime>
                <connectionTimeOut>180</connectionTimeOut>
                <accessCode>UNSECURE</accessCode>
                <maxRowCount>10000</maxRowCount>
                <maxAnalysisRowCount>0</maxAnalysisRowCount>
                <broadcastPermitted>true</broadcastPermitted>
                <subscribePermitted>true</subscribePermitted>
                <dataProfileEnabled>true</dataProfileEnabled>
                <localTimezoneCode>AUSTRALIA/LORD_HOWE</localTimezoneCode>
                <secondaryMinConnections>0</secondaryMinConnections>
                <secondaryMaxConnections>0</secondaryMaxConnections>
                <secondaryConnectionRefreshTime>0</secondaryConnectionRefreshTime>
                <secondaryConnectionTimeOut>0</secondaryConnectionTimeOut>
                <lastModifiedGMTDateTime>20240607025556.000000</lastModifiedGMTDateTime>
                <sourceUUID>7d7543c0-e9c7-4a80-ab14-73181e4d0694</sourceUUID>
                <filterList/>
                <sourceParameterList>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>DATABASE</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>[DATABASE_NAME]</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>HOSTNAME</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>[SERVER_ADDRESS]</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>ISOLATIONLEVEL</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue/>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>PORT</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>5432</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>SOURCECLASSNAME</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>com.hof.sources.JDBCSourcePlatformImplementation</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>false</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>USESCHEMA</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>true</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>YF_DRIVER_SELECTION</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>org.postgresql.Driver</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                </sourceParameterList>
              </source>
              <translationDictionary/>
              <refCodeDictionary/>
            </data>"";
    }
}
Go
package main
 
import (
    ""bytes""
    ""encoding/json""
    ""fmt""
    ""io/ioutil""
    ""math/rand""
    ""mime/multipart""
    ""net/http""
    ""strings""
    ""time""
)
 
func main() {
    host := ""http://localhost:8080/Yellowfin""
    restUsername := ""admin@yellowfin.com.au""
    restPassword := ""test""
 
    tenantClientReferenceId := ""NEWCLIENT""
    databaseUserName := ""postgres""
    encryptedPassword := ""NDliYzg3NGItMDVjJVY8ywTSdIE3D1zdGplLLBUcEFqw""
    serverAddress := ""localhost""
    databaseName := ""testdata""
 
    token, err := generateToken(host, restUsername, restPassword, tenantClientReferenceId)
    if err != nil {
        fmt.Println(""Error generating token:"", err)
        return
    }
 
    tenantId, err := retrieveTenantIpIdForTenantName(host, token, tenantClientReferenceId)
    if err != nil {
        fmt.Println(""Error retrieving tenant ID:"", err)
        return
    }
    fmt.Println(""Tenant Id:"", tenantId)
 
    // Replace tokens with values
    modifiedFileContents := strings.Replace(importFileContents, ""[USERNAME]"", databaseUserName, -1)
    modifiedFileContents = strings.Replace(modifiedFileContents, ""[TENANT_NAME]"", tenantClientReferenceId, -1)
    modifiedFileContents = strings.Replace(modifiedFileContents, ""[ENCRYPTED_PASSWORD]"", encryptedPassword, -1)
    modifiedFileContents = strings.Replace(modifiedFileContents, ""[SERVER_ADDRESS]"", serverAddress, -1)
    modifiedFileContents = strings.Replace(modifiedFileContents, ""[DATABASE_NAME]"", databaseName, -1)
 
    bodyBuffer := &bytes.Buffer{}
    writer := multipart.NewWriter(bodyBuffer)
 
    // Add file content
    part, err := writer.CreateFormFile(""contentToProcess"", ""YFExport.xml"")
    if err != nil {
        fmt.Println(""Error creating form file:"", err)
        return
    }
    part.Write([]byte(modifiedFileContents))
 
    // Add text body
    err = writer.WriteField(""importOptions"", `[{""itemIndex"": 0, ""optionKey"": ""SKIP"", ""optionValue"": false}, {""itemIndex"": 0, ""optionKey"": ""OPTION"", ""optionValue"": ""ADD""}]`)
    if err != nil {
        fmt.Println(""Error writing field:"", err)
        return
    }
 
    writer.Close()
 
    client := &http.Client{}
    req, err := http.NewRequest(""POST"", host+""/api/rpc/import-export/import-content"", bodyBuffer)
    if err != nil {
        fmt.Println(""Error creating request:"", err)
        return
    }
 
    nonce := rand.Int63()
 
    req.Header.Set(""Authorization"", fmt.Sprintf(""YELLOWFIN ts=%d, nonce=%d, token=%s"", time.Now().UnixMilli(), nonce, token))
    req.Header.Set(""Accept"", ""application/vnd.yellowfin.api-v1+json"")
    req.Header.Set(""Content-Type"", writer.FormDataContentType())
    req.Header.Set(""cache-control"", ""no-cache"")
 
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println(""Error sending request:"", err)
        return
    }
    defer resp.Body.Close()
 
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(""Error reading response body:"", err)
        return
    }
 
    fmt.Println(string(body))
}
 
func generateToken(host, restUsername, restPassword, tenant string) (string, error) {
    nonce := rand.Int63()
 
    requestBody, err := json.Marshal(map[string]string{
        ""userName"":     restUsername,
        ""password"":     restPassword,
        ""clientOrgRef"": tenant,
    })
    if err != nil {
        fmt.Println(""Error marshaling request body:"", err)
        return """", err
    }
 
    client := &http.Client{}
    request, err := http.NewRequest(""POST"", host+""/api/refresh-tokens"", bytes.NewBuffer(requestBody))
    if err != nil {
        fmt.Println(""Error creating request:"", err)
        return """", err
    }
 
    request.Header.Set(""Authorization"", fmt.Sprintf(""YELLOWFIN ts=%d, nonce=%d"", time.Now().UnixMilli(), nonce))
    request.Header.Set(""Accept"", ""application/vnd.yellowfin.api-v1+json"")
    request.Header.Set(""Content-Type"", ""application/json"")
 
    response, err := client.Do(request)
    if err != nil {
        fmt.Println(""Error sending request:"", err)
        return """", err
    }
    defer response.Body.Close()
 
    responseBody, err := ioutil.ReadAll(response.Body)
    if err != nil {
        fmt.Println(""Error reading response body:"", err)
        return """", err
    }
 
    var jsonResponse map[string]interface{}
    err = json.Unmarshal(responseBody, &jsonResponse)
    if err != nil {
        fmt.Println(""Error parsing JSON response:"", err)
        return """", err
    }
 
    accessToken, ok := jsonResponse[""_embedded""].(map[string]interface{})[""accessToken""].(map[string]interface{})[""securityToken""].(string)
    if !ok {
        fmt.Println(""Token not retrieved"")
        return """", fmt.Errorf(""Token not retrieved successfully"")
    }
 
    return accessToken, nil
}
 
func retrieveTenantIpIdForTenantName(host, token, tenantCode string) (int, error) {
    client := &http.Client{}
    req, err := http.NewRequest(""GET"", host+""/api/orgs"", nil)
    if err != nil {
        return 0, err
    }
 
    nonce := rand.Int63()
 
    req.Header.Set(""Authorization"", fmt.Sprintf(""YELLOWFIN ts=%d, nonce=%d, token=%s"", time.Now().UnixMilli(), nonce, token))
    req.Header.Set(""Accept"", ""application/vnd.yellowfin.api-v1+json"")
    req.Header.Set(""Content-Type"", ""application/json"")
 
    resp, err := client.Do(req)
    if err != nil {
        return 0, err
    }
    defer resp.Body.Close()
 
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return 0, err
    }
 
    var jsonResponse map[string]interface{}
    err = json.Unmarshal(body, &jsonResponse)
    if err != nil {
        return 0, err
    }
 
    items, ok := jsonResponse[""items""].([]interface{})
    if !ok {
        return 0, fmt.Errorf(""Invalid response format"")
    }
 
    for _, item := range items {
        group, ok := item.(map[string]interface{})
        if !ok {
            continue
        }
 
        if group[""clientRefId""] == tenantCode {
            return int(group[""ipOrg""].(float64)), nil
        }
    }
 
    return 0, fmt.Errorf(""Tenant could not be found for code: %s"", tenantCode)
}
 
const importFileContents = `<?xml version=""1.0"" encoding=""UTF-8""?><!-- Yellowfin export file --><!-- Generated at 2024-06-07 12:56 AEST (+1000) --><data>
              <info>
                <exportversion>4</exportversion>
                <exportsubversion>54</exportsubversion>
                <transferHeaderUUID>c072afce-d02a-4b2c-ae06-c3b62c8d6ea8</transferHeaderUUID>
                <appversion>9.11</appversion>
                <appsubversion>0.3</appsubversion>
                <buildversion>20240607</buildversion>
                <exportdate>2024-06-07 12:56 AEST (+1000)</exportdate>
                <systemid>9e/Rsd4Jf6UwZGq/5Q8Ej1Giviw=</systemid>
              </info>
              <source>
                <id>132641</id>
                <sourceName>PostgreSQL Connection for [TENANT_NAME]</sourceName>
                <sourceDescription>PostgreSQL Connection for [TENANT_NAME]</sourceDescription>
                <databasePath>public</databasePath>
                <userName>[USERNAME]</userName>
                <password>[ENCRYPTED_PASSWORD]</password>
                <connectionTypeCode>GENERICUSER</connectionTypeCode>
                <connectionMethodCode>JDBC</connectionMethodCode>
                <connectionDriver>org.postgresql.Driver</connectionDriver>
                <databaseURL>jdbc:postgresql://[SERVER_ADDRESS]:5432/[DATABASE_NAME]></databaseURL>
                <databaseTypeCode>POSTGRESQL</databaseTypeCode>
                <minConnections>1</minConnections>
                <maxConnections>5</maxConnections>
                <connectionRefreshTime>180</connectionRefreshTime>
                <connectionTimeOut>180</connectionTimeOut>
                <accessCode>UNSECURE</accessCode>
                <maxRowCount>10000</maxRowCount>
                <maxAnalysisRowCount>0</maxAnalysisRowCount>
                <broadcastPermitted>true</broadcastPermitted>
                <subscribePermitted>true</subscribePermitted>
                <dataProfileEnabled>true</dataProfileEnabled>
                <localTimezoneCode>AUSTRALIA/LORD_HOWE</localTimezoneCode>
                <secondaryMinConnections>0</secondaryMinConnections>
                <secondaryMaxConnections>0</secondaryMaxConnections>
                <secondaryConnectionRefreshTime>0</secondaryConnectionRefreshTime>
                <secondaryConnectionTimeOut>0</secondaryConnectionTimeOut>
                <lastModifiedGMTDateTime>20240607025556.000000</lastModifiedGMTDateTime>
                <sourceUUID>7d7543c0-e9c7-4a80-ab14-73181e4d0694</sourceUUID>
                <filterList/>
                <sourceParameterList>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>DATABASE</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>[DATABASE_NAME]</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>HOSTNAME</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>[SERVER_ADDRESS]</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>ISOLATIONLEVEL</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue/>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>PORT</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>5432</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>SOURCECLASSNAME</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>com.hof.sources.JDBCSourcePlatformImplementation</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>false</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>USESCHEMA</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>true</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                  <sourceParameter>
                    <id>0</id>
                    <parameterTypeCode>TEXT</parameterTypeCode>
                    <parameterKey>YF_DRIVER_SELECTION</parameterKey>
                    <parameterIndex>0</parameterIndex>
                    <parameterValue>org.postgresql.Driver</parameterValue>
                    <documentId>0</documentId>
                    <userVisible>true</userVisible>
                  </sourceParameter>
                </sourceParameterList>
              </source>
              <translationDictionary/>
              <refCodeDictionary/>
            </data>
`
JavaScript
const fetch = require(""node-fetch"");
const FormData = require(""form-data"");
const { Buffer } = require('buffer');
 
async function main() {
    console.log(""Import Datasource for Client"");
 
    const host = ""http://localhost:8080/Yellowfin"";
    const restUsername = ""admin@yellowfin.com.au"";
    const restPassword = ""test"";
 
    const tenantClientReferenceId = ""NEWCLIENT"";
    const databaseUserName = ""postgres"";
    const encryptedPassword = ""NDliYzg3NGItMDVjJVY8ywTSdIE3D1zdGplLLBUcEFqw"";
    const serverAddress = ""localhost"";
    const databaseName = ""testdata"";
 
    const token = await generateTokenForTenant(host, restUsername, restPassword, tenantClientReferenceId);
 
    if (!token) {
        console.error(""Failed to retrieve access token"");
        return;
    }
 
    const tenantId = await retrieveTenantIpIdForTenantName(host, token, tenantClientReferenceId);
    console.log(""Tenant Id:"", tenantId);
 
    // Replace tokens with values
    let modifiedFileContents = importFileContents;
    modifiedFileContents = modifiedFileContents.replace(""[USERNAME]"", databaseUserName);
    modifiedFileContents = modifiedFileContents.replace(""[TENANT_NAME]"", tenantClientReferenceId);
    modifiedFileContents = modifiedFileContents.replace(""[ENCRYPTED_PASSWORD]"", encryptedPassword);
    modifiedFileContents = modifiedFileContents.replace(""[SERVER_ADDRESS]"", serverAddress);
    modifiedFileContents = modifiedFileContents.replace(""[DATABASE_NAME]"", databaseName);
 
    const formData = new FormData();
    formData.append('contentToProcess', Buffer.from(modifiedFileContents), { filename: 'YFExport.xml' });
    formData.append('importOptions', JSON.stringify([
        { itemIndex: 0, optionKey: ""SKIP"", optionValue: false },
        { itemIndex: 0, optionKey: ""OPTION"", optionValue: ""ADD"" }
    ]));
 
    const nonce = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
    const headers = {
        'Authorization': `YELLOWFIN ts=${Date.now()}, nonce=${nonce}, token=${token}`,
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'cache-control': 'no-cache'
    };
 
    try {
        const response = await fetch(`${host}/api/rpc/import-export/import-content`, {
            method: 'POST',
            headers: headers,
            body: formData
        });
 
        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }
 
        const responseBody = await response.text();
        console.log(responseBody);
    } catch (error) {
        console.error(""Error:"", error.message);
    }
}
 
async function retrieveTenantIpIdForTenantName(host, token, tenantCode) {
    const nonce = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
    const headers = {
        'Authorization': `YELLOWFIN ts=${Date.now()}, nonce=${nonce}, token=${token}`,
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'Content-Type': 'application/json'
    };
 
    try {
        const response = await fetch(`${host}/api/orgs`, {
            method: 'GET',
            headers: headers
        });
 
        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }
 
        const jsonResponse = await response.json();
        const groups = jsonResponse.items;
 
        for (const group of groups) {
            if (group.clientRefId && tenantCode === group.clientRefId) {
                return group.ipOrg;
            }
        }
 
        console.log(""Tenant could not be found for code:"", tenantCode);
        process.exit(-1);
    } catch (error) {
        console.error(""Error:"", error.message);
    }
 
    return null;
}
 
async function generateTokenForTenant(host, username, password, tenant) {
    const nonce = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
    const headers = {
        'Authorization': `YELLOWFIN ts=${Date.now()}, nonce=${nonce}`,
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'Content-Type': 'application/json'
    };
 
    const body = JSON.stringify({
        userName: username,
        password: password,
        clientOrgRef: tenant
    });
 
    try {
        const response = await fetch(`${host}/api/refresh-tokens`, {
            method: 'POST',
            headers: headers,
            body: body
        });
 
        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }
 
        const jsonResponse = await response.json();
        const accessToken = jsonResponse._embedded.accessToken.securityToken;
 
        if (accessToken) {
            console.log(`Access Token: ${accessToken}`);
            return accessToken;
        } else {
            console.log(""Token not retrieved successfully"");
            process.exit(-1);
        }
    } catch (error) {
        console.error(""Error:"", error.message);
    }
 
    return null;
}
 
const importFileContents = `<?xml version=""1.0"" encoding=""UTF-8""?><!-- Yellowfin export file --><!-- Generated at 2024-06-07 12:56 AEST (+1000) -->
<data>
    <info>
    <exportversion>4</exportversion>
    <exportsubversion>54</exportsubversion>
    <transferHeaderUUID>c072afce-d02a-4b2c-ae06-c3b62c8d6ea8</transferHeaderUUID>
    <appversion>9.11</appversion>
    <appsubversion>0.3</appsubversion>
    <buildversion>20240607</buildversion>
    <exportdate>2024-06-07 12:56 AEST (+1000)</exportdate>
    <systemid>9e/Rsd4Jf6UwZGq/5Q8Ej1Giviw=</systemid>
    </info>
    <source>
    <id>132641</id>
    <sourceName>PostgreSQL Connection for [TENANT_NAME]</sourceName>
    <sourceDescription>PostgreSQL Connection for [TENANT_NAME]</sourceDescription>
    <databasePath>public</databasePath>
    <userName>[USERNAME]</userName>
    <password>[ENCRYPTED_PASSWORD]</password>
    <connectionTypeCode>GENERICUSER</connectionTypeCode>
    <connectionMethodCode>JDBC</connectionMethodCode>
    <connectionDriver>org.postgresql.Driver</connectionDriver>
    <databaseURL>jdbc:postgresql://[SERVER_ADDRESS]:5432/[DATABASE_NAME]></databaseURL>
    <databaseTypeCode>POSTGRESQL</databaseTypeCode>
    <minConnections>1</minConnections>
    <maxConnections>5</maxConnections>
    <connectionRefreshTime>180</connectionRefreshTime>
    <connectionTimeOut>180</connectionTimeOut>
    <accessCode>UNSECURE</accessCode>
    <maxRowCount>10000</maxRowCount>
    <maxAnalysisRowCount>0</maxAnalysisRowCount>
    <broadcastPermitted>true</broadcastPermitted>
    <subscribePermitted>true</subscribePermitted>
    <dataProfileEnabled>true</dataProfileEnabled>
    <localTimezoneCode>AUSTRALIA/LORD_HOWE</localTimezoneCode>
    <secondaryMinConnections>0</secondaryMinConnections>
    <secondaryMaxConnections>0</secondaryMaxConnections>
    <secondaryConnectionRefreshTime>0</secondaryConnectionRefreshTime>
    <secondaryConnectionTimeOut>0</secondaryConnectionTimeOut>
    <lastModifiedGMTDateTime>20240607025556.000000</lastModifiedGMTDateTime>
    <sourceUUID>7d7543c0-e9c7-4a80-ab14-73181e4d0694</sourceUUID>
    <filterList/>
    <sourceParameterList>
        <sourceParameter>
        <id>0</id>
        <parameterTypeCode>TEXT</parameterTypeCode>
        <parameterKey>DATABASE</parameterKey>
        <parameterIndex>0</parameterIndex>
        <parameterValue>[DATABASE_NAME]</parameterValue>
        <documentId>0</documentId>
        <userVisible>true</userVisible>
        </sourceParameter>
        <sourceParameter>
        <id>0</id>
        <parameterTypeCode>TEXT</parameterTypeCode>
        <parameterKey>HOSTNAME</parameterKey>
        <parameterIndex>0</parameterIndex>
        <parameterValue>[SERVER_ADDRESS]</parameterValue>
        <documentId>0</documentId>
        <userVisible>true</userVisible>
        </sourceParameter>
        <sourceParameter>
        <id>0</id>
        <parameterTypeCode>TEXT</parameterTypeCode>
        <parameterKey>ISOLATIONLEVEL</parameterKey>
        <parameterIndex>0</parameterIndex>
        <parameterValue/>
        <documentId>0</documentId>
        <userVisible>true</userVisible>
        </sourceParameter>
        <sourceParameter>
        <id>0</id>
        <parameterTypeCode>TEXT</parameterTypeCode>
        <parameterKey>PORT</parameterKey>
        <parameterIndex>0</parameterIndex>
        <parameterValue>5432</parameterValue>
        <documentId>0</documentId>
        <userVisible>true</userVisible>
        </sourceParameter>
        <sourceParameter>
        <id>0</id>
        <parameterTypeCode>TEXT</parameterTypeCode>
        <parameterKey>SOURCECLASSNAME</parameterKey>
        <parameterIndex>0</parameterIndex>
        <parameterValue>com.hof.sources.JDBCSourcePlatformImplementation</parameterValue>
        <documentId>0</documentId>
        <userVisible>false</userVisible>
        </sourceParameter>
        <sourceParameter>
        <id>0</id>
        <parameterTypeCode>TEXT</parameterTypeCode>
        <parameterKey>USESCHEMA</parameterKey>
        <parameterIndex>0</parameterIndex>
        <parameterValue>true</parameterValue>
        <documentId>0</documentId>
        <userVisible>true</userVisible>
        </sourceParameter>
        <sourceParameter>
        <id>0</id>
        <parameterTypeCode>TEXT</parameterTypeCode>
        <parameterKey>YF_DRIVER_SELECTION</parameterKey>
        <parameterIndex>0</parameterIndex>
        <parameterValue>org.postgresql.Driver</parameterValue>
        <documentId>0</documentId>
        <userVisible>true</userVisible>
        </sourceParameter>
    </sourceParameterList>
    </source>
    <translationDictionary/>
    <refCodeDictionary/>
</data>
`;
 
main().catch(console.error);
PHP
<?php
function main($importFileContents) {
    $host = ""http://localhost:8080/Yellowfin"";
    $restUsername = ""admin@yellowfin.com.au"";
    $restPassword = ""test"";
 
    try {
        $token = generateTokenForTenant($host, $restUsername, $restPassword, ""NEWCLIENT"");
 
        $tenantClientReferenceId = ""NEWCLIENT"";
        $databaseUserName = ""postgres"";
        $encryptedPassword = ""NDliYzg3NGItMDVjJVY8ywTSdIE3D1zdGplLLBUcEFqw"";
        $serverAddress = ""localhost"";
        $databaseName = ""testdata"";
 
        // Replace tokens with values
        $modifiedFileContents = $importFileContents;
        $modifiedFileContents = str_replace(""[USERNAME]"", $databaseUserName, $modifiedFileContents);
        $modifiedFileContents = str_replace(""[TENANT_NAME]"", $tenantClientReferenceId, $modifiedFileContents);
        $modifiedFileContents = str_replace(""[ENCRYPTED_PASSWORD]"", $encryptedPassword, $modifiedFileContents);
        $modifiedFileContents = str_replace(""[SERVER_ADDRESS]"", $serverAddress, $modifiedFileContents);
        $modifiedFileContents = str_replace(""[DATABASE_NAME]"", $databaseName, $modifiedFileContents);
 
        // Build multipart entity
        $multipartEntity = buildMultipartEntity($modifiedFileContents);
 
        // Make HTTP request
        $response = sendMultipartRequest($host, $token, $multipartEntity);
        echo $response;
    } catch (Exception $e) {
        echo ""Error: "" . $e->getMessage();
    }
}
 
function generateTokenForTenant($host, $username, $password, $tenant) {
    // Generate nonce
    $nonce = mt_rand();
 
    // Create request body
    $requestBody = json_encode(array(
        ""userName"" => $username,
        ""password"" => $password,
        ""clientOrgRef"" => $tenant
    ));
 
    // Create request headers
    $headers = array(
        'Authorization: YELLOWFIN ts=' . intval(microtime(true) * 1000) . ', nonce=' . $nonce,
        'Accept: application/vnd.yellowfin.api-v1+json',
        'Content-Type: application/json'
    );
 
    $response = httpRequest('POST', ""$host/api/refresh-tokens"", $headers, $requestBody);
 
    // Parse JSON response
    $jsonResponse = json_decode($response, true);
 
    // Get access token from response
    if (isset($jsonResponse[""_embedded""][""accessToken""][""securityToken""])) {
        $accessToken = $jsonResponse[""_embedded""][""accessToken""][""securityToken""];
        echo ""Access Token: "" . $accessToken;
 
        return $accessToken;
    } else {
        throw new Exception(""Token not retrieved successfully"");
    }
}
 
function buildMultipartEntity($fileContents) {
    // Build multipart entity
    $boundary = uniqid();
 
    $multipartBody = ""--$boundary\r\n"";
    $multipartBody .= 'Content-Disposition: form-data; name=""contentToProcess""; filename=""YFExport.xml""' . ""\r\n"";
    $multipartBody .= ""Content-Type: application/xml\r\n\r\n"";
    $multipartBody .= $fileContents . ""\r\n"";
    $multipartBody .= ""--$boundary\r\n"";
    $multipartBody .= 'Content-Disposition: form-data; name=""importOptions""' . ""\r\n"";
    $multipartBody .= ""Content-Type: application/json\r\n\r\n"";
    $multipartBody .= '[{ ""itemIndex"": 0, ""optionKey"": ""SKIP"", ""optionValue"": false }, { ""itemIndex"": 0, ""optionKey"": ""OPTION"", ""optionValue"": ""ADD"" }]' . ""\r\n"";
    $multipartBody .= ""--$boundary--"";
 
    return $multipartBody;
}
 
function sendMultipartRequest($host, $token, $multipartBody) {
    $headers = array(
        'Authorization: YELLOWFIN ts=' . intval(microtime(true) * 1000) . ', nonce=' . mt_rand() . ', token=' . $token,
        'Accept: application/vnd.yellowfin.api-v1+json',
        'Content-Type: multipart/form-data; boundary=' . substr($multipartBody, 2, strpos($multipartBody, ""\r\n"") - 2),
        'cache-control: no-cache'
    );
 
    try {
        $response = httpRequest('POST', ""$host/api/rpc/import-export/import-content"", $headers, $multipartBody);
        return $response;
    } catch (Exception $e) {
        throw new Exception(""Error sending request: "" . $e->getMessage());
    }
}
 
function httpRequest($method, $url, $headers, $data = null) {
    $ch = curl_init();
 
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
 
    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    }
 
    $response = curl_exec($ch);
 
    if (curl_errno($ch)) {
        throw new Exception('Error: ' . curl_error($ch));
    }
 
    curl_close($ch);
 
    return $response;
}
 
$importFileContents = ""<?xml version=\""1.0\"" encoding=\""UTF-8\""?><!-- Yellowfin export file --><!-- Generated at 2024-06-07 12:56 AEST (+1000) -->
<data>
    <info>
    <exportversion>4</exportversion>
    <exportsubversion>54</exportsubversion>
    <transferHeaderUUID>c072afce-d02a-4b2c-ae06-c3b62c8d6ea8</transferHeaderUUID>
    <appversion>9.11</appversion>
    <appsubversion>0.3</appsubversion>
    <buildversion>20240607</buildversion>
    <exportdate>2024-06-07 12:56 AEST (+1000)</exportdate>
    <systemid>9e/Rsd4Jf6UwZGq/5Q8Ej1Giviw=</systemid>
    </info>
    <source>
    <id>132641</id>
    <sourceName>PostgreSQL Connection for [TENANT_NAME]</sourceName>
    <sourceDescription>PostgreSQL Connection for [TENANT_NAME]</sourceDescription>
    <databasePath>public</databasePath>
    <userName>[USERNAME]</userName>
    <password>[ENCRYPTED_PASSWORD]</password>
    <connectionTypeCode>GENERICUSER</connectionTypeCode>
    <connectionMethodCode>JDBC</connectionMethodCode>
    <connectionDriver>org.postgresql.Driver</connectionDriver>
    <databaseURL>jdbc:postgresql://[SERVER_ADDRESS]:5432/[DATABASE_NAME]></databaseURL>
    <databaseTypeCode>POSTGRESQL</databaseTypeCode>
    <minConnections>1</minConnections>
    <maxConnections>5</maxConnections>
    <connectionRefreshTime>180</connectionRefreshTime>
    <connectionTimeOut>180</connectionTimeOut>
    <accessCode>UNSECURE</accessCode>
    <maxRowCount>10000</maxRowCount>
    <maxAnalysisRowCount>0</maxAnalysisRowCount>
    <broadcastPermitted>true</broadcastPermitted>
    <subscribePermitted>true</subscribePermitted>
    <dataProfileEnabled>true</dataProfileEnabled>
    <localTimezoneCode>AUSTRALIA/LORD_HOWE</localTimezoneCode>
    <secondaryMinConnections>0</secondaryMinConnections>
    <secondaryMaxConnections>0</secondaryMaxConnections>
    <secondaryConnectionRefreshTime>0</secondaryConnectionRefreshTime>
    <secondaryConnectionTimeOut>0</secondaryConnectionTimeOut>
    <lastModifiedGMTDateTime>20240607025556.000000</lastModifiedGMTDateTime>
    <sourceUUID>7d7543c0-e9c7-4a80-ab14-73181e4d0694</sourceUUID>
    <filterList/>
    <sourceParameterList>
        <sourceParameter>
        <id>0</id>
        <parameterTypeCode>TEXT</parameterTypeCode>
        <parameterKey>DATABASE</parameterKey>
        <parameterIndex>0</parameterIndex>
        <parameterValue>[DATABASE_NAME]</parameterValue>
        <documentId>0</documentId>
        <userVisible>true</userVisible>
        </sourceParameter>
        <sourceParameter>
        <id>0</id>
        <parameterTypeCode>TEXT</parameterTypeCode>
        <parameterKey>HOSTNAME</parameterKey>
        <parameterIndex>0</parameterIndex>
        <parameterValue>[SERVER_ADDRESS]</parameterValue>
        <documentId>0</documentId>
        <userVisible>true</userVisible>
        </sourceParameter>
        <sourceParameter>
        <id>0</id>
        <parameterTypeCode>TEXT</parameterTypeCode>
        <parameterKey>ISOLATIONLEVEL</parameterKey>
        <parameterIndex>0</parameterIndex>
        <parameterValue/>
        <documentId>0</documentId>
        <userVisible>true</userVisible>
        </sourceParameter>
        <sourceParameter>
        <id>0</id>
        <parameterTypeCode>TEXT</parameterTypeCode>
        <parameterKey>PORT</parameterKey>
        <parameterIndex>0</parameterIndex>
        <parameterValue>5432</parameterValue>
        <documentId>0</documentId>
        <userVisible>true</userVisible>
        </sourceParameter>
        <sourceParameter>
        <id>0</id>
        <parameterTypeCode>TEXT</parameterTypeCode>
        <parameterKey>SOURCECLASSNAME</parameterKey>
        <parameterIndex>0</parameterIndex>
        <parameterValue>com.hof.sources.JDBCSourcePlatformImplementation</parameterValue>
        <documentId>0</documentId>
        <userVisible>false</userVisible>
        </sourceParameter>
        <sourceParameter>
        <id>0</id>
        <parameterTypeCode>TEXT</parameterTypeCode>
        <parameterKey>USESCHEMA</parameterKey>
        <parameterIndex>0</parameterIndex>
        <parameterValue>true</parameterValue>
        <documentId>0</documentId>
        <userVisible>true</userVisible>
        </sourceParameter>
        <sourceParameter>
        <id>0</id>
        <parameterTypeCode>TEXT</parameterTypeCode>
        <parameterKey>YF_DRIVER_SELECTION</parameterKey>
        <parameterIndex>0</parameterIndex>
        <parameterValue>org.postgresql.Driver</parameterValue>
        <documentId>0</documentId>
        <userVisible>true</userVisible>
        </sourceParameter>
    </sourceParameterList>
    </source>
    <translationDictionary/>
    <refCodeDictionary/>
</data>
"";
 
main($importFileContents);
?>
Python
import json
import random
import time
import requests
from requests.exceptions import RequestException
 
def main():
    host = ""http://localhost:8080/Yellowfin""
    rest_username = ""admin@yellowfin.com.au""
    rest_password = ""test""
 
    tenant_client_reference_id = ""NEWCLIENT""
    database_user_name = ""postgres""
    encrypted_password = ""NDliYzg3NGItMDVjJVY8ywTSdIE3D1zdGplLLBUcEFqw""
    server_address = ""localhost""
    database_name = ""testdata""
 
    try:
        token = generate_token(host, rest_username, rest_password, tenant_client_reference_id)
        tenant_id = retrieve_tenant_id_for_tenant_name(host, token, tenant_client_reference_id)
        print(""Tenant Id:"", tenant_id)
 
        # Replace tokens with values
        modified_file_contents = import_file_contents.replace(""[USERNAME]"", database_user_name) \
                                                     .replace(""[TENANT_NAME]"", tenant_client_reference_id) \
                                                     .replace(""[ENCRYPTED_PASSWORD]"", encrypted_password) \
                                                     .replace(""[SERVER_ADDRESS]"", server_address) \
                                                     .replace(""[DATABASE_NAME]"", database_name)
 
        multipart_entity = MultipartEncoder(
            fields={
                'contentToProcess': ('YFExport.xml', modified_file_contents, 'application/xml'),
                'importOptions': json.dumps([
                    {""itemIndex"": 0, ""optionKey"": ""SKIP"", ""optionValue"": False},
                    {""itemIndex"": 0, ""optionKey"": ""OPTION"", ""optionValue"": ""ADD""}
                ])
            }
        )
 
        headers = {
            'Authorization': f'YELLOWFIN ts={int(time.time() * 1000)}, nonce={random.randint(0, 2**63 - 1)}, token={token}',
            'Accept': 'application/vnd.yellowfin.api-v1+json',
            'Content-Type': multipart_entity.content_type,
            'cache-control': 'no-cache'
        }
 
        response = requests.post(f'{host}/api/rpc/import-export/import-content', headers=headers, data=multipart_entity.to_string())
 
        print(f""Content-Type: {multipart_entity.content_type}"")
        print(response.text)
 
    except RequestException as e:
        print(f""Request Exception: {e}"")
 
def generate_token(host, username, password, tenant):
    request_body = json.dumps({
        ""userName"": username,
        ""password"": password,
        ""clientOrgRef"": tenant
    })
 
    headers = {
        'Authorization': f'YELLOWFIN ts={int(time.time() * 1000)}, nonce={random.randint(0, 2**63 - 1)}',
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'Content-Type': 'application/json'
    }
 
    response = requests.post(f'{host}/api/refresh-tokens', headers=headers, data=request_body)
 
    if response.status_code == 200:
        json_response = response.json()
        access_token = json_response[""_embedded""][""accessToken""][""securityToken""]
        print(""Access Token:"", access_token)
        return access_token
    else:
        raise Exception(""Token not retrieved successfully"")
 
def retrieve_tenant_id_for_tenant_name(host, token, tenant_code):
    headers = {
        'Authorization': f'YELLOWFIN ts={int(time.time() * 1000)}, nonce={random.randint(0, 2**63 - 1)}, token={token}',
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'Content-Type': 'application/json'
    }
 
    response = requests.get(f'{host}/api/orgs', headers=headers)
 
    if response.status_code == 200:
        json_data = response.json()
        items = json_data.get('items', [])
 
        for item in items:
            if 'clientRefId' in item and item['clientRefId'] == tenant_code:
                return item['ipOrg']
 
        print(f""Tenant could not be found for code: {tenant_code}"")
        exit(-1)
 
    else:
        raise RequestException(f""Failed to retrieve tenant id. Status code: {response.status_code}"")
 
class MultipartEncoder:
    def __init__(self, fields):
        self.boundary = '----WebKitFormBoundary7MA4YWxkTrZu0gW'
        self.content_type = f'multipart/form-data; boundary={self.boundary}'
        self.data = self.encode(fields)
 
    def encode(self, fields):
        lines = []
 
        for key, value in fields.items():
            lines.append(f'--{self.boundary}')
            if isinstance(value, tuple):  # file data
                filename, data, content_type = value
                lines.append(f'Content-Disposition: form-data; name=""{key}""; filename=""{filename}""')
                lines.append(f'Content-Type: {content_type}')
                lines.append('')
                lines.append(data)
            else:  # regular form field
                lines.append(f'Content-Disposition: form-data; name=""{key}""')
                lines.append('')
                lines.append(value)
 
        lines.append(f'--{self.boundary}--')
        lines.append('')
        return '\r\n'.join(lines)
 
    def to_string(self):
        return self.data
 
import_file_contents = '''<?xml version=""1.0"" encoding=""UTF-8""?><!-- Yellowfin export file --><!-- Generated at 2024-06-07 12:56 AEST (+1000) -->
<data>
    <info>
    <exportversion>4</exportversion>
    <exportsubversion>54</exportsubversion>
    <transferHeaderUUID>c072afce-d02a-4b2c-ae06-c3b62c8d6ea8</transferHeaderUUID>
    <appversion>9.11</appversion>
    <appsubversion>0.3</appsubversion>
    <buildversion>20240607</buildversion>
    <exportdate>2024-06-07 12:56 AEST (+1000)</exportdate>
    <systemid>9e/Rsd4Jf6UwZGq/5Q8Ej1Giviw=</systemid>
    </info>
    <source>
    <id>132641</id>
    <sourceName>PostgreSQL Connection for [TENANT_NAME]</sourceName>
    <sourceDescription>PostgreSQL Connection for [TENANT_NAME]</sourceDescription>
    <databasePath>public</databasePath>
    <userName>[USERNAME]</userName>
    <password>[ENCRYPTED_PASSWORD]</password>
    <connectionTypeCode>GENERICUSER</connectionTypeCode>
    <connectionMethodCode>JDBC</connectionMethodCode>
    <connectionDriver>org.postgresql.Driver</connectionDriver>
    <databaseURL>jdbc:postgresql://[SERVER_ADDRESS]:5432/[DATABASE_NAME]></databaseURL>
    <databaseTypeCode>POSTGRESQL</databaseTypeCode>
    <minConnections>1</minConnections>
    <maxConnections>5</maxConnections>
    <connectionRefreshTime>180</connectionRefreshTime>
    <connectionTimeOut>180</connectionTimeOut>
    <accessCode>UNSECURE</accessCode>
    <maxRowCount>10000</maxRowCount>
    <maxAnalysisRowCount>0</maxAnalysisRowCount>
    <broadcastPermitted>true</broadcastPermitted>
    <subscribePermitted>true</subscribePermitted>
    <dataProfileEnabled>true</dataProfileEnabled>
    <localTimezoneCode>AUSTRALIA/LORD_HOWE</localTimezoneCode>
    <secondaryMinConnections>0</secondaryMinConnections>
    <secondaryMaxConnections>0</secondaryMaxConnections>
    <secondaryConnectionRefreshTime>0</secondaryConnectionRefreshTime>
    <secondaryConnectionTimeOut>0</secondaryConnectionTimeOut>
    <lastModifiedGMTDateTime>20240607025556.000000</lastModifiedGMTDateTime>
    <sourceUUID>7d7543c0-e9c7-4a80-ab14-73181e4d0694</sourceUUID>
    <filterList/>
    <sourceParameterList>
        <sourceParameter>
        <id>0</id>
        <parameterTypeCode>TEXT</parameterTypeCode>
        <parameterKey>DATABASE</parameterKey>
        <parameterIndex>0</parameterIndex>
        <parameterValue>[DATABASE_NAME]</parameterValue>
        <documentId>0</documentId>
        <userVisible>true</userVisible>
        </sourceParameter>
        <sourceParameter>
        <id>0</id>
        <parameterTypeCode>TEXT</parameterTypeCode>
        <parameterKey>HOSTNAME</parameterKey>
        <parameterIndex>0</parameterIndex>
        <parameterValue>[SERVER_ADDRESS]</parameterValue>
        <documentId>0</documentId>
        <userVisible>true</userVisible>
        </sourceParameter>
        <sourceParameter>
        <id>0</id>
        <parameterTypeCode>TEXT</parameterTypeCode>
        <parameterKey>ISOLATIONLEVEL</parameterKey>
        <parameterIndex>0</parameterIndex>
        <parameterValue/>
        <documentId>0</documentId>
        <userVisible>true</userVisible>
        </sourceParameter>
        <sourceParameter>
        <id>0</id>
        <parameterTypeCode>TEXT</parameterTypeCode>
        <parameterKey>PORT</parameterKey>
        <parameterIndex>0</parameterIndex>
        <parameterValue>5432</parameterValue>
        <documentId>0</documentId>
        <userVisible>true</userVisible>
        </sourceParameter>
        <sourceParameter>
        <id>0</id>
        <parameterTypeCode>TEXT</parameterTypeCode>
        <parameterKey>SOURCECLASSNAME</parameterKey>
        <parameterIndex>0</parameterIndex>
        <parameterValue>com.hof.sources.JDBCSourcePlatformImplementation</parameterValue>
        <documentId>0</documentId>
        <userVisible>false</userVisible>
        </sourceParameter>
        <sourceParameter>
        <id>0</id>
        <parameterTypeCode>TEXT</parameterTypeCode>
        <parameterKey>USESCHEMA</parameterKey>
        <parameterIndex>0</parameterIndex>
        <parameterValue>true</parameterValue>
        <documentId>0</documentId>
        <userVisible>true</userVisible>
        </sourceParameter>
        <sourceParameter>
        <id>0</id>
        <parameterTypeCode>TEXT</parameterTypeCode>
        <parameterKey>YF_DRIVER_SELECTION</parameterKey>
        <parameterIndex>0</parameterIndex>
        <parameterValue>org.postgresql.Driver</parameterValue>
        <documentId>0</documentId>
        <userVisible>true</userVisible>
        </sourceParameter>
    </sourceParameterList>
    </source>
    <translationDictionary/>
    <refCodeDictionary/>
</data>
'''
 
if __name__ == ""__main__"":
    main()

データソースサービス経由で新しいデータソースを作成

データソースは、POST /api/data-sources エンドポイント Create Data Source を使用して、REST API経由で直接作成することができます。

これは、こちらの形式のデータソースモデルを取ります。

{
   "sourceName": "Client Database",
   "sourceDescription": "",
   "sourceType": "POSTGRESQL",
   "connectionType": "JDBC",
   "connectionTypeCode": "GENERICUSER",
   "connectionDriver": "org.postgresql.Driver",
   "connectionString": "jdbc:postgresql://192.168.1.100:5432/testdata",
   "connectionTimeout": 180,
   "userName": "postgres",
   "minimumConnections": 1,
   "maximumConnections": 5,
   "refreshTime": 180,
   "timezone": "AUSTRALIA/SYDNEY",
   "accessLevelCode": "UNSECURE",
   "maxRows": 10000,
   "maxAnalysisRows": 0,
   "inheritChildSourceFilters": false,
   "sourceLogIndicator": false,
   "sourceOptions": [
        {
        "optionKey": "ISOLATIONLEVEL",
        "optionValue": "1.0",
        "valueDataType": "1"
        },
        {
        "optionKey": "USESCHEMA",
        "optionValue": "true",
        "valueDataType": "6"
        },
        {
        "optionKey": "HOSTNAME",
        "optionValue": "192.168.1.100",
        "valueDataType": "2"
        },
        {
        "optionKey": "PORT",
        "optionValue": "5432",
        "valueDataType": "1"
        },
        {
        "optionKey": "DATABASE",
        "optionValue": "testdata",
        "valueDataType": "2"
        },
        {
        "optionKey": "YF_DRIVER_SELECTION",
        "optionValue": "org.postgresql.Driver",
        "valueDataType": "2"
        }
    ]
}

モデルの本体は、GET /api/data-sources エンドポイントによって返されるモデルと似ています。プライマリー組織のデータソースと似た新しいソースを作成する場合は、GET /api/data-sources により返されるデータをテンプレートとして使用できます。

作成モデル内のsourceOptionsは、データベースの種類によって異なり、新しいデータソースに接続する際に接続ウィザードによって公開されるオプションの代表的なものです。

connectionString はモデル本体で使用できますが、データソースの作成時にソースオプションに基づいて再生成されることに注意してください。

以下の例では、POST /api/data-sources エンドポイントを使用して新しいデータソースを作成する方法を示しています。

Java
package rest.code.examples;
import java.io.IOException;
import java.util.Random;
import org.apache.hc.client5.http.fluent.Content;
import org.apache.hc.client5.http.fluent.Request;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
/**
* Create a datasource using the Yellowfin REST API
*/
public class CreateADataSource {
   public static void main(String[] args) throws Exception {
      
            String host = ""http://localhost:8080/yellowfinHead"";
            String restUsername = ""admin@yellowfin.com.au"";
            String restPassword = ""test"";
             
            String createDataSourcePayload = ""{\n""
                    + ""   \""sourceName\"": \""PostgreSQL Database Created Via Import\"",\n""
                    + ""   \""sourceDescription\"": \""\"",\n""
                    + ""   \""sourceType\"": \""POSTGRESQL\"",\n""
                    + ""   \""connectionType\"": \""JDBC\"",\n""
                    + ""   \""connectionTypeCode\"": \""GENERICUSER\"",\n""
                    + ""   \""connectionDriver\"": \""org.postgresql.Driver\"",\n""
                    + ""   \""connectionString\"": \""jdbc:postgresql://192.168.1.100:5432/testdata\"",\n""
                    + ""   \""connectionTimeout\"": 180,\n""
                    + ""   \""userName\"": \""postgres\"",\n""
                    + ""   \""minimumConnections\"": 1,\n""
                    + ""   \""maximumConnections\"": 5,\n""
                    + ""   \""refreshTime\"": 180,\n""
                    + ""   \""timezone\"": \""AUSTRALIA/SYDNEY\"",\n""
                    + ""   \""accessLevelCode\"": \""UNSECURE\"",\n""
                    + ""   \""maxRows\"": 10000,\n""
                    + ""   \""maxAnalysisRows\"": 0,\n""
                    + ""   \""inheritChildSourceFilters\"": false,\n""
                    + ""   \""sourceLogIndicator\"": false,\n""
                    + ""   \""sourceOptions\"": [\n""
                    + ""{\n""
                    + ""\""optionKey\"": \""ISOLATIONLEVEL\"",\n""
                    + ""\""optionValue\"": \""1.0\"",\n""
                    + ""\""valueDataType\"": \""1\""\n""
                    + ""},\n""
                    + ""{\n""
                    + ""\""optionKey\"": \""USESCHEMA\"",\n""
                    + ""\""optionValue\"": \""true\"",\n""
                    + ""\""valueDataType\"": \""6\""\n""
                    + ""},\n""
                    + ""{\n""
                    + ""\""optionKey\"": \""HOSTNAME\"",\n""
                    + ""\""optionValue\"": \""192.168.1.100\"",\n""
                    + ""\""valueDataType\"": \""2\""\n""
                    + ""},\n""
                    + ""{\n""
                    + ""\""optionKey\"": \""PORT\"",\n""
                    + ""\""optionValue\"": \""5432\"",\n""
                    + ""\""valueDataType\"": \""1\""\n""
                    + ""},\n""
                    + ""{\n""
                    + ""\""optionKey\"": \""DATABASE\"",\n""
                    + ""\""optionValue\"": \""testdata\"",\n""
                    + ""\""valueDataType\"": \""2\""\n""
                    + ""},\n""
                    + ""{\n""
                    + ""\""optionKey\"": \""YF_DRIVER_SELECTION\"",\n""
                    + ""\""optionValue\"": \""org.postgresql.Driver\"",\n""
                    + ""\""valueDataType\"": \""2\""\n""
                    + ""}\n""
                    + ""    ]\n""
                    + ""}""
                    ;
                                       
                     
             
             
            String token = generateToken(host, restUsername, restPassword);
             
            System.out.println(""Payload: "" + createDataSourcePayload);
             
            Content c = Request.post(host + ""/api/data-sources"")
                    .addHeader(""Authorization"", ""YELLOWFIN ts="" + System.currentTimeMillis() + "" , nonce="" + new Random().nextLong() + "", token="" + token)
                    .addHeader(""Accept"", ""application/vnd.yellowfin.api-v1+json"")
                    .addHeader(""Content-Type"", ""application/json"")
                    .bodyString(createDataSourcePayload, null)
                .execute().returnContent();
                 
        System.out.print(c.asString());
      
   }
   
   public static String generateToken(String host, String username, String password) throws IOException {
     
        Content c = Request.post(host + ""/api/refresh-tokens"")
                .addHeader(""Authorization"", ""YELLOWFIN ts="" + System.currentTimeMillis() + "" , nonce="" + new Random().nextLong())
                .addHeader(""Accept"", ""application/vnd.yellowfin.api-v1+json"")
                .addHeader(""Content-Type"", ""application/json"")
                .bodyString(""{ \""userName\"": \""""+ username + ""\"",\""password\"": \""""+ password + ""\""}"", null)
            .execute().returnContent();
             
        JsonObject jsonObject = new JsonParser().parse(c.asString()).getAsJsonObject();
        JsonElement accessToken = jsonObject.getAsJsonObject(""_embedded"").getAsJsonObject(""accessToken"").get(""securityToken"");
        
        if (accessToken!=null) {
                System.out.println(""Access Token: "" + accessToken);
        } else {
                System.out.println(""Token not retrieved successfully"");
                System.exit(-1);
        }
        return accessToken.getAsString();
     
   }
   
}
C#
using System.Net.Http.Headers;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
 
namespace YellowfinAPIExamples
{
    public class CreateADataSource
    {
        static async Task Main(string[] args)
        {
            string host = ""http://localhost:8080/Yellowfin"";
            string restUsername = ""admin@yellowfin.com.au"";
            string restPassword = ""test"";
 
            string createDataSourcePayload = @""
{
    """"sourceName"""": """"PostgreSQL Database Created Via Import"""",
    """"sourceDescription"""": """""""",
    """"sourceType"""": """"POSTGRESQL"""",
    """"connectionType"""": """"JDBC"""",
    """"connectionTypeCode"""": """"GENERICUSER"""",
    """"connectionDriver"""": """"org.postgresql.Driver"""",
    """"connectionString"""": """"jdbc:postgresql://192.168.1.100:5432/testdata"""",
    """"connectionTimeout"""": 180,
    """"userName"""": """"postgres"""",
    """"minimumConnections"""": 1,
    """"maximumConnections"""": 5,
    """"refreshTime"""": 180,
    """"timezone"""": """"AUSTRALIA/SYDNEY"""",
    """"accessLevelCode"""": """"UNSECURE"""",
    """"maxRows"""": 10000,
    """"maxAnalysisRows"""": 0,
    """"inheritChildSourceFilters"""": false,
    """"sourceLogIndicator"""": false,
    """"sourceOptions"""": [
        {
            """"optionKey"""": """"ISOLATIONLEVEL"""",
            """"optionValue"""": """"1.0"""",
            """"valueDataType"""": """"1""""
        },
        {
            """"optionKey"""": """"USESCHEMA"""",
            """"optionValue"""": """"true"""",
            """"valueDataType"""": """"6""""
        },
        {
            """"optionKey"""": """"HOSTNAME"""",
            """"optionValue"""": """"192.168.1.100"""",
            """"valueDataType"""": """"2""""
        },
        {
            """"optionKey"""": """"PORT"""",
            """"optionValue"""": """"5432"""",
            """"valueDataType"""": """"1""""
        },
        {
            """"optionKey"""": """"DATABASE"""",
            """"optionValue"""": """"testdata"""",
            """"valueDataType"""": """"2""""
        },
        {
            """"optionKey"""": """"YF_DRIVER_SELECTION"""",
            """"optionValue"""": """"org.postgresql.Driver"""",
            """"valueDataType"""": """"2""""
        }
    ]
}"";
 
            string token = await GenerateToken(host, restUsername, restPassword);
 
            Console.WriteLine(""Payload: "" + createDataSourcePayload);
 
            using (var httpClient = new HttpClient())
            {
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(""YELLOWFIN"", $""ts={DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}, nonce={new Random().NextInt64()}, token={token}"");
                httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(""application/vnd.yellowfin.api-v1+json""));
                var content = new StringContent(createDataSourcePayload, System.Text.Encoding.UTF8, ""application/json"");
 
                HttpResponseMessage response = await httpClient.PostAsync($""{host}/api/data-sources"", content);
                if (response.IsSuccessStatusCode)
                {
                    string responseBody = await response.Content.ReadAsStringAsync();
                    Console.WriteLine(responseBody);
                }
                else
                {
                    Console.WriteLine(""Failed to create data source. Status code: "" + response.StatusCode);
                }
            }
        }
 
        static async Task<string> GenerateToken(string host, string restUsername, string restPassword)
        {
            using (var client = new HttpClient())
            {
                // Generate nonce
                long nonce = new Random().NextInt64();
 
                // Create HTTP request
                var request = new HttpRequestMessage(HttpMethod.Post, $""{host}/api/refresh-tokens"");
                request.Headers.Add(""Authorization"", $""YELLOWFIN ts={DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}, nonce={nonce}"");
                request.Headers.Add(""Accept"", ""application/vnd.yellowfin.api-v1+json"");
                request.Content = new StringContent(
                    JsonConvert.SerializeObject(new { userName = restUsername, password = restPassword }),
                    System.Text.Encoding.UTF8,
                    ""application/json""
                );
 
                // Send request and get response
                HttpResponseMessage response = await client.SendAsync(request);
                string responseContent = await response.Content.ReadAsStringAsync();
 
                // Parse JSON response
                JObject jsonObject = JsonConvert.DeserializeObject<JObject>(responseContent);
                string accessToken = jsonObject[""_embedded""][""accessToken""][""securityToken""].ToString();
 
                if (!string.IsNullOrEmpty(accessToken))
                {
                    Console.WriteLine(""Access Token: "" + accessToken);
                }
                else
                {
                    Console.WriteLine(""Token not retrieved"");
                    Environment.Exit(-1);
                }
 
                return accessToken;
            }
        }
    }
}
Go
package main
 
import (
    ""bytes""
    ""encoding/json""
    ""fmt""
    ""io/ioutil""
    ""math/rand""
    ""net/http""
    ""time""
)
 
func main() {
    host := ""http://localhost:8080/Yellowfin""
    restUsername := ""admin@yellowfin.com.au""
    restPassword := ""test""
 
    createDataSourcePayload := `{
        ""sourceName"": ""PostgreSQL Database Created Via Import"",
        ""sourceDescription"": """",
        ""sourceType"": ""POSTGRESQL"",
        ""connectionType"": ""JDBC"",
        ""connectionTypeCode"": ""GENERICUSER"",
        ""connectionDriver"": ""org.postgresql.Driver"",
        ""connectionString"": ""jdbc:postgresql://192.168.1.100:5432/testdata"",
        ""connectionTimeout"": 180,
        ""userName"": ""postgres"",
        ""minimumConnections"": 1,
        ""maximumConnections"": 5,
        ""refreshTime"": 180,
        ""timezone"": ""AUSTRALIA/SYDNEY"",
        ""accessLevelCode"": ""UNSECURE"",
        ""maxRows"": 10000,
        ""maxAnalysisRows"": 0,
        ""inheritChildSourceFilters"": false,
        ""sourceLogIndicator"": false,
        ""sourceOptions"": [
            {
                ""optionKey"": ""ISOLATIONLEVEL"",
                ""optionValue"": ""1.0"",
                ""valueDataType"": ""1""
            },
            {
                ""optionKey"": ""USESCHEMA"",
                ""optionValue"": ""true"",
                ""valueDataType"": ""6""
            },
            {
                ""optionKey"": ""HOSTNAME"",
                ""optionValue"": ""192.168.1.100"",
                ""valueDataType"": ""2""
            },
            {
                ""optionKey"": ""PORT"",
                ""optionValue"": ""5432"",
                ""valueDataType"": ""1""
            },
            {
                ""optionKey"": ""DATABASE"",
                ""optionValue"": ""testdata"",
                ""valueDataType"": ""2""
            },
            {
                ""optionKey"": ""YF_DRIVER_SELECTION"",
                ""optionValue"": ""org.postgresql.Driver"",
                ""valueDataType"": ""2""
            }
        ]
    }`
 
    token, err := generateToken(host, restUsername, restPassword)
    if err != nil {
        fmt.Println(""Error generating token:"", err)
        return
    }
 
    fmt.Println(""Payload:"", createDataSourcePayload)
 
    client := &http.Client{}
    req, err := http.NewRequest(""POST"", host+""/api/data-sources"", bytes.NewBuffer([]byte(createDataSourcePayload)))
    if err != nil {
        fmt.Println(""Error creating request:"", err)
        return
    }
 
    nonce := rand.Int63()
 
    req.Header.Set(""Authorization"", fmt.Sprintf(""YELLOWFIN ts=%d, nonce=%d, token=%s"", time.Now().UnixMilli(), nonce, token))
    req.Header.Set(""Accept"", ""application/vnd.yellowfin.api-v1+json"")
    req.Header.Set(""Content-Type"", ""application/json"")
 
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println(""Error sending request:"", err)
        return
    }
    defer resp.Body.Close()
 
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(""Error reading response body:"", err)
        return
    }
 
    fmt.Println(string(body))
}
 
func generateToken(host, restUsername, restPassword string) (string, error) {
    nonce := rand.Int63()
 
    requestBody, err := json.Marshal(map[string]string{
        ""userName"": restUsername,
        ""password"": restPassword,
    })
    if err != nil {
        fmt.Println(""Error marshaling request body:"", err)
        return """", err
    }
 
    client := &http.Client{}
    req, err := http.NewRequest(""POST"", host+""/api/refresh-tokens"", bytes.NewBuffer(requestBody))
    if err != nil {
        fmt.Println(""Error creating request:"", err)
        return """", err
    }
 
    req.Header.Set(""Authorization"", fmt.Sprintf(""YELLOWFIN ts=%d, nonce=%d"", time.Now().UnixMilli(), nonce))
    req.Header.Set(""Accept"", ""application/vnd.yellowfin.api-v1+json"")
    req.Header.Set(""Content-Type"", ""application/json"")
 
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println(""Error sending request:"", err)
        return """", err
    }
    defer resp.Body.Close()
 
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(""Error reading response body:"", err)
        return """", err
    }
 
    var jsonResponse map[string]interface{}
    err = json.Unmarshal(body, &jsonResponse)
    if err != nil {
        fmt.Println(""Error parsing JSON response:"", err)
        return """", err
    }
 
    accessToken, ok := jsonResponse[""_embedded""].(map[string]interface{})[""accessToken""].(map[string]interface{})[""securityToken""].(string)
    if !ok {
        fmt.Println(""Token not retrieved"")
        return """", fmt.Errorf(""Token not retrieved successfully"")
    }
 
    return accessToken, nil
}
JavaScript
const fetch = require(""node-fetch"");
 
async function main() {
    const host = ""http://localhost:8080/Yellowfin"";
    const restUsername = ""admin@yellowfin.com.au"";
    const restPassword = ""test"";
 
    const createDataSourcePayload = `{
        ""sourceName"": ""PostgreSQL Database Created Via Import"",
        ""sourceDescription"": """",
        ""sourceType"": ""POSTGRESQL"",
        ""connectionType"": ""JDBC"",
        ""connectionTypeCode"": ""GENERICUSER"",
        ""connectionDriver"": ""org.postgresql.Driver"",
        ""connectionString"": ""jdbc:postgresql://192.168.1.100:5432/testdata"",
        ""connectionTimeout"": 180,
        ""userName"": ""postgres"",
        ""minimumConnections"": 1,
        ""maximumConnections"": 5,
        ""refreshTime"": 180,
        ""timezone"": ""AUSTRALIA/SYDNEY"",
        ""accessLevelCode"": ""UNSECURE"",
        ""maxRows"": 10000,
        ""maxAnalysisRows"": 0,
        ""inheritChildSourceFilters"": false,
        ""sourceLogIndicator"": false,
        ""sourceOptions"": [
            {
                ""optionKey"": ""ISOLATIONLEVEL"",
                ""optionValue"": ""1.0"",
                ""valueDataType"": ""1""
            },
            {
                ""optionKey"": ""USESCHEMA"",
                ""optionValue"": ""true"",
                ""valueDataType"": ""6""
            },
            {
                ""optionKey"": ""HOSTNAME"",
                ""optionValue"": ""192.168.1.100"",
                ""valueDataType"": ""2""
            },
            {
                ""optionKey"": ""PORT"",
                ""optionValue"": ""5432"",
                ""valueDataType"": ""1""
            },
            {
                ""optionKey"": ""DATABASE"",
                ""optionValue"": ""testdata"",
                ""valueDataType"": ""2""
            },
            {
                ""optionKey"": ""YF_DRIVER_SELECTION"",
                ""optionValue"": ""org.postgresql.Driver"",
                ""valueDataType"": ""2""
            }
        ]
    }`;
 
    const token = await generateToken(host, restUsername, restPassword);
 
    if (!token) {
        console.error(""Failed to retrieve access token"");
        return;
    }
 
    console.log(""Payload:"", createDataSourcePayload);
 
    const nonce = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
 
    const headers = {
        'Authorization': `YELLOWFIN ts=${Date.now()}, nonce=${nonce}, token=${token}`,
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'Content-Type': 'application/json'
    };
 
    try {
        const response = await fetch(`${host}/api/data-sources`, {
            method: 'POST',
            headers: headers,
            body: createDataSourcePayload
        });
 
        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }
 
        const responseBody = await response.text();
        console.log(responseBody);
    } catch (error) {
        console.error(""Error:"", error.message);
    }
}
 
async function generateToken(host, restUsername, restPassword) {
    const nonce = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
 
    const headers = {
        'Authorization': `YELLOWFIN ts=${Date.now()}, nonce=${nonce}`,
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'Content-Type': 'application/json'
    };
 
    const body = JSON.stringify({
        userName: restUsername,
        password: restPassword
    });
 
    try {
        const response = await fetch(`${host}/api/refresh-tokens`, {
            method: 'POST',
            headers: headers,
            body: body
        });
 
        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }
 
        const jsonResponse = await response.json();
        const accessToken = jsonResponse._embedded.accessToken.securityToken;
 
        if (accessToken) {
            console.log(`Access Token: ${accessToken}`);
        } else {
            console.log(""Token not retrieved"");
        }
 
        return accessToken;
    } catch (error) {
        console.error(""Error:"", error.message);
    }
 
    return null;
}
 
main();
PHP
<?php
function main() {
    $host = ""http://localhost:8080/Yellowfin"";
    $restUsername = ""admin@yellowfin.com.au"";
    $restPassword = ""test"";
 
    $createDataSourcePayload = '{
        ""sourceName"": ""PostgreSQL Database Created Via Import"",
        ""sourceDescription"": """",
        ""sourceType"": ""POSTGRESQL"",
        ""connectionType"": ""JDBC"",
        ""connectionTypeCode"": ""GENERICUSER"",
        ""connectionDriver"": ""org.postgresql.Driver"",
        ""connectionString"": ""jdbc:postgresql://192.168.1.100:5432/testdata"",
        ""connectionTimeout"": 180,
        ""userName"": ""postgres"",
        ""minimumConnections"": 1,
        ""maximumConnections"": 5,
        ""refreshTime"": 180,
        ""timezone"": ""AUSTRALIA/SYDNEY"",
        ""accessLevelCode"": ""UNSECURE"",
        ""maxRows"": 10000,
        ""maxAnalysisRows"": 0,
        ""inheritChildSourceFilters"": false,
        ""sourceLogIndicator"": false,
        ""sourceOptions"": [
            {
                ""optionKey"": ""ISOLATIONLEVEL"",
                ""optionValue"": ""1.0"",
                ""valueDataType"": ""1""
            },
            {
                ""optionKey"": ""USESCHEMA"",
                ""optionValue"": ""true"",
                ""valueDataType"": ""6""
            },
            {
                ""optionKey"": ""HOSTNAME"",
                ""optionValue"": ""192.168.1.100"",
                ""valueDataType"": ""2""
            },
            {
                ""optionKey"": ""PORT"",
                ""optionValue"": ""5432"",
                ""valueDataType"": ""1""
            },
            {
                ""optionKey"": ""DATABASE"",
                ""optionValue"": ""testdata"",
                ""valueDataType"": ""2""
            },
            {
                ""optionKey"": ""YF_DRIVER_SELECTION"",
                ""optionValue"": ""org.postgresql.Driver"",
                ""valueDataType"": ""2""
            }
        ]
    }';
 
    try {
        $token = generateToken($host, $restUsername, $restPassword);
    } catch (Exception $e) {
        echo ""Error generating token: "" . $e->getMessage();
        return;
    }
 
    echo ""Payload: "" . $createDataSourcePayload . ""\n"";
 
    $nonce = mt_rand();
    $headers = array(
        'Authorization: YELLOWFIN ts=' . intval(microtime(true) * 1000) . ', nonce=' . $nonce . ', token=' . $token,
        'Accept: application/vnd.yellowfin.api-v1+json',
        'Content-Type: application/json'
    );
 
    try {
        $response = httpRequest('POST', ""$host/api/data-sources"", $headers, $createDataSourcePayload);
        echo $response;
    } catch (Exception $e) {
        echo ""Error sending request: "" . $e->getMessage();
    }
}
 
function generateToken($host, $restUsername, $restPassword) {
    // Generate nonce
    $nonce = mt_rand();
 
    // Create request body
    $requestBody = json_encode(array(
        ""userName"" => $restUsername,
        ""password"" => $restPassword
    ));
 
    // Create request headers
    $headers = array(
        'Authorization: YELLOWFIN ts=' . intval(microtime(true) * 1000) . ', nonce=' . $nonce,
        'Accept: application/vnd.yellowfin.api-v1+json',
        'Content-Type: application/json'
    );
 
    $response = httpRequest('POST', ""$host/api/refresh-tokens"", $headers, $requestBody);
 
    // Parse JSON response
    $jsonResponse = json_decode($response, true);
 
    // Get access token from response
    if (isset($jsonResponse[""_embedded""][""accessToken""][""securityToken""])) {
        $accessToken = $jsonResponse[""_embedded""][""accessToken""][""securityToken""];
        echo ""Access Token: "" . $accessToken;
 
        return $accessToken;
    } else {
        throw new Exception(""Token not retrieved successfully"");
    }
}
 
function httpRequest($method, $url, $headers, $data = null) {
    $ch = curl_init();
 
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
 
    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    }
 
    $response = curl_exec($ch);
 
    if (curl_errno($ch)) {
        throw new Exception('Error: ' . curl_error($ch));
    }
 
    curl_close($ch);
 
    return $response;
}
 
main();
?>
Python
import json
import random
import time
import requests
 
def main():
    host = ""http://localhost:8080/Yellowfin""
    rest_username = ""admin@yellowfin.com.au""
    rest_password = ""test""
 
    create_data_source_payload = '''
    {
        ""sourceName"": ""PostgreSQL Database Created Via Import"",
        ""sourceDescription"": """",
        ""sourceType"": ""POSTGRESQL"",
        ""connectionType"": ""JDBC"",
        ""connectionTypeCode"": ""GENERICUSER"",
        ""connectionDriver"": ""org.postgresql.Driver"",
        ""connectionString"": ""jdbc:postgresql://192.168.1.100:5432/testdata"",
        ""connectionTimeout"": 180,
        ""userName"": ""postgres"",
        ""minimumConnections"": 1,
        ""maximumConnections"": 5,
        ""refreshTime"": 180,
        ""timezone"": ""AUSTRALIA/SYDNEY"",
        ""accessLevelCode"": ""UNSECURE"",
        ""maxRows"": 10000,
        ""maxAnalysisRows"": 0,
        ""inheritChildSourceFilters"": false,
        ""sourceLogIndicator"": false,
        ""sourceOptions"": [
            {
                ""optionKey"": ""ISOLATIONLEVEL"",
                ""optionValue"": ""1.0"",
                ""valueDataType"": ""1""
            },
            {
                ""optionKey"": ""USESCHEMA"",
                ""optionValue"": ""true"",
                ""valueDataType"": ""6""
            },
            {
                ""optionKey"": ""HOSTNAME"",
                ""optionValue"": ""192.168.1.100"",
                ""valueDataType"": ""2""
            },
            {
                ""optionKey"": ""PORT"",
                ""optionValue"": ""5432"",
                ""valueDataType"": ""1""
            },
            {
                ""optionKey"": ""DATABASE"",
                ""optionValue"": ""testdata"",
                ""valueDataType"": ""2""
            },
            {
                ""optionKey"": ""YF_DRIVER_SELECTION"",
                ""optionValue"": ""org.postgresql.Driver"",
                ""valueDataType"": ""2""
            }
        ]
    }
    '''
 
    try:
        token = generate_token(host, rest_username, rest_password)
    except Exception as e:
        print(f""Error generating token: {e}"")
        return
 
    print(""Payload:"", create_data_source_payload)
 
    nonce = random.randint(0, 2**63 - 1)
 
    headers = {
        'Authorization': f'YELLOWFIN ts={int(time.time() * 1000)}, nonce={nonce}, token={token}',
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'Content-Type': 'application/json'
    }
 
    try:
        response = requests.post(f""{host}/api/data-sources"", headers=headers, data=create_data_source_payload)
        response.raise_for_status()
        print(response.text)
    except requests.RequestException as e:
        print(f""Error sending request: {e}"")
 
def generate_token(host, rest_username, rest_password):
    nonce = random.randint(0, 2**63 - 1)
 
    # Create request body
    request_body = json.dumps({
        ""userName"": rest_username,
        ""password"": rest_password
    })
 
    # Create request headers
    headers = {
        'Authorization': f'YELLOWFIN ts={int(time.time() * 1000)}, nonce={nonce}',
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'Content-Type': 'application/json'
    }
 
    try:
        response = requests.post(f""{host}/api/refresh-tokens"", headers=headers, data=request_body)
        response.raise_for_status()
        json_response = response.json()
        access_token = json_response[""_embedded""][""accessToken""][""securityToken""]
        print(""Access Token:"", access_token)
        return access_token
    except requests.RequestException as e:
        raise Exception(""Token not retrieved successfully"") from e
 
if __name__ == ""__main__"":
    main()

データソースの一覧化

データソースの一覧は、GET /api/data-sources エンドポイント Get All Data Sources を使用することで取得できます。これは、以下の形式のデータソースモデルを返します。

{
            "sourceId": 132780,
            "sourceName": "PostgreSQL Connection for NEWCLIENT",
            "sourceDescription": "PostgreSQL Connection for NEWCLIENT",
            "sourceType": "POSTGRESQL",
            "connectionType": "JDBC",
            "connectionTypeCode": "GENERICUSER",
            "connectionDriver": "org.postgresql.Driver",
            "connectionPath": "public",
            "connectionString": "jdbc:postgresql://localhost:5432/testdata",
            "connectionTimeout": 180,
            "userName": "postgres",
            "minimumConnections": 1,
            "maximumConnections": 5,
            "refreshTime": 180,
            "timezone": "AUSTRALIA/LORD_HOWE",
            "accessLevelCode": "UNSECURE",
            "maxRows": 10000,
            "maxAnalysisRows": 0,
            "inheritChildSourceFilters": false,
            "sourceLogIndicator": false
}

こちらのサービスを使用して、指定されたデータソース名のデータソースの内部整数識別子 (sourceId) を検索できます。

以下のコード例は、システムからデータソースの一覧を取得する方法を示しています。

Java
package rest.code.examples;
import java.io.IOException;
import java.util.Random;
import org.apache.hc.client5.http.fluent.Content;
import org.apache.hc.client5.http.fluent.Request;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
/**
 * List DataSources using the Yellowfin REST API
 */
public class ListDataSources {
    public static void main(String[] args) throws Exception {
 
        System.out.print(""List Datasources"");
 
 
        String host = ""http://localhost:8080/Yellowfin"";
        String restUsername = ""admin@yellowfin.com.au"";
        String restPassword = ""test"";
 
        String token = generateToken(host, restUsername, restPassword);
 
        Content c = Request.get(host + ""/api/data-sources"")
                .addHeader(""Authorization"", ""YELLOWFIN ts="" + System.currentTimeMillis() + "" , nonce="" + new Random().nextLong() + "", token="" + token)
                .addHeader(""Accept"", ""application/vnd.yellowfin.api-v1+json"")
                .addHeader(""Content-Type"", ""application/json"")
                .execute().returnContent();
 
        System.out.print(c.asString());
 
    }
 
 
    /*
     *  This function generates an access token for a user that will grant them access to
     *  call REST API endpoints.
     */
 
    public static String generateToken(String host, String username, String password) throws IOException {
 
        Content c = Request.post(host + ""/api/refresh-tokens"")
                .addHeader(""Authorization"", ""YELLOWFIN ts="" + System.currentTimeMillis() + "" , nonce="" + new Random().nextLong())
                .addHeader(""Accept"", ""application/vnd.yellowfin.api-v1+json"")
                .addHeader(""Content-Type"", ""application/json"")
                .bodyString(""{ \""userName\"": \""""+ username + ""\"",\""password\"": \""""+ password + ""\""}"", null)
                .execute().returnContent();
 
        JsonObject jsonObject = new JsonParser().parse(c.asString()).getAsJsonObject();
        JsonElement accessToken = jsonObject.getAsJsonObject(""_embedded"").getAsJsonObject(""accessToken"").get(""securityToken"");
 
        if (accessToken!=null) {
            System.out.println(""Access Token: "" + accessToken);
        } else {
            System.out.println(""Token not retrieved successfully"");
            System.exit(-1);
        }
        return accessToken.getAsString();
 
    }
 
}
C#
using System.Net.Http.Headers;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
 
namespace YellowfinAPIExamples
{
    public class ListDataSources
    {
        static async Task Main(string[] args)
        {
            string host = ""http://localhost:8080/Yellowfin"";
            string restUsername = ""admin@yellowfin.com.au"";
            string restPassword = ""test"";
 
            string token = await GenerateToken(host, restUsername, restPassword);
 
            Console.WriteLine(""List Datasources"");
 
            using (var httpClient = new HttpClient())
            {
                long nonce = new Random().NextInt64();
 
                // Setup request headers
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(""YELLOWFIN"", $""ts={DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}, nonce={nonce}, token={token}"");
                httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(""application/vnd.yellowfin.api-v1+json""));
 
                // Make GET request to retrieve data sources
                HttpResponseMessage response = await httpClient.GetAsync($""{host}/api/data-sources"");
                if (response.IsSuccessStatusCode)
                {
                    string responseBody = await response.Content.ReadAsStringAsync();
                    Console.WriteLine(responseBody);
                }
                else
                {
                    Console.WriteLine($""Failed to retrieve data sources. Status code: {response.StatusCode}"");
                }
            }
        }
 
        static async Task<string> GenerateToken(string host, string username, string password)
        {
            using (var client = new HttpClient())
            {
                // Generate nonce
                long nonce = new Random().NextInt64();
 
                // Create HTTP request
                var request = new HttpRequestMessage(HttpMethod.Post, $""{host}/api/refresh-tokens"");
                request.Headers.Authorization = new AuthenticationHeaderValue(""YELLOWFIN"", $""ts={DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}, nonce={nonce}"");
                request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(""application/vnd.yellowfin.api-v1+json""));
                request.Content = new StringContent(
                    JsonConvert.SerializeObject(new { userName = username, password = password }),
                    System.Text.Encoding.UTF8,
                    ""application/json""
                );
 
                // Send request and get response
                HttpResponseMessage response = await client.SendAsync(request);
                string responseContent = await response.Content.ReadAsStringAsync();
 
                // Parse JSON response
                JObject jsonObject = JsonConvert.DeserializeObject<JObject>(responseContent);
                string accessToken = jsonObject[""_embedded""][""accessToken""][""securityToken""].ToString();
 
                if (!string.IsNullOrEmpty(accessToken))
                {
                    Console.WriteLine(""Access Token: "" + accessToken);
                }
                else
                {
                    Console.WriteLine(""Token not retrieved successfully"");
                    Environment.Exit(-1);
                }
 
                return accessToken;
            }
        }
    }
}
Go
package main
 
import (
    ""bytes""
    ""encoding/json""
    ""fmt""
    ""io/ioutil""
    ""math/rand""
    ""net/http""
    ""time""
)
 
func main() {
    host := ""http://localhost:8080/Yellowfin""
    restUsername := ""admin@yellowfin.com.au""
    restPassword := ""test""
 
    token, err := generateToken(host, restUsername, restPassword)
    if err != nil {
        fmt.Println(""Error generating token:"", err)
        return
    }
 
    fmt.Println(""List Datasources"")
 
    client := &http.Client{}
    req, err := http.NewRequest(""GET"", host+""/api/data-sources"", nil)
    if err != nil {
        fmt.Println(""Error creating request:"", err)
        return
    }
 
    nonce := rand.Int63()
 
    req.Header.Set(""Authorization"", fmt.Sprintf(""YELLOWFIN ts=%d, nonce=%d, token=%s"", time.Now().UnixMilli(), nonce, token))
    req.Header.Set(""Accept"", ""application/vnd.yellowfin.api-v1+json"")
    req.Header.Set(""Content-Type"", ""application/json"")
 
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println(""Error sending request:"", err)
        return
    }
    defer resp.Body.Close()
 
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(""Error reading response body:"", err)
        return
    }
 
    fmt.Println(string(body))
}
 
func generateToken(host, username, password string) (string, error) {
    // Generate nonce
    nonce := rand.Int63()
 
    // Create request body
    requestBody, err := json.Marshal(map[string]string{
        ""userName"": username,
        ""password"": password,
    })
    if err != nil {
        fmt.Println(""Error marshaling request body:"", err)
        return """", err
    }
 
    // Create HTTP client
    client := &http.Client{}
 
    // Create HTTP request
    request, err := http.NewRequest(""POST"", host+""/api/refresh-tokens"", bytes.NewBuffer(requestBody))
    if err != nil {
        fmt.Println(""Error creating request:"", err)
        return """", err
    }
 
    // Add request headers
    request.Header.Set(""Authorization"", fmt.Sprintf(""YELLOWFIN ts=%d, nonce=%d"", time.Now().UnixMilli(), nonce))
    request.Header.Set(""Accept"", ""application/vnd.yellowfin.api-v1+json"")
    request.Header.Set(""Content-Type"", ""application/json"")
 
    // Send HTTP request
    response, err := client.Do(request)
    if err != nil {
        fmt.Println(""Error sending request:"", err)
        return """", err
    }
    defer response.Body.Close()
 
    // Read response body
    responseBody, err := ioutil.ReadAll(response.Body)
    if err != nil {
        fmt.Println(""Error reading response body:"", err)
        return """", err
    }
 
    // Parse JSON response
    var jsonResponse map[string]interface{}
    err = json.Unmarshal(responseBody, &jsonResponse)
    if err != nil {
        fmt.Println(""Error parsing JSON response:"", err)
        return """", err
    }
 
    // Get access token from response
    accessToken, ok := jsonResponse[""_embedded""].(map[string]interface{})[""accessToken""].(map[string]interface{})[""securityToken""].(string)
    if !ok {
        fmt.Println(""Token not retrieved"")
        return """", fmt.Errorf(""Token not retrieved successfully"")
    }
 
    return accessToken, nil
}
JavaScript
const fetch = require(""node-fetch"");
 
async function main() {
    const host = ""http://localhost:8080/Yellowfin"";
    const restUsername = ""admin@yellowfin.com.au"";
    const restPassword = ""test"";
 
    const createUserPayload = JSON.stringify([{
        userId: ""user1"",
        emailAddress: ""user1@yellowfin.com.au"",
        roleCode: ""Consumer & Collaborator"",
        password: ""test"",
        firstName: ""User"",
        lastName: ""One"",
        languageCode: ""EN"",
        timeZoneCode: ""AUSTRALIA/SYDNEY""
    }]);
 
    const token = await generateToken(host, restUsername, restPassword);
 
    if (!token) {
        console.error(""Failed to retrieve access token"");
        return;
    }
 
    console.log(""Payload:"", createUserPayload);
 
    const nonce = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
 
    const headers = {
        'Authorization': `YELLOWFIN ts=${Date.now()}, nonce=${nonce}, token=${token}`,
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'Content-Type': 'application/json'
    };
 
    try {
        const response = await fetch(`${host}/api/data-sources`, {
            method: 'GET',
            headers: headers
        });
 
        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }
 
        const responseBody = await response.text();
        console.log(responseBody);
    } catch (error) {
        console.error(""Error:"", error.message);
    }
}
 
async function generateToken(host, restUsername, restPassword) {
    // Generate nonce
    const nonce = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
 
    // Create request headers
    const headers = {
        'Authorization': `YELLOWFIN ts=${Date.now()}, nonce=${nonce}`,
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'Content-Type': 'application/json'
    };
 
    // Create request body
    const body = JSON.stringify({
        userName: restUsername,
        password: restPassword
    });
 
    try {
        // Make POST request
        const response = await fetch(`${host}/api/refresh-tokens`, {
            method: 'POST',
            headers: headers,
            body: body
        });
 
        // Check if request was successful
        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }
 
        // Parse JSON response
        const jsonResponse = await response.json();
        const accessToken = jsonResponse._embedded.accessToken.securityToken;
 
        if (accessToken) {
            console.log(`Access Token: ${accessToken}`);
        } else {
            console.log(""Token not retrieved"");
        }
 
        return accessToken;
    } catch (error) {
        console.error(""Error:"", error.message);
    }
 
    return null;
}
 
main();
PHP
<?php
function main() {
    $host = ""http://localhost:8080/Yellowfin"";
    $restUsername = ""admin@yellowfin.com.au"";
    $restPassword = ""test"";
 
    $createUserPayload = json_encode(array(
        array(
            ""userId"" => ""user1"",
            ""emailAddress"" => ""user1@yellowfin.com.au"",
            ""roleCode"" => ""Consumer & Collaborator"",
            ""password"" => ""test"",
            ""firstName"" => ""User"",
            ""lastName"" => ""One"",
            ""languageCode"" => ""EN"",
            ""timeZoneCode"" => ""AUSTRALIA/SYDNEY""
        )
    ));
 
    try {
        $token = generateToken($host, $restUsername, $restPassword);
    } catch (Exception $e) {
        echo ""Error generating token: "" . $e->getMessage();
        return;
    }
 
    echo ""Payload: "" . $createUserPayload . ""\n"";
 
    $nonce = mt_rand();
    $headers = array(
        'Authorization: YELLOWFIN ts=' . intval(microtime(true) * 1000) . ', nonce=' . $nonce . ', token=' . $token,
        'Accept: application/vnd.yellowfin.api-v1+json',
        'Content-Type: application/json'
    );
 
    try {
        $response = httpRequest('GET', ""$host/api/data-sources"", $headers);
        echo $response;
    } catch (Exception $e) {
        echo ""Error listing data sources: "" . $e->getMessage();
    }
}
 
function generateToken($host, $restUsername, $restPassword) {
    // Generate nonce
    $nonce = mt_rand();
 
    // Create request body
    $requestBody = json_encode(array(
        ""userName"" => $restUsername,
        ""password"" => $restPassword
    ));
 
    // Create request headers
    $headers = array(
        'Authorization: YELLOWFIN ts=' . intval(microtime(true) * 1000) . ', nonce=' . $nonce,
        'Accept: application/vnd.yellowfin.api-v1+json',
        'Content-Type: application/json'
    );
 
    $response = httpRequest('POST', ""$host/api/refresh-tokens"", $headers, $requestBody);
 
    // Parse JSON response
    $jsonResponse = json_decode($response, true);
 
    // Get access token from response
    if (isset($jsonResponse[""_embedded""][""accessToken""][""securityToken""])) {
        $accessToken = $jsonResponse[""_embedded""][""accessToken""][""securityToken""];
        echo ""Access Token: "" . $accessToken;
 
        return $accessToken;
    } else {
        throw new Exception(""Token not retrieved successfully"");
    }
}
 
function httpRequest($method, $url, $headers, $data = null) {
    $ch = curl_init();
 
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
 
    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    }
 
    $response = curl_exec($ch);
 
    if (curl_errno($ch)) {
        throw new Exception('Error: ' . curl_error($ch));
    }
 
    curl_close($ch);
 
    return $response;
}
 
main();
?>
Python
import json
import random
import time
import requests
 
def main():
    host = ""http://localhost:8080/Yellowfin""
    rest_username = ""admin@yellowfin.com.au""
    rest_password = ""test""
 
    try:
        token = generate_token(host, rest_username, rest_password)
        list_data_sources(host, token)
    except Exception as e:
        print(f""Error: {e}"")
 
def list_data_sources(host, token):
    headers = {
        'Authorization': f'YELLOWFIN ts={int(time.time() * 1000)}, nonce={random.randint(0, 2**63 - 1)}, token={token}',
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'Content-Type': 'application/json'
    }
 
    try:
        response = requests.get(f'{host}/api/data-sources', headers=headers)
        response.raise_for_status()
        print(response.text)
    except requests.RequestException as e:
        print(f""Error listing data sources: {e}"")
 
def generate_token(host, username, password):
    nonce = random.randint(0, 2 ** 63 - 1)
 
    request_body = json.dumps({
        ""userName"": username,
        ""password"": password
    })
 
    headers = {
        'Authorization': f'YELLOWFIN ts={int(time.time() * 1000)}, nonce={nonce}',
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'Content-Type': 'application/json'
    }
 
    try:
        response = requests.post(f'{host}/api/refresh-tokens', headers=headers, data=request_body)
        response.raise_for_status()
        json_response = response.json()
        access_token = json_response[""_embedded""][""accessToken""][""securityToken""]
        print(""Access Token:"", access_token)
        return access_token
    except requests.RequestException as e:
        print(f""Token retrieval error: {e}"")
        raise Exception(""Token not retrieved successfully"")
 
if __name__ == ""__main__"":
    main()

ソース置換のためのクライアントデータソースのプライマリー組織データソースへの添付

クライアントデータソースは、POST /api/data-sources/{primaryOrgSourceId}/client-data-sources/?clientSourceId={clientOrgSourceId} エンドポイント Add Client Data Source を使用して、(ソース置換で使用するために) プライマリー組織データソースにリンクできます。

ここで、{primaryOrgSourceId} は、プライマリー組織データソースの整数識別子であり、{clientOrgSourceId} は、リンクするクライアント組織データソースの整数識別子です。

以下の例では、(名前で識別された) クライアントデータソースを、(名前で識別された) プライマリー組織データソースにリンクする方法を示しています。

Java
package rest.code.examples;
import java.io.IOException;
import java.util.Random;
import org.apache.hc.client5.http.fluent.Content;
import org.apache.hc.client5.http.fluent.Request;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
/**
 * Attach a Client Datasource to Primary Org Source for Source Substitution using the Yellowfin REST API
 */
public class AttachClientDatasourceToPrimarySource {
    public static void main(String[] args) throws Exception {
 
        System.out.print(""Attach a Tenant Source to Primary Org Source for Source Substitution"");
 
        String host = ""http://localhost:8080/Yellowfin"";
        String restUsername = ""admin@yellowfin.com.au"";
        String restPassword = ""test"";
 
        String primarySourceName = ""PostgreSQL Connection at Primary Org"";
        String clientSourceName = ""PostgreSQL Connection for NEWCLIENT"";
        String clientOrgReference = ""NEWCLIENT"";
 
        String clientToken = generateToken(host, restUsername, restPassword, clientOrgReference);
        Integer clientOrgSourceId = findDataSourceForSourceNameAtClient(host, clientToken, clientSourceName);
 
        System.out.println(""Client Org Source Id: "" + clientOrgSourceId);
 
        String primaryToken = generateToken(host, restUsername, restPassword, null);
        Integer primaryOrgSourceId = findDataSourceForSourceNameAtClient(host, primaryToken, primarySourceName);
 
        System.out.println(""Primary Org Source Id: "" + clientOrgSourceId);
 
        Content c = Request.get(host + ""/api/data-sources/"" + primaryOrgSourceId + ""/client-data-sources/?clientSourceId="" + clientOrgSourceId)
                .addHeader(""Authorization"", ""YELLOWFIN ts="" + System.currentTimeMillis() + "" , nonce="" + new Random().nextLong() + "", token="" + primaryToken)
                .addHeader(""Accept"", ""application/vnd.yellowfin.api-v1+json"")
                .addHeader(""Content-Type"", ""application/json"")
                .execute().returnContent();
 
        System.out.print(c.asString());
 
    }
 
    /*
     *  This function finds a datasource for a given datasource name
     *  call REST API endpoints.
     */
 
    private static Integer findDataSourceForSourceNameAtClient(String host, String token, String sourceName) throws IOException {
 
        Content c = Request.get(host + ""/api/data-sources"")
                .addHeader(""Authorization"", ""YELLOWFIN ts="" + System.currentTimeMillis() + "" , nonce="" + new Random().nextLong() + "", token="" + token)
                .addHeader(""Accept"", ""application/vnd.yellowfin.api-v1+json"")
                .addHeader(""Content-Type"", ""application/json"")
                .execute().returnContent();
 
        JsonObject jsonObject = new JsonParser().parse(c.asString()).getAsJsonObject();
        JsonElement sourceList = jsonObject.get(""items"");
        JsonArray sources = sourceList.getAsJsonArray();
 
        for (int i=0; i < sources.size(); i++ ) {
            JsonObject source = sources.getAsJsonArray().get(i).getAsJsonObject();
            if (sourceName.equals(source.get(""sourceName"").getAsString())) return source.get(""sourceId"").getAsInt();
        }
 
        System.out.println(""Data Source could not be found for name:"" + sourceName);
        System.exit(-1);
        return null;
 
    }
 
 
    /*
     *  This function generates an access token for a user that will grant them access to
     *  call REST API endpoints.
     */
 
    public static String generateToken(String host, String username, String password, String tenantClientOrgRefId) throws IOException {
 
        String tokenBody = ""{ \""userName\"": \""""+ username + ""\"",\""password\"": \""""+ password + ""\"""";
        if (tenantClientOrgRefId!=null) {
            tokenBody = tokenBody + "",\""clientOrgRef\"": \""""+ tenantClientOrgRefId + ""\"""";
        }
        tokenBody = tokenBody + ""}"";
 
        Content c = Request.post(host + ""/api/refresh-tokens"")
                .addHeader(""Authorization"", ""YELLOWFIN ts="" + System.currentTimeMillis() + "" , nonce="" + new Random().nextLong())
                .addHeader(""Accept"", ""application/vnd.yellowfin.api-v1+json"")
                .addHeader(""Content-Type"", ""application/json"")
                .bodyString(tokenBody, null)
                .execute().returnContent();
 
        JsonObject jsonObject = new JsonParser().parse(c.asString()).getAsJsonObject();
        JsonElement accessToken = jsonObject.getAsJsonObject(""_embedded"").getAsJsonObject(""accessToken"").get(""securityToken"");
 
        if (accessToken!=null) {
            System.out.println(""Access Token: "" + accessToken);
        } else {
            System.out.println(""Token not retrieved successfully"");
            System.exit(-1);
        }
        return accessToken.getAsString();
 
    }
 
}
C#
using System.Net.Http.Headers;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
 
namespace YellowfinAPIExamples
{
    public class AttachClientDatasourceToPrimarySource
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine(""Attach a Tenant Source to Primary Org Source for Source Substitution"");
 
            string host = ""http://localhost:8080/Yellowfin"";
            string restUsername = ""admin@yellowfin.com.au"";
            string restPassword = ""test"";
 
            string primarySourceName = ""PostgreSQL Connection at Primary Org"";
            string clientSourceName = ""PostgreSQL Connection for NEWCLIENT"";
            string clientOrgReference = ""NEWCLIENT"";
 
            string clientToken = await GenerateToken(host, restUsername, restPassword, clientOrgReference);
            int clientOrgSourceId = await FindDataSourceForSourceNameAtClient(host, clientToken, clientSourceName);
            Console.WriteLine(""Client Org Source Id: "" + clientOrgSourceId);
 
            string primaryToken = await GenerateToken(host, restUsername, restPassword, null);
            int primaryOrgSourceId = await FindDataSourceForSourceNameAtClient(host, primaryToken, primarySourceName);
            Console.WriteLine(""Primary Org Source Id: "" + primaryOrgSourceId);
 
            using (var httpClient = new HttpClient())
            {
                long nonce = new Random().NextInt64();
 
                // Setup request headers
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(""YELLOWFIN"", $""ts={DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}, nonce={nonce}, token={primaryToken}"");
                httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(""application/vnd.yellowfin.api-v1+json""));
 
                // Make GET request to attach client datasource to primary org source
                HttpResponseMessage response = await httpClient.GetAsync($""{host}/api/data-sources/{primaryOrgSourceId}/client-data-sources/?clientSourceId={clientOrgSourceId}"");
                if (response.IsSuccessStatusCode)
                {
                    string responseBody = await response.Content.ReadAsStringAsync();
                    Console.WriteLine(responseBody);
                }
                else
                {
                    Console.WriteLine($""Failed to attach client datasource. Status code: {response.StatusCode}"");
                }
            }
        }
 
        static async Task<int> FindDataSourceForSourceNameAtClient(string host, string token, string sourceName)
        {
            using (var httpClient = new HttpClient())
            {
                // Setup request headers
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(""YELLOWFIN"", $""ts={DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}, nonce={new Random().NextInt64()}, token={token}"");
                httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(""application/vnd.yellowfin.api-v1+json""));
 
                // Make GET request to fetch data sources
                HttpResponseMessage response = await httpClient.GetAsync($""{host}/api/data-sources"");
                if (response.IsSuccessStatusCode)
                {
                    string responseBody = await response.Content.ReadAsStringAsync();
 
                    // Parse JSON response
                    JObject jsonObject = JsonConvert.DeserializeObject<JObject>(responseBody);
                    JArray sources = jsonObject[""items""].ToObject<JArray>();
 
                    // Iterate through sources to find the correct one
                    foreach (JObject source in sources)
                    {
                        if (sourceName.Equals(source[""sourceName""].ToString(), StringComparison.OrdinalIgnoreCase))
                        {
                            return source[""sourceId""].ToObject<int>();
                        }
                    }
                }
 
                Console.WriteLine($""Data Source could not be found for name: {sourceName}"");
                Environment.Exit(-1);
                return -1; // Ideally unreachable, since Environment.Exit should terminate the process
            }
        }
 
        static async Task<string> GenerateToken(string host, string username, string password, string tenantClientOrgRefId)
        {
            using (var client = new HttpClient())
            {
                // Generate nonce
                long nonce = new Random().NextInt64();
 
                // Create HTTP request
                var request = new HttpRequestMessage(HttpMethod.Post, $""{host}/api/refresh-tokens"");
                request.Headers.Add(""Authorization"", $""YELLOWFIN ts={DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}, nonce={nonce}"");
                request.Headers.Add(""Accept"", ""application/vnd.yellowfin.api-v1+json"");
                request.Content = new StringContent(
                    JsonConvert.SerializeObject(new { userName = username, password = password, clientOrgRef = tenantClientOrgRefId }),
                    System.Text.Encoding.UTF8,
                    ""application/json""
                );
 
                // Send request and get response
                HttpResponseMessage response = await client.SendAsync(request);
                string responseContent = await response.Content.ReadAsStringAsync();
 
                // Parse JSON response
                JObject jsonObject = JsonConvert.DeserializeObject<JObject>(responseContent);
                string accessToken = jsonObject[""_embedded""][""accessToken""][""securityToken""].ToString();
 
                if (!string.IsNullOrEmpty(accessToken))
                {
                    Console.WriteLine(""Access Token: "" + accessToken);
                }
                else
                {
                    Console.WriteLine(""Token not retrieved successfully"");
                    Environment.Exit(-1);
                }
 
                return accessToken;
            }
        }
    }
}
Go
package main
 
import (
    ""bytes""
    ""encoding/json""
    ""fmt""
    ""io/ioutil""
    ""math/rand""
    ""net/http""
    ""time""
)
 
func main() {
    fmt.Println(""Attach a Tenant Source to Primary Org Source for Source Substitution"")
 
    host := ""http://localhost:8080/Yellowfin""
    restUsername := ""admin@yellowfin.com.au""
    restPassword := ""test""
 
    primarySourceName := ""PostgreSQL Connection at Primary Org""
    clientSourceName := ""PostgreSQL Connection for NEWCLIENT""
    clientOrgReference := ""NEWCLIENT""
 
    clientToken, err := generateToken(host, restUsername, restPassword, clientOrgReference)
    if err != nil {
        fmt.Println(""Error generating client token:"", err)
        return
    }
 
    clientOrgSourceId, err := findDataSourceForSourceNameAtClient(host, clientToken, clientSourceName)
    if err != nil {
        fmt.Println(""Error finding client data source:"", err)
        return
    }
    fmt.Println(""Client Org Source Id:"", clientOrgSourceId)
 
    primaryToken, err := generateToken(host, restUsername, restPassword, """")
    if err != nil {
        fmt.Println(""Error generating primary token:"", err)
        return
    }
 
    primaryOrgSourceId, err := findDataSourceForSourceNameAtClient(host, primaryToken, primarySourceName)
    if err != nil {
        fmt.Println(""Error finding primary data source:"", err)
        return
    }
    fmt.Println(""Primary Org Source Id:"", primaryOrgSourceId)
 
    client := &http.Client{}
    nonce := rand.Int63()
 
    req, err := http.NewRequest(""GET"", fmt.Sprintf(""%s/api/data-sources/%d/client-data-sources/?clientSourceId=%d"", host, primaryOrgSourceId, clientOrgSourceId), nil)
    if err != nil {
        fmt.Println(""Error creating request:"", err)
        return
    }
 
    req.Header.Set(""Authorization"", fmt.Sprintf(""YELLOWFIN ts=%d, nonce=%d, token=%s"", time.Now().UnixMilli(), nonce, primaryToken))
    req.Header.Set(""Accept"", ""application/vnd.yellowfin.api-v1+json"")
    req.Header.Set(""Content-Type"", ""application/json"")
 
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println(""Error sending request:"", err)
        return
    }
    defer resp.Body.Close()
 
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(""Error reading response body:"", err)
        return
    }
 
    fmt.Println(string(body))
}
 
func findDataSourceForSourceNameAtClient(host, token, sourceName string) (int, error) {
    client := &http.Client{}
    nonce := rand.Int63()
 
    req, err := http.NewRequest(""GET"", fmt.Sprintf(""%s/api/data-sources"", host), nil)
    if err != nil {
        return 0, fmt.Errorf(""Error creating request: %v"", err)
    }
 
    req.Header.Set(""Authorization"", fmt.Sprintf(""YELLOWFIN ts=%d, nonce=%d, token=%s"", time.Now().UnixMilli(), nonce, token))
    req.Header.Set(""Accept"", ""application/vnd.yellowfin.api-v1+json"")
    req.Header.Set(""Content-Type"", ""application/json"")
 
    resp, err := client.Do(req)
    if err != nil {
        return 0, fmt.Errorf(""Error sending request: %v"", err)
    }
    defer resp.Body.Close()
 
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return 0, fmt.Errorf(""Error reading response body: %v"", err)
    }
 
    var jsonResponse map[string]interface{}
    err = json.Unmarshal(body, &jsonResponse)
    if err != nil {
        return 0, fmt.Errorf(""Error parsing JSON response: %v"", err)
    }
 
    items := jsonResponse[""items""].([]interface{})
    for _, item := range items {
        source := item.(map[string]interface{})
        if sourceName == source[""sourceName""].(string) {
            sourceId := int(source[""sourceId""].(float64))
            return sourceId, nil
        }
    }
 
    return 0, fmt.Errorf(""Data Source could not be found for name: %s"", sourceName)
}
 
func generateToken(host, username, password, tenantClientOrgRefId string) (string, error) {
    nonce := rand.Int63()
 
    tokenBody := map[string]string{
        ""userName"": username,
        ""password"": password,
    }
    if tenantClientOrgRefId != """" {
        tokenBody[""clientOrgRef""] = tenantClientOrgRefId
    }
 
    requestBody, err := json.Marshal(tokenBody)
    if err != nil {
        return """", fmt.Errorf(""Error marshaling request body: %v"", err)
    }
 
    client := &http.Client{}
    req, err := http.NewRequest(""POST"", fmt.Sprintf(""%s/api/refresh-tokens"", host), bytes.NewBuffer(requestBody))
    if err != nil {
        return """", fmt.Errorf(""Error creating request: %v"", err)
    }
 
    req.Header.Set(""Authorization"", fmt.Sprintf(""YELLOWFIN ts=%d, nonce=%d"", time.Now().UnixMilli(), nonce))
    req.Header.Set(""Accept"", ""application/vnd.yellowfin.api-v1+json"")
    req.Header.Set(""Content-Type"", ""application/json"")
 
    resp, err := client.Do(req)
    if err != nil {
        return """", fmt.Errorf(""Error sending request: %v"", err)
    }
    defer resp.Body.Close()
 
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return """", fmt.Errorf(""Error reading response body: %v"", err)
    }
 
    var jsonResponse map[string]interface{}
    err = json.Unmarshal(body, &jsonResponse)
    if err != nil {
        return """", fmt.Errorf(""Error parsing JSON response: %v"", err)
    }
 
    embedded := jsonResponse[""_embedded""].(map[string]interface{})
    accessToken := embedded[""accessToken""].(map[string]interface{})[""securityToken""].(string)
 
    if accessToken == """" {
        return """", fmt.Errorf(""Token not retrieved successfully"")
    }
 
    fmt.Println(""Access Token:"", accessToken)
    return accessToken, nil
}
JavaScript
const fetch = require(""node-fetch"");
 
async function main() {
    console.log(""Attach a Tenant Source to Primary Org Source for Source Substitution"");
 
    const host = ""http://localhost:8080/Yellowfin"";
    const restUsername = ""admin@yellowfin.com.au"";
    const restPassword = ""test"";
 
    const primarySourceName = ""PostgreSQL Connection at Primary Org"";
    const clientSourceName = ""PostgreSQL Connection for NEWCLIENT"";
    const clientOrgReference = ""NEWCLIENT"";
 
    const clientToken = await generateToken(host, restUsername, restPassword, clientOrgReference);
    const clientOrgSourceId = await findDataSourceForSourceNameAtClient(host, clientToken, clientSourceName);
 
    console.log(""Client Org Source Id:"", clientOrgSourceId);
 
    const primaryToken = await generateToken(host, restUsername, restPassword, null);
    const primaryOrgSourceId = await findDataSourceForSourceNameAtClient(host, primaryToken, primarySourceName);
 
    console.log(""Primary Org Source Id:"", primaryOrgSourceId);
 
    const nonce = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
 
    const headers = {
        'Authorization': `YELLOWFIN ts=${Date.now()}, nonce=${nonce}, token=${primaryToken}`,
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'Content-Type': 'application/json'
    };
 
    try {
        const response = await fetch(`${host}/api/data-sources/${primaryOrgSourceId}/client-data-sources/?clientSourceId=${clientOrgSourceId}`, {
            method: 'GET',
            headers: headers
        });
 
        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }
 
        const responseBody = await response.text();
        console.log(responseBody);
    } catch (error) {
        console.error(""Error:"", error.message);
    }
}
 
async function findDataSourceForSourceNameAtClient(host, token, sourceName) {
    const nonce = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
 
    const headers = {
        'Authorization': `YELLOWFIN ts=${Date.now()}, nonce=${nonce}, token=${token}`,
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'Content-Type': 'application/json'
    };
 
    try {
        const response = await fetch(`${host}/api/data-sources`, {
            method: 'GET',
            headers: headers
        });
 
        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }
 
        const jsonResponse = await response.json();
        const sources = jsonResponse.items;
 
        for (let i = 0; i < sources.length; i++) {
            const source = sources[i];
            if (sourceName === source.sourceName) {
                return source.sourceId;
            }
        }
 
        console.log(""Data Source could not be found for name:"", sourceName);
        process.exit(-1); // Exit if data source not found
    } catch (error) {
        console.error(""Error:"", error.message);
        process.exit(-1); // Exit on error
    }
}
 
async function generateToken(host, username, password, tenantClientOrgRefId) {
    const nonce = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
 
    const headers = {
        'Authorization': `YELLOWFIN ts=${Date.now()}, nonce=${nonce}`,
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'Content-Type': 'application/json'
    };
 
    const requestBody = {
        userName: username,
        password: password
    };
 
    if (tenantClientOrgRefId !== null) {
        requestBody.clientOrgRef = tenantClientOrgRefId;
    }
 
    try {
        const response = await fetch(`${host}/api/refresh-tokens`, {
            method: 'POST',
            headers: headers,
            body: JSON.stringify(requestBody)
        });
 
        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }
 
        const jsonResponse = await response.json();
        const accessToken = jsonResponse._embedded.accessToken.securityToken;
 
        if (accessToken) {
            console.log(`Access Token: ${accessToken}`);
        } else {
            console.log(""Token not retrieved successfully"");
            process.exit(-1); // Exit if token not retrieved
        }
 
        return accessToken;
    } catch (error) {
        console.error(""Error:"", error.message);
        process.exit(-1); // Exit on error
    }
}
 
main();
PHP
<?php
 
function main() {
    $host = ""http://localhost:8080/Yellowfin"";
    $restUsername = ""admin@yellowfin.com.au"";
    $restPassword = ""test"";
 
    echo ""Attach a Tenant Source to Primary Org Source for Source Substitution\n"";
 
    $primarySourceName = ""PostgreSQL Connection at Primary Org"";
    $clientSourceName = ""PostgreSQL Connection for NEWCLIENT"";
    $clientOrgReference = ""NEWCLIENT"";
 
    try {
        $clientToken = generateToken($host, $restUsername, $restPassword, $clientOrgReference);
        $clientOrgSourceId = findDataSourceForSourceNameAtClient($host, $clientToken, $clientSourceName);
 
        echo ""Client Org Source Id: $clientOrgSourceId\n"";
 
        $primaryToken = generateToken($host, $restUsername, $restPassword, null);
        $primaryOrgSourceId = findDataSourceForSourceNameAtClient($host, $primaryToken, $primarySourceName);
 
        echo ""Primary Org Source Id: $primaryOrgSourceId\n"";
 
        $headers = [
            'Authorization: YELLOWFIN ts=' . intval(microtime(true) * 1000) . ', nonce=' . mt_rand() . ', token=' . $primaryToken,
            'Accept: application/vnd.yellowfin.api-v1+json',
            'Content-Type: application/json'
        ];
 
        $url = ""$host/api/data-sources/$primaryOrgSourceId/client-data-sources/?clientSourceId=$clientOrgSourceId"";
        $response = httpRequest('GET', $url, $headers);
 
        echo $response;
    } catch (Exception $e) {
        echo ""Error: "" . $e->getMessage();
    }
}
 
function generateToken($host, $restUsername, $restPassword, $tenantClientOrgRefId = null) {
    $nonce = mt_rand();
 
    $tokenBody = ""{ \""userName\"": \""$restUsername\"", \""password\"": \""$restPassword\"""";
    if ($tenantClientOrgRefId !== null) {
        $tokenBody .= "", \""clientOrgRef\"": \""$tenantClientOrgRefId\"""";
    }
    $tokenBody .= ""}"";
 
    $headers = [
        'Authorization: YELLOWFIN ts=' . intval(microtime(true) * 1000) . ', nonce=' . $nonce,
        'Accept: application/vnd.yellowfin.api-v1+json',
        'Content-Type: application/json'
    ];
 
    $response = httpRequest('POST', ""$host/api/refresh-tokens"", $headers, $tokenBody);
 
    $jsonResponse = json_decode($response, true);
 
    if (isset($jsonResponse[""_embedded""][""accessToken""][""securityToken""])) {
        return $jsonResponse[""_embedded""][""accessToken""][""securityToken""];
    } else {
        throw new Exception(""Token not retrieved successfully"");
    }
}
 
function findDataSourceForSourceNameAtClient($host, $token, $sourceName) {
    $headers = [
        'Authorization: YELLOWFIN ts=' . intval(microtime(true) * 1000) . ', nonce=' . mt_rand() . ', token=' . $token,
        'Accept: application/vnd.yellowfin.api-v1+json',
        'Content-Type: application/json'
    ];
 
    $response = httpRequest('GET', ""$host/api/data-sources"", $headers);
 
    $jsonObject = json_decode($response);
 
    if (isset($jsonObject->items)) {
        foreach ($jsonObject->items as $source) {
            if ($source->sourceName === $sourceName) {
                return $source->sourceId;
            }
        }
    }
 
    echo ""Data Source could not be found for name: $sourceName\n"";
    exit(-1);
}
 
function httpRequest($method, $url, $headers, $data = null) {
    $ch = curl_init();
 
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
 
    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    }
 
    $response = curl_exec($ch);
 
    if (curl_errno($ch)) {
        throw new Exception('Error: ' . curl_error($ch));
    }
 
    curl_close($ch);
 
    return $response;
}
 
main();
?>
Python
import random
import time
import requests
 
def main():
    print(""Attach a Tenant Source to Primary Org Source for Source Substitution"")
 
    host = ""http://localhost:8080/Yellowfin""
    rest_username = ""admin@yellowfin.com.au""
    rest_password = ""test""
 
    primary_source_name = ""PostgreSQL Connection at Primary Org""
    client_source_name = ""PostgreSQL Connection for NEWCLIENT""
    client_org_reference = ""NEWCLIENT""
 
    try:
        client_token = generate_token(host, rest_username, rest_password, client_org_reference)
        client_org_source_id = find_data_source_for_source_name_at_client(host, client_token, client_source_name)
        print(""Client Org Source Id:"", client_org_source_id)
 
        primary_token = generate_token(host, rest_username, rest_password, None)
        primary_org_source_id = find_data_source_for_source_name_at_client(host, primary_token, primary_source_name)
        print(""Primary Org Source Id:"", primary_org_source_id)
 
        headers = {
            'Authorization': f'YELLOWFIN ts={int(time.time() * 1000)}, nonce={random.randint(0, 2**63 - 1)}, token={primary_token}',
            'Accept': 'application/vnd.yellowfin.api-v1+json',
            'Content-Type': 'application/json'
        }
 
        url = f'{host}/api/data-sources/{primary_org_source_id}/client-data-sources/?clientSourceId={client_org_source_id}'
        response = requests.get(url, headers=headers)
        response.raise_for_status()
 
        print(response.text)
 
    except Exception as e:
        print(f""Error: {e}"")
 
def find_data_source_for_source_name_at_client(host, token, source_name):
    headers = {
        'Authorization': f'YELLOWFIN ts={int(time.time() * 1000)}, nonce={random.randint(0, 2**63 - 1)}, token={token}',
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'Content-Type': 'application/json'
    }
 
    url = f'{host}/api/data-sources'
    response = requests.get(url, headers=headers)
    response.raise_for_status()
 
    json_data = response.json()
    items = json_data.get('items', [])
 
    for source in items:
        if source['sourceName'] == source_name:
            return source['sourceId']
 
    raise Exception(f""Data Source could not be found for name: {source_name}"")
 
def generate_token(host, username, password, tenant_client_org_ref_id):
    body = {
        ""userName"": username,
        ""password"": password
    }
 
    if tenant_client_org_ref_id:
        body['clientOrgRef'] = tenant_client_org_ref_id
 
    headers = {
        'Authorization': f'YELLOWFIN ts={int(time.time() * 1000)}, nonce={random.randint(0, 2**63 - 1)}',
        'Accept': 'application/vnd.yellowfin.api-v1+json',
        'Content-Type': 'application/json'
    }
 
    response = requests.post(f'{host}/api/refresh-tokens', headers=headers, json=body)
    response.raise_for_status()
 
    json_response = response.json()
    access_token = json_response[""_embedded""][""accessToken""][""securityToken""]
    print(""Access Token:"", access_token)
 
    return access_token
 
if __name__ == ""__main__"":
    main()



  • No labels