Looking through Hapi's documentation, and trying to google, I can find how to setup a 404 page, but I cannot find anything about setting up a 500 page.
I tried adding an error handler like follows:
server.on('internalError', function (request, err) {
console.log("Internal Error:", err);
request.reply.view('errors/500', {
error: err
}).code(500);
});
But my hook never gets called. Is there an easy way to return a custom 500 page with Hapijs?
You need to trap the error response inside an onPreResponse extension function and set a new HTML response there.
The same principle applies to any Boom error, whether it be one set by you in a handler or set by hapi internally (e.g. a 404 Not found or a 401 Unauthorized from failed auth.
Here's an example that you can try yourself:
index.js
const Hapi = require('hapi');
const Path = require('path');
const server = new Hapi.Server();
server.connection({ port: 4000 });
server.route({
method: 'GET',
path: '/',
handler: function (request, reply) {
reply(new Error('I\'ll be a 500'));
}
});
server.ext('onPreResponse', (request, reply) => {
if (request.response.isBoom) {
const err = request.response;
const errName = err.output.payload.error;
const statusCode = err.output.payload.statusCode;
return reply.view('error', {
statusCode: statusCode,
errName: errName
})
.code(statusCode);
}
reply.continue();
});
server.register(require('vision'), (err) => {
if (err) {
throw err;
}
server.views({
engines: {
hbs: require('handlebars')
},
path: Path.join(__dirname, 'templates')
});
server.start((err) => {
if (err) {
throw err;
}
console.log('Server running at:', server.info.uri);
});
});
templates/error.hbs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{title}}</title>
<style>
body {
text-align: center;
background: #B0B0B0;
color: #222;
}
.error h1 {
font-size: 80px;
margin-bottom: 0;
}
</style>
</head>
<body>
<div class="error">
<h1>⚠<br/>{{statusCode}}</h1>
<h2>{{errName}}</h2>
</div>
</body>
</html>
Test it out by going to http://localhost:4000/ to see your custom error page:
This approach catches any Boom response, including those generated internally by hapi rather than by us. Therefore will also work with 4xx errors. Try navigating to http://localhost:4000/notapage and you'll get the same pretty page but for a 404:
For those looking for this answer compatible with Hapi v17+, the same code index.js code will be translated as:
index.js
"use strict";
const hapi = require('hapi');
const path = require('path');
const server = new hapi.Server({ port: 4000 });
server.route({
method: 'GET',
path: '/',
handler: (request, h) {
return new Error('I\'ll be a 500');
}
});
server.ext({
type: 'onPreResponse',
method: (request, h) => {
if (request.response.isBoom) {
const err = request.response;
const errName = err.output.payload.error;
const statusCode = err.output.payload.statusCode;
return h.view('error', {
statusCode: statusCode,
errName: errName
})
.code(statusCode);
}
return h.continue;
}
});
(async()=>{
await server.register([ require('#hapi/vision') ]);
server.views({
engines: { hbs: require('handlebars') },
path: Path.join(__dirname, 'templates')
});
await server.start();
return `Server running at: ${server.info.uri}`;
})().then(console.log).catch(console.error);
Related
On my server/index.js file I am trying to access aws-appsync queries as shown in THIS documentation of AWS GraphQL from NodeJS. What I am looking for is to access my prior created aws-appsync service to make a GQL query and get response accordingly. My Appsync access is also related to aws-cognito IAM user on schema. So I was trying to access appsync service by using aws-cognito IAM to get the data from the service itself. but getting error of
E:\myProjectName\node_modules\#aws-sdk\credential-provider-node\dist-cjs\defaultProvider.js:13
throw new property_provider_1.CredentialsProviderError("Could not load credentials from any providers", false);
^ CredentialsProviderError: Could not load credentials from any providers
at E:\myProjectName\node_modules\#aws-sdk\credential-provider-node\dist-cjs\defaultProvider.js:13:11
at E:\myProjectName\node_modules\#aws-sdk\credential-provider-node\node_modules\#aws-sdk\property-provider\dist-cjs\chain.js:11:28
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async coalesceProvider (E:\myProjectName\node_modules\#aws-sdk\credential-provider-node\node_modules\#aws-sdk\property-provider\dist-cjs\memoize.js:14:24)
at async SignatureV4.credentialProvider (E:\myProjectName\node_modules\#aws-sdk\credential-provider-node\node_modules\#aws-sdk\property-provider\dist-cjs\memoize.js:33:24)
at async SignatureV4.signRequest (E:\myProjectName\node_modules\#aws-sdk\signature-v4\dist-cjs\SignatureV4.js:86:29) at async handler (file:///E:/myProjectName/server/index.js:86:20) { tryNextLink: false }
Let me share my Code
import express from 'express';
const app = express();
import path from 'path';
const PORT = process.env.PORT || 3000;
import fs from 'fs';
import { fileURLToPath } from 'url';
import crypto from '#aws-crypto/sha256-js';
import { defaultProvider } from '#aws-sdk/credential-provider-node';
import { SignatureV4 } from '#aws-sdk/signature-v4';
import { HttpRequest } from '#aws-sdk/protocol-http';
import { default as fetch, Request } from 'node-fetch';
const { Sha256 } = crypto;
const GRAPHQL_ENDPOINT = 'https://myawsendpoint.amazonaws.com/graphql'
const AWS_REGION = 'us-east-1'
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
app.use(express.static(
path.resolve(__dirname, '..', 'build')
));
app.listen(PORT, (error) => {
if (error) {
return console.log('Error during app startup', error);
}
console.log("listening on " + PORT + "...");
});
const indexPath = path.resolve(__dirname, '..', 'build', 'index.html');
const query = `query MyQuery {
listCountrys {
items {
countryName
}
}
}
const handler = async (event) => {
console.log(`EVENT: ${JSON.stringify(event)}`);
const endpoint = new URL(GRAPHQL_ENDPOINT);
console.log("endpoint", endpoint)
const signer = new SignatureV4({
credentials: defaultProvider({ timeout: 2000, maxRetries: 2 }),
region: AWS_REGION,
service: 'appsync',
sha256: Sha256
});
const requestToBeSigned = new HttpRequest({
method: 'POST',
headers: {
'Content-Type': 'application/json',
host: endpoint.host
},
hostname: endpoint.host,
body: JSON.stringify({ query }),
path: endpoint.pathname
});
console.log("=== requestToBeSigned", requestToBeSigned)
const signed = await signer.sign(requestToBeSigned);
const request = new Request(endpoint, signed);
let statusCode = 200;
let body;
let response;
try {
response = await fetch(request);
body = await response.json();
console.log("=== body response", body)
if (body.errors)
statusCode = 400;
} catch (error) {
console.log("=== body response error", error)
statusCode = 500;
body = {
errors: [
{
message: error.message
}
]
};
}
return {
statusCode,
body: JSON.stringify(body)
};
}
app.get('^/public/posts/:id', (req, res, next) => {
handler()
});
});
Schema :
#aws_iam
#aws_cognito_user_pools
listCountrys(filter: ModelCountryFilterInput, limit: Int, nextToken: String): ModelCountryConnection
I don't know what I missed actually. I am providing exactly what was told on the documentation. Can anyone enlighten me please? Thanks in advance.
I faced the same issue with Nodemailer and AWS SES.
Anyone who is being redirected to this SO Question like I was, this work around might help.
import * as AWS from "aws-sdk";
import * as nodemailer from "nodemailer";
export const EmailService = async () => {
AWS.config.update({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
region: process.env.AWS_REGION,
});
const ses = new AWS.SES({ apiVersion: "****-**-**" });
const transporter = nodemailer.createTransport({
SES: ses,
});
try {
const response = await transporter.sendMail({
from: process.env.ADMIN_EMAIL,
to: userEmail,
subject: "Test Mail",
html: `
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<div style="padding:20px;">
<div style="max-width: 500px;">
<h2>Test Mail</h2>
<p>
Hi there,<br/><br/>
This is a test mail.
</p>
</div>
</div>
</body>
</html>
`,
});
if (response?.messageId) {
return {
status: true,
message: response?.messageId,
};
} else {
return {
status: false,
message: "Failed to send email",
};
}
} catch (error: any) {
return {
status: false,
message: error.message,
};
}
};
Here is the actual way of doing it https://nodemailer.com/transports/ses/
I am create a web app and using the Forge viewer to display my models, but when I upload and translate a 3D DWG model to svf for viewing I am only seeing 2D. It is a 3D DWG model, but the viewer is only displaying it as a 2D model instead. Is there something I'm missing within the viewer.html code? I can't seem to find where the mistake is.
viewer.html (Used from a sample project on github)
<!DOCTYPE html>
<html>
<head>
<title>Autodesk Forge: 3D Viewer App Sample</title>
<meta http-equiv="cache-control" content="max-age=0" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
<meta http-equiv="pragma" content="no-cache" />
<!-- Third Party package -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<!-- Autodesk Forge Viewer files (IMPORTANT) -->
<link rel="stylesheet" href="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/style.min.css"
type="text/css" />
<script src="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/viewer3D.min.js"></script>
<style>
/** Just simple CSS styling to make this page a little nicer **/
body {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<!-- The Viewer will be instantiated here -->
<div id="MyViewerDiv"></div>
<!-- Custom script -->
<script>
var viewer;
var options = {
env: "AutodeskProduction",
api: "derivativeV2", // TODO: for models uploaded to EMEA change this option to 'derivativeV2_EU'
getAccessToken: getForgeToken
};
var documentId = "urn:" + getUrlParameter("urn");
console.log(documentId);
// Run this when the page is loaded
Autodesk.Viewing.Initializer(options, function onInitialized() {
// Find the element where the 3d viewer will live.
var htmlElement = document.getElementById("MyViewerDiv");
if (htmlElement) {
// Create and start the viewer in that element
viewer = new Autodesk.Viewing.GuiViewer3D(htmlElement);
viewer.start();
// Load the document into the viewer.
Autodesk.Viewing.Document.load(
documentId,
onDocumentLoadSuccess,
onDocumentLoadFailure
);
}
});
/**
* Autodesk.Viewing.Document.load() success callback.
* Proceeds with model initialization.
*/
function onDocumentLoadSuccess(doc) {
// Load the default viewable geometry into the viewer.
// Using the doc, we have access to the root BubbleNode,
// which references the root node of a graph that wraps each object from the Manifest JSON.
var viewable = doc.getRoot().getDefaultGeometry();
if (viewable) {
viewer
.loadDocumentNode(doc, viewable)
.then(function (result) {
console.log("Viewable Loaded!");
})
.catch(function (err) {
console.log("Viewable failed to load.");
console.log(err);
});
}
}
/**
* Autodesk.Viewing.Document.load() failure callback.
*/
function onDocumentLoadFailure(viewerErrorCode) {
console.error(
"onDocumentLoadFailure() - errorCode: " + viewerErrorCode
);
jQuery("#MyViewerDiv").html(
"<p>Translation in progress... Please try refreshing the page.</p>"
);
}
// Get Query string from URL,
// we will use this to get the value of 'urn' from URL
function getUrlParameter(name) {
console.log("Made it here 2");
console.log(name);
name = name.replace(/[[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
var results = regex.exec(location.search);
return results === null
? ""
: decodeURIComponent(results[1].replace(/\+/g, " "));
}
// Get public access token for read only,
// using ajax to access route /api/forge/oauth/public in the background
function getForgeToken(callback) {
console.log("Made it here");
jQuery.ajax({
url: "/api/forge/oauth2/public",
success: function (res) {
callback(res.access_token, res.expires_in);
}
});
}
</script>
</body>
</html>
Node JS Code to translate and send to viewer
const express = require("express");
const Axios = require("axios");
const bodyParser = require("body-parser");
const cors = require("cors");
let config = require("./config");
let mainFunc = require("./BP-s3oss");
//Express Server
let app = express();
// let router = express.Router();
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(__dirname + "/www"));
app.get("/api/s3Data/:bucket", async (req, res) => {
let bucket = req.params.bucket;
let object = decodeURIComponent(req.query.object);
//Log to console
console.log(config.forge.forge_bucket + " " + object);
//Comment KWard: Add in Error check if unsuccessful
try {
//Main Function
let main = await mainFunc(bucket, object);
//Initialize Process
res.redirect("/api/forge/s3toOSS/" + config.forge.forge_bucket + "/" + encodeURIComponent(object));
} catch (error) {
res.status(500).send('Something bad Happened!');
}
});
//Start Express Server on Port 3000
app.set("port", 3000);
var server = app.listen(app.get("port"), function () {
console.log("Server listening on port " + server.address().port);
});
//-------------------------------------------------------------------
// Configuration for your Forge account
// Initialize the 2-legged OAuth2 client, and
// set specific scopes
//-------------------------------------------------------------------
var FORGE_CLIENT_ID = config.forgecredentials.client_id;
var FORGE_CLIENT_SECRET = config.forgecredentials.client_secret;
var access_token = "";
var scopes = "data:read data:write data:create bucket:create bucket:read";
const querystring = require("querystring");
//Route /AWStoFORGE/OSS
app.get("/api/forge/s3toOSS/:bucket/:object", async (req, res) => {
let bucket = req.params.bucket;
let object = req.params.object;
console.log(bucket + " " + object);
res.redirect("/api/forge/oauth" + "/" + encodeURIComponent(object));
});
// Route /api/forge/oauth
app.get("/api/forge/oauth/:object", function (req, res) {
let objectKey = req.params.object;
Axios({
method: "POST",
url: "https://developer.api.autodesk.com/authentication/v1/authenticate",
headers: {
"content-type": "application/x-www-form-urlencoded"
},
data: querystring.stringify({
client_id: FORGE_CLIENT_ID,
client_secret: FORGE_CLIENT_SECRET,
grant_type: "client_credentials",
scope: scopes
})
})
.then(function (response) {
// Success
access_token = response.data.access_token;
console.log("Successful Authentication");
res.redirect(
"/api/forge/datamanagement/bucket/getobject" + "/" + encodeURIComponent(objectKey)
);
})
.catch(function (error) {
// Failed
console.log(error);
res.send("Failed to authenticate");
});
});
// Route /api/forge/oauth2/public
app.get("/api/forge/oauth2/public", function (req, res) {
// Limit public token to Viewer read only
Axios({
method: "POST",
url: "https://developer.api.autodesk.com/authentication/v1/authenticate",
headers: {
"content-type": "application/x-www-form-urlencoded"
},
data: querystring.stringify({
client_id: FORGE_CLIENT_ID,
client_secret: FORGE_CLIENT_SECRET,
grant_type: "client_credentials",
scope: "viewables:read"
})
})
.then(function (response) {
// Successs
res.json({
access_token: response.data.access_token,
expires_in: response.data.expires_in
});
})
.catch(function (error) {
// Failed
console.log(error);
res.status(500).json(error);
});
});
const bucketKey = config.forge.forge_bucket;
const policyKey = "persistent"; // Never Expires
// For converting the source into a Base64-Encoded string
var Buffer = require("buffer").Buffer;
String.prototype.toBase64 = function () {
// Buffer is part of Node.js to enable interaction with octet streams in TCP streams,
// file system operations, and other contexts.
return new Buffer(this).toString("base64");
};
app.get("/api/forge/datamanagement/bucket/getobject/:objectKey", function (
req,
res
) {
let objectVal = req.params.objectKey;
console.log(bucketKey);
console.log(objectVal);
Axios({
method: "GET",
url:
"https://developer.api.autodesk.com/oss/v2/buckets/" +
encodeURIComponent(bucketKey) +
"/objects/" +
encodeURIComponent(objectVal) +
"/details",
maxContentLength: 104857780,
headers: {
Authorization: "Bearer " + access_token,
"content-type": "application/json"
}
})
.then(function (response) {
//Success
console.log("Object Retrieved from Forge OSS");
var urn = response.data.objectId.toBase64();
res.redirect("/api/forge/modelderivative/" + encodeURIComponent(urn));
})
.catch(function (error) {
//Failed
console.log(error);
res.send("Failed to get objectId from OSS.");
});
});
// Route /api/forge/modelderivative
app.get("/api/forge/modelderivative/:urn", function (req, res) {
var decodeURN = decodeURIComponent(req.params.urn)
var urn = decodeURN;
var format_type = "svf";
var format_views = ["2d", "3d"];
// console.log(urn);
Axios({
method: "POST",
url: "https://developer.api.autodesk.com/modelderivative/v2/designdata/job",
headers: {
"content-type": "application/json",
Authorization: "Bearer " + access_token
},
data: JSON.stringify({
input: {
urn: urn
},
output: {
formats: [
{
type: format_type,
views: format_views
}
]
}
})
})
.then(function (response) {
// Success
console.log("Redirected to Viewer HTML");
res.redirect("/viewer.html?urn=" + urn);
// res.send(urn);
})
.catch(function (error) {
// Failed
console.log(error);
res.send("Error at Model Derivative job.");
});
});
Check if the default view of your model is the 2D one that you are seeing as you are loading the default view with:
var viewable = doc.getRoot().getDefaultGeometry();
You can either load a specific view through the DocumentBrowser extension:
const viewer = new Autodesk.Viewing.GuiViewer3D(document.body.children[0],{extensions:['Autodesk.DocumentBrowser']})
Autodesk.Viewing.Document.load('urn:urn', doc=> {
viewer.start()
viewer.loadDocumentNode(doc,doc.getRoot().getDefaultGeometry())
//…
Or specify query to look up a viewable (such as a 3D one) in the document and load it:
Autodesk.Viewing.Document.load('urn:urn', doc=> {
const viewable = doc.getRoot().search({'role':'3d'})[0] //name of viewable for instance
viewer.start()
viewer.loadDocumentNode(doc,viewable)
//...
Adding a little more info to this...
If you want to retrieve the list of views in the document browser extension, here are two ways...
Using DOC object
let myViews = viewer.model.getDocumentNode().search({'role':'3d', type:'view'});
// returns, 5 views in an array
// change the camera view to view #2
viewer.setView(myViews[1]);
// print out the name of the view
console.log( myViews[1].name() );
> "3D_RF_AC1"
Using Extension
let ext = viewer.getExtension("Autodesk.DocumentBrowser");
let myViews = ext.geometries[0].children.filter( i => {
return(i.data.camera)
})
// change the camera view to view #2
viewer.setView( myViews[1] );
// print out the name of the view
console.log( myViews[1].name() );
> "3D_RF_AC1"
I would like to update my view after an ajax call, rendering compiled ejs from the server.
These two previous questions seem to achieve this but I cannot update my view
Can't Render EJS Template on Client
How to generate content on ejs with jquery after ajax call to express server
So from what I understand I should compile my ejs file (partial) on the server.
fixtures.ejs
<% fixtures.forEach((fixture) => { %>
<h2><%= fixture.home_team %> vs <%= fixture.away_team %></h2>
<% }) %>
index.js
app.post('/league_fixtures', async function (req, res) {
try {
var league_name = req.body.league_name;
const fixtures = await leagueFixtures(league_name);
//compile view
fs.readFile('./views/fixtures.ejs', "utf-8", function(err, template) {
fixture_template = ejs.compile(template, { client: true });
var html = fixture_template({fixtures: fixtures});
console.log(html);
// This logs out my HTML with fixtures so I am almost there
// <h2>Club Africain vs Al-Faisaly Amman</h2>
// <h2>Al Nejmeh vs ASAC Concorde</h2>
});
res.json({fixtures: fixtures });
} catch (err) {
res.status(500).send({ error: 'Something failed!' })
}
});
Ajax
$("a.league-name").on("click", function (e) {
e.preventDefault();
var league_name = $(this).text().trim();
$.ajax({
url: '/league_fixtures',
type: 'POST',
dataType: "json",
data: { league_name: league_name },
success: function(fixtures){
// How do i get HTML from server into here ?
$('#panel_' + league_name).html(fixtures);
},
error: function(jqXHR, textStatus, err){
alert('text status '+textStatus+', err '+err)
}
})
});
});
I don't get any errors when I fire the ajax request but I also do not get any data or HTML updated in my div.
What am I doing wrong?
So I finally got a working solution:
index.js
app.post('/league_fixtures', async function (req, res) {
try {
const league_name = req.body.league_name;
const fixtures = await leagueFixtures(league_name);
const file = await readFile('./views/fixtures.ejs');
var fixture_template = ejs.compile(file, { client: true });
const html = fixture_template({fixtures: fixtures});
res.send({ html: html });
} catch (err) {
res.status(500).send({ error: 'Something failed!' })
}
});
ajax call
$.ajax({
url: '/league_fixtures',
type: 'POST',
dataType: "json",
cache: true,
data: { league_name: league_name },
success: function(fixtures){
var html = fixtures['html'];
$('#panel_' + league_name).html(html);
},
error: function(jqXHR, textStatus, err){
alert('text status '+textStatus+', err '+err)
}
})
Is there a way using power bi rest API in node js, I watched video ,Ran Breuer and Arina Hantsis were showing the demo here,Setting up and Getting Started with Power BI Embedded I want to achieve same but using node js, in our development environment we do not use c#.
I found the Node SDK but it saying we no longer support node SDK,Node SDK
Do I have to change development structure from Node js to c# in order to use power bi Rest API!!
If you want to achieve same, what Ran Breuer and Arina Hantsis demonstrate in there video!
you can use these codes...
after reading the documentation, I come up with this solution it took me 5 days to figure out, anyway I am posting here so everyone can have easy access to codes.
**AppOwnData Power bi embedded reports **
Controller.js
const request = require('request');
const getAccessToken = function () {
return new Promise(function (resolve, reject) {
const url = 'https://login.microsoftonline.com/common/oauth2/token';
const username = ''; // Username of PowerBI "pro" account - stored in config
const password = ''; // Password of PowerBI "pro" account - stored in config
const clientId = ''; // Applicaton ID of app registered via Azure Active Directory - stored in config
const headers = {
'Content-Type': 'application/x-www-form-urlencoded'
};
const formData = {
grant_type: 'password',
client_id: clientId,
resource: 'https://analysis.windows.net/powerbi/api',
scope: 'openid',
username: username,
password: password
};
request.post({
url: url,
form: formData,
headers: headers
}, function (err, result, body) {
if (err) return reject(err);
const bodyObj = JSON.parse(body);
resolve(bodyObj.access_token);
});
});
};
const getReportEmbedToken = function (accessToken, groupId, reportId) {
return new Promise(function (resolve, reject) {
const url = 'https://api.powerbi.com/v1.0/myorg/groups/' + groupId + '/reports/' + reportId + '/GenerateToken';
const headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer ' + accessToken
};
const formData = {
'accessLevel': 'view'
};
request.post({
url: url,
form: formData,
headers: headers
}, function (err, result, body) {
if (err) return reject(err);
const bodyObj = JSON.parse(body);
resolve(bodyObj.token);
});
});
};
module.exports = {
embedReport: function (req, res) {
getAccessToken().then(function (accessToken) {
getReportEmbedToken(accessToken, req.params.groupId, req.params.reportId).then(function (embedToken) {
res.render('index', {
reportId: req.params.dashboardId,
embedToken,
embedUrl: 'https://app.powerbi.com/reportEmbed?reportId=' + req.params.reportId + '&groupId=' + req.params.groupId
});
}).catch(function (err) {
res.send(500, err);
});
}).catch(function (err) {
res.send(500, err);
});
}
};
Your router index.js
const express = require('express'),
router = express.Router(),
mainCtrl = require('../controllers/MainController');
router.get('/report/:groupId/:reportId', mainCtrl.embedReport);
module.exports = router;
index.ejs or what ever you like
<!DOCTYPE html>
<html>
<head>
<title>Node.js PowerBI Embed</title>
<link rel="stylesheet" href="/bootstrap/dist/css/bootstrap.min.css" />
<style>
html,
body {
height: 100%;
}
.fill {
min-height: 100%;
height: 100%;
box-sizing: border-box;
}
#reportContainer {
height: 100%;
min-height: 100%;
display: block;
}
</style>
</head>
<body>
<div class="container-fluid fill">
<div id="reportContainer"></div>
</div>
<script src="/jquery/dist/jquery.min.js"></script>
<script src="/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="/powerbi-client/dist/powerbi.js"></script>
<script>
const models = window['powerbi-client'].models;
const config = {
type: 'report',
tokenType: models.TokenType.Embed,
accessToken: '<%- embedToken %>',
embedUrl: '<%- embedUrl %>',
id: '<%- reportId %>'
};
// Get a reference to the embedded dashboard HTML element
const reportContainer = $('#reportContainer')[0];
// Embed the dashboard and display it within the div container.
powerbi.embed(reportContainer, config);
</script>
</body>
</html>
Finally Enjoy
localhost:4000/report/put your group id here / put you report id here
I used #Joyo Waseem codes and successfully embedded the report, then I give a try to embed Dashboard and it works too, I decided to post my codes here so anyone who tries to embed Dashboard can use these codes.
Embedded Dashboard using power bi Res API
Controler.js
const request = require('request');
const getAccessToken = function () {
return new Promise(function (resolve, reject) {
const url = 'https://login.microsoftonline.com/common/oauth2/token';
const username = ''; // Username of PowerBI "pro" account - stored in config
const password = ''; // Password of PowerBI "pro" account - stored in config
const clientId = ''; // Applicaton ID of app registered via Azure Active Directory - stored in config
const headers = {
'Content-Type': 'application/x-www-form-urlencoded'
};
const formData = {
grant_type: 'password',
client_id: clientId,
resource: 'https://analysis.windows.net/powerbi/api',
scope: 'openid',
username: username,
password: password
};
request.post({
url: url,
form: formData,
headers: headers
}, function (err, result, body) {
if (err) return reject(err);
const bodyObj = JSON.parse(body);
resolve(bodyObj.access_token);
});
});
};
const getEmbedToken = function (accessToken, groupId, dashboardId) {
return new Promise(function (resolve, reject) {
const url = 'https://api.powerbi.com/v1.0/myorg/groups/' + groupId + '/dashboards/' + dashboardId + '/GenerateToken';
const headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer ' + accessToken
};
const formData = {
'accessLevel': 'View'
};
request.post({
url: url,
form: formData,
headers: headers
}, function (err, result, body) {
if (err) return reject(err);
const bodyObj = JSON.parse(body);
resolve(bodyObj.token);
});
});
};
module.exports = {
prepareView: function(req, res) {
getAccessToken().then(function(accessToken) {
console.log(req.params.groupId);
getEmbedToken(accessToken, req.params.groupId, req.params.dashboardId).then(function(embedToken) {
res.render('index', {
dashboardId: req.params.dashboardId,
embedToken,
embedUrl: 'https://app.powerbi.com/dashboardEmbed?dashboardId=' + req.params.dashboardId + '&groupId=' + req.params.groupId
});
});
});
}
};
index.js
const express = require('express'),
router = express.Router(),
mainCtrl = require('../controllers/MainController');
router.get('/dashboard/:groupId/:dashboardId', mainCtrl.prepareView);
module.exports = router;
index.ejs etc.
<!DOCTYPE html>
<html>
<head>
<title>Node.js PowerBI Embed</title>
<link rel="stylesheet" href="/bootstrap/dist/css/bootstrap.min.css" />
<style>
html,
body {
height: 100%;
}
.fill {
min-height: 100%;
height: 100%;
box-sizing: border-box;
}
#dashboardContainer {
height: 100%;
min-height: 100%;
display: block;
}
</style>
</head>
<body>
<div class="container-fluid fill">
<div id="dashboardContainer"></div>
</div>
<script src="/jquery/dist/jquery.min.js"></script>
<script src="/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="/powerbi-client/dist/powerbi.js"></script>
<script>
const models = window['powerbi-client'].models;
const config = {
type: 'dashboard',
tokenType: models.TokenType.Embed,
accessToken: '<%- embedToken %>',
embedUrl: '<%- embedUrl %>',
id: '<%- dashboardId %>'
};
// Get a reference to the embedded dashboard HTML element
const dashboardContainer = $('#dashboardContainer')[0];
// Embed the dashboard and display it within the div container.
powerbi.embed(dashboardContainer, config);
</script>
</body>
</html>
#Jo Joy what is the seen you should know .
https://github.com/Microsoft/PowerBI-Node/issues/40
It about priorities these company decide in which project they do .
They can response very well about this. But as far as discussion there are no such plan to do so . You can access api before feb 2017 .
If newer api you have to try it for your . May be you folk it . We as commundity will contribute .
They no longer support the Node SDK, but have you tried it? It might still be working. You are gonna want some sort of SDK - it seems that is not the easiest API to work with.
Currently we are using Polymer for frontend. In polymer we have element “vaadin-upload”.
Issue: We are not able to fire/trace node js code. When we try to upload image then it throws POST 404 not found error.
Please check below code of Polymer and NodeJS.
Polymer:
<vaadin-upload target="http://localhost:5000/upload" method="POST" timeout="300000" headers="{'X-Custom-Header': 'value'}"></vaadin-upload>
Node Js:
var server = new Hapi.Server();
server.route({
method: 'POST',
path: '/upload',
config: {
payload:{
maxBytes:209715200,
output:'stream',
parse: false
},
handler: function (request, reply) {
var data = request.payload;
if (data.file) {
var name = data.file.hapi.filename;
var path = __dirname + "/upload/" + name;
var file = fs.createWriteStream(path);
file.on('error', function (err) {
console.error(err)
});
data.file.pipe(file);
data.file.on('end', function (err) {
var ret = {
filename: data.file.hapi.filename,
headers: data.file.hapi.headers
}
reply(JSON.stringify(ret));
})
}
}
}
});
After looking at the hapijs tutorial it looks like you need to define the port after you create the server instance.
server.connection({ port: 5000 });
Hapi will save the file to the directory for you so you don't have to handle it.
const server = new Hapi.Server();
server.connection({
port: 5000
});
server.start(function () {
console.log('server running at: ' + server.info.uri);
});
const PATH_TO_UPLOADED_FILES = '...';
server.route({
method: 'POST',
path: '/upload',
config: {
payload: {
output: 'file',
uploads: PATH_TO_UPLOADED_FILES,
parse: true,
maxBytes: 209715200
},
handler: function (request, reply) {
// file path is at: request.payload.file.path
reply('thanks');
}
}
});