5. Generate Physical Properties of a Component (beta)
This code sample demonstrates the use of the Manufacturing Data Model API to find out physical properties such as area, mass, volume, density, surface area, and bounding box of a component.
See this code sample on the Manufacturing Data Model Samples Git Repository.
Note: This code sample requires Node.js version 16.13.2 or later.
Before You Begin
- If you do not have an app registered for the Manufacturing Data Model API, follow the procedure outlined in Create an App to obtain a Client ID for your app.
- Make sure that you add the following as the Callback URL:
http://localhost:8080/callback/oauth
. - In the APIs section, verify that the Manufacturing Data Model API is selected.
- Make sure that you add the following as the Callback URL:
- Clone or fork the GitHub Repository.
- In the 6.Get Physical Properties for Component folder, install all dependencies by running:
npm i
Setting up the Application
index.js:
// Replace the string literal values with your own client id, client secret,
// hub name, project name and component name.
const clientId = '<YOUR_CLIENT_ID>';
const clientSecret = '<YOUR_CLIENT_SECRET>';
const hubName = '<YOUR_HUB_NAME>';
const projectName = '<YOUR_PROJECT_NAME>';
const componentName = '<YOUR_COMPONENT_NAME>';
In index.js shown above, specify values for the following variables:
clientId
- Your Client IDclientSecret
- Your Client SecrethubName
- The name of the hub that contains the design you want to read. (See the following image)projectName
- The name of the project that contains the design you want to read.componentName
- The name of the design you want to read.

Running the Sample
- In the terminal, navigate to the 6.Get Physical Properties for Component folder and execute the following command:
npm start
- A URL is provided to be opened in a browser to log into your Autodesk account. Open a browser and go to http://localhost:8080.
- Once the “Got the access token. You can close the browser!” message is displayed on the browser, return to the terminal.
- In the terminal window, you can now see the properties of the component getting generated similar to the following image.
Workflow Description
The workflow can be summarized in three steps:
- Request for the properties such as area, mass, volume, density, bounding box, and surface area of a specific model based on its hub, project, and component name.
- If the status is
IN_PROGRESS
(it is still being generated), keep on checking the status. - Once the status is
COMPLETED
, check the properties of the component in the terminal window.
This workflow can be seen in the following code block:
app.js:
async getPhysicalProperties(hubName, projectName, componentName) {
try {
while (true) {
let response = await this.sendQuery(
`query GetPhysicalProperties($hubName: String!, $projectName: String!, $componentName: String!) {
hubs(filter:{name:$hubName}) {
results {
projects(filter:{name:$projectName}) {
results {
rootFolder {
items(filter:{name:$componentName}) {
results {
... on Component {
tipVersion {
physicalProperties {
status
area {
displayValue
propertyDefinition {
units {
name
}
}
}
volume {
displayValue
propertyDefinition {
units {
name
}
}
}
mass {
displayValue
value
propertyDefinition {
units {
name
}
}
}
density {
displayValue
propertyDefinition {
units {
name
}
}
}
boundingBox {
length {
displayValue
propertyDefinition {
units {
name
}
}
}
height {
displayValue
propertyDefinition {
units {
name
}
}
}
width {
displayValue
propertyDefinition {
units {
name
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}`,
{
hubName,
projectName,
componentName
}
)
let geometry = this.getComponentVersionPhysicalProperties(
response, hubName, projectName, componentName
);
if (geometry.status === "COMPLETED") {
return geometry;
}
}
} catch (err) {
console.log("There was an issue: " + err.message)
}
}
JavaScript Source Code Walkthrough
app.js
This is the main operational code of the application. It sends a GraphQL query to open the design and fetch the properties of a component model.
// Axios is a promise-based HTTP client for the browser and node.js.
import axios from "axios";
// We need the following in order to save files to the machine
import fs from "fs";
import path from "path";
// Application constructor
export default class App {
constructor(accessToken) {
this.graphAPI = 'https://developer-stg.api.autodesk.com/mfgdataapi/2022-04/graphql';
this.accessToken = accessToken;
}
getRequestHeaders() {
return {
"Content-type": "application/json",
"Authorization": "Bearer " + this.accessToken,
};
}
async sendQuery(query, variables) {
let response = await axios({
method: 'POST',
url: `${this.graphAPI}`,
headers: this.getRequestHeaders(),
data: {
query,
variables
}
})
if (response.data.errors) {
let formatted = JSON.stringify(response.data.errors, null, 2);
console.log(`API error:\n${formatted}`);
}
return response;
}
getComponentVersionPhysicalProperties(response, hubName, projectName, componentName) {
let hubs = response.data.data.hubs.results;
if (hubs.length < 1)
throw { message: `Hub "${hubName}" does not exist` }
let projects = hubs[0].projects.results;
if (projects.length < 1)
throw { message: `Project "${projectName}" does not exist` }
let files = projects[0].rootFolder.items.results;
if (files.length < 1)
throw { message: `Component "${componentName}" does not exist` }
return files[0].tipVersion.physicalProperties;
}
// <getPhysicalProperties>
async getPhysicalProperties(hubName, projectName, componentName) {
try {
while (true) {
let response = await this.sendQuery(
`query GetPhysicalProperties($hubName: String!, $projectName: String!, $componentName: String!) {
hubs(filter:{name:$hubName}) {
results {
projects(filter:{name:$projectName}) {
results {
rootFolder {
items(filter:{name:$componentName}) {
results {
... on Component {
tipVersion {
physicalProperties {
status
area {
displayValue
propertyDefinition {
units {
name
}
}
}
volume {
displayValue
propertyDefinition {
units {
name
}
}
}
mass {
displayValue
value
propertyDefinition {
units {
name
}
}
}
density {
displayValue
propertyDefinition {
units {
name
}
}
}
boundingBox {
length {
displayValue
propertyDefinition {
units {
name
}
}
}
height {
displayValue
propertyDefinition {
units {
name
}
}
}
width {
displayValue
propertyDefinition {
units {
name
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}`,
{
hubName,
projectName,
componentName
}
)
let geometry = this.getComponentVersionPhysicalProperties(
response, hubName, projectName, componentName
);
if (geometry.status === "COMPLETED") {
return geometry;
}
}
} catch (err) {
console.log("There was an issue: " + err.message)
}
}
// </getPhysicalProperties>
}
index.js
This is the module that you use to run the application and set the required constant variables.
import MyApp from './app.js';
import MyAuth from './auth.js';
// Replace the string literal values with your own client id, client secret,
// hub name, project name and component name.
const clientId = '<YOUR_CLIENT_ID>';
const clientSecret = '<YOUR_CLIENT_SECRET>';
const hubName = '<YOUR_HUB_NAME>';
const projectName = '<YOUR_PROJECT_NAME>';
const componentName = '<YOUR_COMPONENT_NAME>';
// Create an instance of auth.js.
let myApsAuth = new MyAuth(clientId, clientSecret);
// Get an access token from your auth.js instance.
let accessToken = await myApsAuth.getAccessToken();
// Create an instance of app.js using the variable set above.
let myApsApp = new MyApp(
accessToken
);
let properties = await myApsApp.getPhysicalProperties(
hubName,
projectName,
componentName
);
console.log("Physical properties:");
printInfo(properties, "");
function printInfo (properties, indent) {
for (let propertyName of Object.keys(properties)) {
let property = properties[propertyName];
if (propertyName === "status") continue;
if (propertyName === "boundingBox") {
console.log(`${indent}${propertyName}:`);
printInfo(property, indent + " ");
continue;
}
console.log(`${indent}${propertyName}: ${property.displayValue} [${property.propertyDefinition.units.name}]`);
}
}
auth.js
This is the module that you use to obtain a three-legged access token to be used with the POST request you send to the Manufacturing Data Model API.
It uses the POST /v1/gettoken endpoint.
// Axios is a promise-based HTTP client for the browser and node.js.
// See npmjs.com/package/axios
import axios from 'axios';
// Express is a JavaSscript web application framework. See expressjs.com.
import express from 'express';
// Instantiate an express application.
let app = express();
// Export the Auth class for use by other app modules.
export default class Auth {
// Construct the class instance and set global variables, based on the client ID and secret.
constructor(clientId, clientSecret) {
this.host = 'https://developer-stg.api.autodesk.com/';
this.authAPI = `${this.host}authentication/v1/`;
this.port = 8080;
this.redirectUri = `http://localhost:${this.port}/callback/oauth`;
this.accessTokenPromise = new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
// Handle the callback/redirection by the Autodesk server once the user approves our app’s access to their data.
app.get('/callback/oauth', async (req, res) => {
const { code } = req.query;
// When you are redirected to the callback URL, the URL also contains a ‘code’ parameter with a value that you can exchange for an actual access token.
try {
const response = await axios({
method: 'POST',
url: `${this.authAPI}gettoken`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: `client_id=${clientId}&client_secret=${clientSecret}&grant_type=authorization_code&code=${code}&redirect_uri=${this.redirectUri}`
})
// Set the accessToken variable to the value in the response.
this.accessToken = response.data.access_token
// Resolve the Promise passed by the getAccessToken() function below with the access token.
// Let the rest of the application continue.
this.resolve(this.accessToken);
// No need to listen for incoming calls anymore.
this.server.close();
res.redirect('/');
} catch (error) {
console.log(error);
this.reject(error);
}
});
app.get('/', async (req, res) => {
// Once you have the access token, then there is nothing more to do.
if (this.accessToken) {
res.send('Got the access token. You can close the browser!').end();
return;
}
// Otherwise, redirect the user to the Autodesk log-in site where they can log in with their credentials
// and approve our app’s access to their data.
// Once that happens, the Autodesk server redirects the user to the callback URL provided.
// That callback is handled above in the app.get('/callback/oauth' …) function.
const url =
`${this.authAPI}authorize?response_type=code` +
`&client_id=${clientId}` +
`&redirect_uri=${this.redirectUri}` +
'&scope=data:read data:write data:create';
res.redirect(url);
})
this.server = app.listen(this.port);
console.log(
`Open http://localhost:${this.port} in a web browser in order to log in with your Autodesk account!`
);
}
// Pass back a Promise that only resolves and lets the rest of the application continue
// once you have an access token.
getAccessToken = async () => {
return this.accessTokenPromise;
}
}