Request

Response

    4. Generate STEP File for a Component

    This code sample demonstrates the use of the Manufacturing Data Model API to generate STEP file 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

    1. 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.
    2. Clone or fork the GitHub Repository.
    3. In the 5.Generate STEP file 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 ID
    • clientSecret - Your Client Secret
    • hubName - 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.
    ../../../_images/code-sample-image-03.png


    Running the Sample

    1. In the terminal, navigate to the 5.Generate STEP file for Component folder and execute the following command:
    npm start
    
    1. 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.
    2. 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.

      ../../../_images/code-sample-image-08.png
    3. In the terminal window, locate the statement Open STEP file saved here, and copy the link that follows the statement to the address bar of a browser. The STEP file displays.

      ../../../_images/code-sample-image-09.png


    Workflow Description

    The workflow can be summarized in three steps:

    1. Request for the STEP file of a specific model based on its hub, project, and component name.
    2. If the status of the STEP file is pending (it is still being generated), keep on checking the status.
    3. Once the status is success, get the URL of the STEP file.

    This workflow can be seen in the following code block:

    app.js:

      async downloadGeometry(hubName, projectName, componentName) {
        try {
          while (true) {
            let response = await this.sendQuery(
              `query GetGeometry($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 {
                                  derivatives (derivativeInput: {outputFormat: STEP, generate: true}) {
                                    expires
                                    signedUrl
                                    status
                                    progress
                                    outputFormat
                                  }       
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }`,
              {
                hubName,
                projectName,
                componentName
              }
            )
    
            let geometry = this.getComponentVersionGeometry(
              response, hubName, projectName, componentName
            );
    
            if (geometry.status === "SUCCESS") {
              // If the geometry generation finished then we can download it
              // from the url
              let geometryPath = path.resolve('geometry.stp');
              await this.downloadFile(geometry.signedUrl, geometryPath);
              return "file://" + encodeURI(geometryPath);
            } else {
              console.log("Extracting geometry … (it may take a few seconds)")
              // Let's wait a second before checking the status of the geometry again
              await new Promise(resolve => setTimeout(resolve, 1000));
            }
          }
        } catch (err) {
          console.log("There was an issue: " + err.message)
        }
      }
    
    Show More



    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 wait for the STEP format to generate. The API generates a STEP file and the signedURl associated with it.

    // 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;
      }
    
      getComponentVersionGeometry(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.derivatives[0];
      }
    
    // <downloadGeometry>
      async downloadGeometry(hubName, projectName, componentName) {
        try {
          while (true) {
            let response = await this.sendQuery(
              `query GetGeometry($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 {
                                  derivatives (derivativeInput: {outputFormat: STEP, generate: true}) {
                                    expires
                                    signedUrl
                                    status
                                    progress
                                    outputFormat
                                  }       
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }`,
              {
                hubName,
                projectName,
                componentName
              }
            )
    
            let geometry = this.getComponentVersionGeometry(
              response, hubName, projectName, componentName
            );
    
            if (geometry.status === "SUCCESS") {
              // If the geometry generation finished then we can download it
              // from the url
              let geometryPath = path.resolve('geometry.stp');
              await this.downloadFile(geometry.signedUrl, geometryPath);
              return "file://" + encodeURI(geometryPath);
            } else {
              console.log("Extracting geometry … (it may take a few seconds)")
              // Let's wait a second before checking the status of the geometry again
              await new Promise(resolve => setTimeout(resolve, 1000));
            }
          }
        } catch (err) {
          console.log("There was an issue: " + err.message)
        }
      }
    // </downloadGeometry>
    
      async downloadFile(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);
        });
      }
    }
    
    Show More

    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 filePath = await myApsApp.downloadGeometry(
      hubName,
      projectName,
      componentName
    );
    
    if (filePath)
      console.log("Open file saved here: " + filePath);
    
    Show More

    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;
      }
    }
    
    Show More
    Was this section useful?