Created
June 7, 2023 22:18
-
-
Save joshatxantie/1ac5a808dd732c165a5d21c8ee2a2c2d to your computer and use it in GitHub Desktop.
PowerBI Microsoft Service (Backend)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ---------------------------------------------------------------------------- | |
// Copyright (c) Microsoft Corporation. | |
// Licensed under the MIT license. | |
// ---------------------------------------------------------------------------- | |
const fetch = require("node-fetch"); | |
let adal = require("adal-node"); | |
const { | |
REACT_APP_TENANT_ID, | |
AZURE_APP_CLIENT_ID, | |
REACT_APP_AD_APPLICATION_ID, | |
AZURE_APP_CLIENT_SECRET, | |
} = process.env; | |
class PowerBiReportDetails { | |
constructor(reportId, reportName, embedUrl) { | |
this.reportId = reportId; | |
this.reportName = reportName; | |
this.embedUrl = embedUrl; | |
} | |
} | |
class EmbedConfig { | |
constructor(type, reportsDetail, embedToken) { | |
this.type = type; | |
this.reportsDetail = reportsDetail; | |
this.embedToken = embedToken; | |
} | |
} | |
/** | |
* Generate embed token and embed urls for reports | |
* @return Details like Embed URL, Access token and Expiry | |
*/ | |
async function getEmbedInfo(workspaceId, reportIds) { | |
// Get the Report Embed details | |
try { | |
// Get report details and embed token | |
const {reportEmbedConfig, headers} = await getEmbedParamsForMultipleReports( | |
workspaceId, | |
reportIds | |
); | |
return { | |
accessToken: reportEmbedConfig.embedToken.token, | |
embedUrl: reportEmbedConfig.reportsDetail, | |
expiry: reportEmbedConfig.embedToken.expiration, | |
headers, | |
status: 200, | |
}; | |
} catch (err) { | |
console.log(err); | |
return { | |
status: err.status, | |
error: `Error while retrieving report embed details\r\n${ | |
err.statusText | |
}\r\nRequestId: \n${err.headers.get("requestid")}`, | |
}; | |
} | |
} | |
/** | |
* Get embed params for a single report for a single workspace | |
* @param {string} workspaceId | |
* @param {string} reportId | |
* @param {string} additionalDatasetId - Optional Parameter | |
* @return EmbedConfig object | |
*/ | |
async function getEmbedParamsForSingleReport( | |
workspaceId, | |
reportId, | |
additionalDatasetId | |
) { | |
const reportInGroupApi = `https://api.powerbi.com/v1.0/myorg/groups/${workspaceId}/reports/${reportId}`; | |
const headers = await getRequestHeader(); | |
// Get report info by calling the PowerBI REST API | |
const result = await fetch(reportInGroupApi, { | |
method: "GET", | |
headers: headers, | |
}); | |
if (!result.ok) { | |
throw result; | |
} | |
// Convert result in json to retrieve values | |
const resultJson = await result.json(); | |
// Add report data for embedding | |
const reportDetails = new PowerBiReportDetails( | |
resultJson.id, | |
resultJson.name, | |
resultJson.embedUrl | |
); | |
const reportEmbedConfig = new EmbedConfig(); | |
// Create mapping for report and Embed URL | |
reportEmbedConfig.reportsDetail = [reportDetails]; | |
// Create list of datasets | |
let datasetIds = [resultJson.datasetId]; | |
// Append additional dataset to the list to achieve dynamic binding later | |
if (additionalDatasetId) { | |
datasetIds.push(additionalDatasetId); | |
} | |
// Get Embed token multiple resources | |
reportEmbedConfig.embedToken = | |
await getEmbedTokenForSingleReportSingleWorkspace( | |
reportId, | |
datasetIds, | |
workspaceId | |
); | |
return reportEmbedConfig; | |
} | |
/** | |
* Get embed params for multiple reports for a single workspace | |
* @param {string} workspaceId | |
* @param {Array<string>} reportIds | |
* @param {Array<string>} additionalDatasetIds - Optional Parameter | |
* @return EmbedConfig object | |
*/ | |
async function getEmbedParamsForMultipleReports( | |
workspaceId, | |
reportIds, | |
additionalDatasetIds | |
) { | |
// EmbedConfig object | |
const reportEmbedConfig = new EmbedConfig(); | |
// Create array of embedReports for mapping | |
reportEmbedConfig.reportsDetail = []; | |
// Create Array of datasets | |
let datasetIds = []; | |
let headers = null | |
// Get datasets and Embed URLs for all the reports | |
for (const reportId of reportIds) { | |
const reportInGroupApi = `https://api.powerbi.com/v1.0/myorg/groups/${workspaceId}/reports/${reportId}`; | |
headers = await getRequestHeader(); | |
// Get report info by calling the PowerBI REST API | |
const result = await fetch(reportInGroupApi, { | |
method: "GET", | |
headers: headers, | |
}); | |
if (!result.ok) { | |
throw result; | |
} | |
// Convert result in json to retrieve values | |
const resultJson = await result.json(); | |
// Store result into PowerBiReportDetails object | |
const reportDetails = new PowerBiReportDetails( | |
resultJson.id, | |
resultJson.name, | |
resultJson.embedUrl | |
); | |
// Create mapping for reports and Embed URLs | |
reportEmbedConfig.reportsDetail.push(reportDetails); | |
// Push datasetId of the report into datasetIds array | |
datasetIds.push(resultJson.datasetId); | |
} | |
// Append to existing list of datasets to achieve dynamic binding later | |
if (additionalDatasetIds) { | |
datasetIds.push(...additionalDatasetIds); | |
} | |
// Get Embed token multiple resources | |
reportEmbedConfig.embedToken = | |
await getEmbedTokenForMultipleReportsSingleWorkspace( | |
reportIds, | |
datasetIds, | |
workspaceId | |
); | |
return {reportEmbedConfig, headers}; | |
} | |
/** | |
* Get Embed token for single report, multiple datasets, and an optional target workspace | |
* @param {string} reportId | |
* @param {Array<string>} datasetIds | |
* @param {string} targetWorkspaceId - Optional Parameter | |
* @return EmbedToken | |
*/ | |
async function getEmbedTokenForSingleReportSingleWorkspace( | |
reportId, | |
datasetIds, | |
targetWorkspaceId | |
) { | |
// Add report id in the request | |
let formData = { | |
reports: [ | |
{ | |
id: reportId, | |
}, | |
], | |
datasets: [], | |
identities: [], | |
targetWorkspaces: [], | |
}; | |
// Add dataset ids in the request | |
for (const datasetId of datasetIds) { | |
formData["datasets"].push({ | |
id: datasetId, | |
}); | |
} | |
// Add targetWorkspace id in the request | |
if (targetWorkspaceId) { | |
formData["targetWorkspaces"].push({ | |
id: targetWorkspaceId, | |
}); | |
} | |
// if (identities) { | |
// formData['identities'] | |
// } | |
const embedTokenApi = "https://api.powerbi.com/v1.0/myorg/GenerateToken"; | |
const headers = await getRequestHeader(); | |
// Generate Embed token for single report, workspace, and multiple datasets. Refer https://aka.ms/MultiResourceEmbedToken | |
const result = await fetch(embedTokenApi, { | |
method: "POST", | |
headers: headers, | |
body: JSON.stringify(formData), | |
}); | |
if (!result.ok) throw result; | |
return result.json(); | |
} | |
/** | |
* Get Embed token for multiple reports, multiple datasets, and an optional target workspace | |
* @param {Array<string>} reportIds | |
* @param {Array<string>} datasetIds | |
* @param {String} targetWorkspaceId - Optional Parameter | |
* @return EmbedToken | |
*/ | |
async function getEmbedTokenForMultipleReportsSingleWorkspace( | |
reportIds, | |
datasetIds, | |
targetWorkspaceId | |
) { | |
// Add dataset ids in the request | |
let formData = { datasets: [] }; | |
for (const datasetId of datasetIds) { | |
formData["datasets"].push({ | |
id: datasetId, | |
}); | |
} | |
// Add report ids in the request | |
formData["reports"] = []; | |
for (const reportId of reportIds) { | |
formData["reports"].push({ | |
id: reportId, | |
}); | |
} | |
// Add targetWorkspace id in the request | |
if (targetWorkspaceId) { | |
formData["targetWorkspaces"] = []; | |
formData["targetWorkspaces"].push({ | |
id: targetWorkspaceId, | |
}); | |
} | |
// // Add report id in the request | |
// let formData = { | |
// 'reports': [{ | |
// 'id': reportId | |
// }], | |
// 'datasets': [], | |
// 'identities': [], | |
// 'targetWorkspaces': [], | |
// }; | |
// // Add dataset ids in the request | |
// for (const datasetId of datasetIds) { | |
// formData['datasets'].push({ | |
// 'id': datasetId | |
// }) | |
// } | |
// // Add targetWorkspace id in the request | |
// if (targetWorkspaceId) { | |
// formData['targetWorkspaces'].push({ | |
// 'id': targetWorkspaceId | |
// }) | |
// } | |
// if (identities) { | |
// formData['identities'] | |
// } | |
const embedTokenApi = "https://api.powerbi.com/v1.0/myorg/GenerateToken"; | |
const headers = await getRequestHeader(); | |
// Generate Embed token for multiple datasets, reports and single workspace. Refer https://aka.ms/MultiResourceEmbedToken | |
const result = await fetch(embedTokenApi, { | |
method: "POST", | |
headers: headers, | |
body: JSON.stringify(formData), | |
}); | |
if (!result.ok) throw result; | |
return result.json(); | |
} | |
/** | |
* Get Embed token for multiple reports, multiple datasets, and optional target workspaces | |
* @param {Array<string>} reportIds | |
* @param {Array<string>} datasetIds | |
* @param {Array<string>} targetWorkspaceIds - Optional Parameter | |
* @return EmbedToken | |
*/ | |
async function getEmbedTokenForMultipleReportsMultipleWorkspaces( | |
reportIds, | |
datasetIds, | |
targetWorkspaceIds | |
) { | |
// Note: This method is an example and is not consumed in this sample app | |
// Add dataset ids in the request | |
let formData = { datasets: [] }; | |
for (const datasetId of datasetIds) { | |
formData["datasets"].push({ | |
id: datasetId, | |
}); | |
} | |
// Add report ids in the request | |
formData["reports"] = []; | |
for (const reportId of reportIds) { | |
formData["reports"].push({ | |
id: reportId, | |
}); | |
} | |
// Add targetWorkspace ids in the request | |
if (targetWorkspaceIds) { | |
formData["targetWorkspaces"] = []; | |
for (const targetWorkspaceId of targetWorkspaceIds) { | |
formData["targetWorkspaces"].push({ | |
id: targetWorkspaceId, | |
}); | |
} | |
} | |
const embedTokenApi = "https://api.powerbi.com/v1.0/myorg/GenerateToken"; | |
const headers = await getRequestHeader(); | |
// Generate Embed token for multiple datasets, reports and workspaces. Refer https://aka.ms/MultiResourceEmbedToken | |
const result = await fetch(embedTokenApi, { | |
method: "POST", | |
headers: headers, | |
body: JSON.stringify(formData), | |
}); | |
if (!result.ok) throw result; | |
return result.json(); | |
} | |
/** | |
* Get Request header | |
* @return Request header with Bearer token | |
*/ | |
async function getRequestHeader() { | |
// Store authentication token | |
let tokenResponse; | |
// Store the error thrown while getting authentication token | |
let errorResponse; | |
// Get the response from the authentication request | |
try { | |
tokenResponse = await getAccessToken(); | |
} catch (err) { | |
if ( | |
err.hasOwnProperty("error_description") && | |
err.hasOwnProperty("error") | |
) { | |
errorResponse = err.error_description; | |
} else { | |
// Invalid PowerBI Username provided | |
errorResponse = err.toString(); | |
} | |
return { | |
status: 401, | |
error: errorResponse, | |
}; | |
} | |
// Extract AccessToken from the response | |
const token = tokenResponse.accessToken; | |
return { | |
"Content-Type": "application/json", | |
Authorization: getAuthHeader(token), | |
}; | |
} | |
// ---------------------------------------------------------------------------- | |
// Copyright (c) Microsoft Corporation. | |
// Licensed under the MIT license. | |
// ---------------------------------------------------------------------------- | |
function getAuthHeader(accessToken) { | |
// Function to append Bearer against the Access Token | |
return "Bearer ".concat(accessToken); | |
} | |
// ---------------------------------------------------------------------------- | |
// Copyright (c) Microsoft Corporation. | |
// Licensed under the MIT license. | |
// ---------------------------------------------------------------------------- | |
const getAccessToken = async function () { | |
let AuthenticationContext = adal.AuthenticationContext; | |
let authorityUrl = `https://login.microsoftonline.com/${REACT_APP_TENANT_ID}/v2.0`; | |
let context = new AuthenticationContext(authorityUrl); | |
return new Promise((resolve, reject) => { | |
context.acquireTokenWithClientCredentials( | |
"https://analysis.windows.net/powerbi/api", | |
REACT_APP_AD_APPLICATION_ID, | |
AZURE_APP_CLIENT_SECRET, | |
function (err, tokenResponse) { | |
// Function returns error object in tokenResponse | |
// Invalid Username will return empty tokenResponse, thus err is used | |
if (err) { | |
reject(tokenResponse == null ? err : tokenResponse); | |
} | |
console.log(tokenResponse); | |
resolve(tokenResponse); | |
} | |
); | |
}); | |
}; | |
module.exports = { | |
getAuthHeader: getAuthHeader, | |
getEmbedInfo: getEmbedInfo, | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment