Get the Thumbnail of a Part
This code sample demonstrates the use of the Manufacturing Data Model API to get the thumbnail of a design.
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 sign up for an APS account (if necessary) and obtain a client ID for your app.
- Make sure that you add the following as the Callback URL:
http://localhost:3000/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 Git Repository.
- In the 2.Find the Thumbnail of a specific Part 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 earlier, 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 2.Find the Thumbnail of a specific Part folder and execute the following command:
npm start
- When prompted, open a browser and go to http://localhost:3000
- Once the “Got the access token. You can close the browser!” message is displayed on the browser, return to the terminal. You will see a screen similar to the following.
- In the terminal window, locate the statement Open thumbnail file saved here, and copy the link that follows the statement to the address bar of a browser. The thumbnail displays.
Workflow description
The workflow can be summarized in three steps:
- Request the thumbnail of a specific model based on its hub, project, and component name.
- If the status of the thumbnail is
pending
(it is still being generated), keep on checking the status. - Once the status is
successful
, get the URL of the thumbnail.
This workflow can be seen in the following code block:
app.js:
async downloadThumbnail(hubName, projectName, componentName) {
try {
let projectId = await this.getProjectId(hubName, projectName);
let componentVersionId = await this.getComponentVersionId(projectId, componentName);
while (true) {
let response = await this.sendQuery(
`query GetThumbnail($componentVersionId: ID!) {
componentVersion(componentVersionId: $componentVersionId) {
thumbnail {
status
signedUrl
}
}
}`,
{
componentVersionId
}
)
let thumbnail = response.data.data.componentVersion.thumbnail;
if (thumbnail.status === "SUCCESS") {
// If the thumbnail generation finished then we can download it
// from the url
let thumbnailPath = path.resolve('thumbnail.png');
await this.downloadImage(thumbnail.signedUrl, thumbnailPath);
return "file://" + encodeURI(thumbnailPath);
} else {
console.log("Extracting thumbnail … (it may take a few seconds)")
// Let's wait a second before checking the status of the thumbnail again
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
} catch (err) {
console.log("There was an issue: " + err.message)
}
}
JavaScript source code walk-through
app.js
This is the main operational code of the application. It sends a GraphQL query to open the design and wait for the thumbnail to generate. The API generates more than one thumbnail. So, the code extracts the URL of the thumbnail that is more one from among them.
// 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.api.autodesk.com/mfg/graphql';
this.accessToken = accessToken;
}
getRequestHeaders() {
return {
"Content-type": "application/json",
"Authorization": "Bearer " + this.accessToken,
};
}
async sendQuery(query, variables) {
try {
let response = await axios({
method: "POST",
url: `${this.graphAPI}`,
headers: this.getRequestHeaders(),
data: {
query,
variables,
},
});
return response;
} catch (err) {
if (err.response.data.errors) {
let formatted = JSON.stringify(err.response.data.errors, null, 2);
console.log(`API error:\n${formatted}`);
}
throw err;
}
}
async getProjectId(hubName, projectName) {
try {
// Get first batch of occurrences
let response = await this.sendQuery(
`query GetProjectId($hubName: String!, $projectName: String!) {
hubs(filter:{name:$hubName}) {
results {
name
projects(filter:{name:$projectName}) {
results {
name
id
}
}
}
}
}`,
{
hubName,
projectName
}
);
let projectId = response.data.data.hubs.results[0].projects.results[0].id;
return projectId;
} catch (err) {
console.log("There was an issue: " + err.message);
}
}
async getComponentVersionId(projectId, componentName) {
try {
// Get first batch of occurrences
let response = await this.sendQuery(
`query GetComponentVersionId($projectId: ID!, $componentName: String!) {
project(projectId: $projectId) {
name
items(filter:{name:$componentName}) {
results {
... on DesignItem {
name
tipRootComponentVersion {
id
}
}
}
}
}
}`,
{
projectId,
componentName
}
);
let componentVersionId = response.data.data.project.items.results[0].tipRootComponentVersion.id;
return componentVersionId;
} catch (err) {
console.log("There was an issue: " + err.message);
}
}
// <downloadThumbnail>
async downloadThumbnail(hubName, projectName, componentName) {
try {
let projectId = await this.getProjectId(hubName, projectName);
let componentVersionId = await this.getComponentVersionId(projectId, componentName);
while (true) {
let response = await this.sendQuery(
`query GetThumbnail($componentVersionId: ID!) {
componentVersion(componentVersionId: $componentVersionId) {
thumbnail {
status
signedUrl
}
}
}`,
{
componentVersionId
}
)
let thumbnail = response.data.data.componentVersion.thumbnail;
if (thumbnail.status === "SUCCESS") {
// If the thumbnail generation finished then we can download it
// from the url
let thumbnailPath = path.resolve('thumbnail.png');
await this.downloadImage(thumbnail.signedUrl, thumbnailPath);
return "file://" + encodeURI(thumbnailPath);
} else {
console.log("Extracting thumbnail … (it may take a few seconds)")
// Let's wait a second before checking the status of the thumbnail again
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
} catch (err) {
console.log("There was an issue: " + err.message)
}
}
// </downloadThumbnail>
async downloadImage(url, path) {
const writer = fs.createWriteStream(path);
const response = await axios({
url,
method: 'GET',
headers: this.getRequestHeaders(),
responseType: 'stream'
});
response.data.pipe(writer);
return new Promise((resolve, reject) => {
writer.on('finish', resolve);
writer.on('error', reject);
});
}
}
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
);
const thumbnailPath = await myApsApp.downloadThumbnail(
hubName,
projectName,
componentName
);
if (thumbnailPath)
console.log("Open thumbnail saved here: " + thumbnailPath);
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.api.autodesk.com/';
this.authAPI = `${this.host}authentication/v2/`;
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}token`,
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;
}
}