Welcome to the Onshape forum! Ask questions and join in the discussions about everything Onshape.

First time visiting? Here are some places to start:
  1. Looking for a certain topic? Check out the categories filter or use Search (upper right).
  2. Need support? Ask a question to our Community Support category.
  3. Please submit support tickets for bugs but you can request improvements in the Product Feedback category.
  4. Be respectful, on topic and if you see a problem, Flag it.

If you would like to contact our Community Manager personally, feel free to send a private message or an email.

Options

API for Dummies

matthew_stacymatthew_stacy Member Posts: 476 PRO
My goal is to setup a configurator similar to this example, but I would like to drive this from the views.py file of a django web application.  The intent is to enable a user to configure a simple part, not unlike the "dancing cube" that @Ethan_K demonstrated on youtube, and then download a STEP file.

So far I have installed onshapepy and onshape_client, but have yet to achieve anything productive yet. I would greatly appreciate any advice, suggestions or examples.

Comments

  • Options
    matthew_stacymatthew_stacy Member Posts: 476 PRO
    Can anyone direct me to python code to update configuration variable values through the API?  I am attempting to adapt this to the views.py file in a django website.  I can successfully use the Client class to  instantiate at https://cad.onshape.com using an apikey.  Subsequently I am able to apply methods of Client() to perform basic tasks:
    • new_document() # create a new Onshape document
    • rename_document()
    • etc.
    My ultimate goal is to edit configuration variables from my website through the Onshape API.  What I am looking for is Python code that could be used to create additional class methods to:
    1. request a list of configuration variables from Onshape
    2. Update the values of those variables from my website
    I have played with some of the onshapepy code with very limited success thus far.  Onshapepy has been deprecated.  The params method of the Part() class  displays configuration variables and provide editing capabilities, but the results are very sporadic.  For example, I have to toggle between workspaces, often multiple times, in Onshape to update the part studio to show current values.
  • Options
    billy2billy2 Member, OS Professional, Mentor, Developers, User Group Leader Posts: 2,015 PRO
    I'm not a python guy, more of a nodejs guy but I'll look up my configuration reading code and post it.

    I'll also post my code that updates these variables.

    One thing to remember about the API is that your request returns a leaf of the data structure. It's best to change the values in the leaf then upload it in its entirety. Don't try and send back one variable of the leaf.

    You have to put back what you recieved.

    @matthew_stacy I got my code originally from a python program. I converted the steps into nodejs. It doesn't matter what language is used, the API steps are the same. You can pick out the steps fairly easy.


  • Options
    billy2billy2 Member, OS Professional, Mentor, Developers, User Group Leader Posts: 2,015 PRO
    edited November 2021
    I'm not sure how much this will help, it's the entire config call to OS servers.

        //***get config inputs    
        if (server.config) {
          // console.log(`config @ config.2.js `,server)
    
          sock.emit('recSock', {
            "id" : "input",
            "update" : "retrieving"
          });
    
          //****this is the code to retrieve config leaf from OS
          //send json to client, need it to build configuration
          server.url=`${server.po.osPath}/api/elements/${server.dwe}/configuration`
          //console.log(`config.2.js server.url config\n${server.url}`)
          var json = await onshape.get(server)
          let config=JSON.parse(json)
    
          // sendJSON(config, `config @ config.2.js`)
    
          //send json for review
          // sock.emit('recSock', {
          //   id : "json",
          //   update : json
          // });
    
          // sock.emit('recSock', {
          //   json : json
          // });
    
          //build update for customize
          let html="", current={}, checked="", selected="";
    
          //build view selector
          if (server.view) {
            //take version or workspace out of dwe for named views
            server.url=`${server.po.osPath}${server.api}${server.dwe.replace(/\/(v|w)\/[0-9 a-z]+/g, "")}/namedViews`
            //console.log(`server.url view ${server.url}`)
            json = await onshape.get(server)
            let view=JSON.parse(json)
    
            if (!view.namedViews) view={namedViews:{}}
    
            //aways have an iso view by default
            view.namedViews.iso={
              "sectionPlanes": [],
              "perspective": false,
              "viewMatrix": [0.7071067811865474,0.7071067811865478,4.163336342344336e-16,0,-0.4082482904638632,0.40824829046386246,0.8164965809277263,0,0.5773502691896261,-0.5773502691896261,0.5773502691896254,0,0.06397250299509981,-0.10429794707348419,0.06397250299509985,1],
              "cameraViewport": [0.09212381909630932,-0.09212381909630932,0.15974959529845348,-0.15974959529845348],
              "angle": 0
            }
    
            var namedViews=Object.keys(view.namedViews)
    
            html+=`view <select id="views" class="shine" onchange="configString();">`
            namedViews.forEach(e => {
              if (e==="iso")
                html+=`<option value="${view.namedViews[e].viewMatrix.slice(0, -4)}" selected>${e}</option>`
              else
                html+=`<option value="${view.namedViews[e].viewMatrix.slice(0, -4)}" >${e}</option>`
            })
            html+=`</select><br />`
    
          }
    
    
          //****I parse the config leaf and create html
          //parse onshape into html
          config.configurationParameters.forEach(e => {
            //html+=`e.type ${e.type}<br/>`;
    
            if (e.type===1826) {
              var units=""
              if (e.message.rangeAndDefault.message.units==="inch") units="in"
              if (e.message.rangeAndDefault.message.units==="millimeter") units="mm"
              html+=`${e.message.parameterName} \
                (${e.message.rangeAndDefault.message.minValue}${units} to ${e.message.rangeAndDefault.message.maxValue}${units}) \
                <input \
                name="config" \
                id="${e.message.parameterName}" \
                class="small border shine" \
                style="text-align:right;" \
                title="range ${e.message.rangeAndDefault.message.minValue}${units} to ${e.message.rangeAndDefault.message.maxValue}${units}" \
                size="5" \
                placeholder="enter" \
                value="${e.message.rangeAndDefault.message.defaultValue}" \
                units="${units}" \
                onchange="configString();" \
                /><br />`
    
                configuration+=`${e.message.parameterName}=${e.message.rangeAndDefault.message.defaultValue}${units};`
            }//input
    
            if (e.type===2550) {
              (e.message.defaultValue) ? checked="checked" : checked="";//see if current is checked
              html+=`${e.message.parameterName} <input \
                name="config" \
                id="${e.message.parameterName}" \
                class="large" \
                type="checkbox" \
                ${checked} \
                onchange="configString();" \
                /><br/>`
    
                configuration+=`${e.message.parameterName}=${e.message.defaultValue};`
            }//checkbox
    
            if (e.type===105) {
              html+=`${e.message.parameterName} <select \
              name="config" \
              id="${e.message.parameterName}" \
              parameterId="${e.message.parameterId}" \
              class="small border" \
              onchange="configString();">`
    
              e.message.options.forEach(e2 => {
                (e2.message.option==="Default") ? selected="selected" : selected="";
                //console.log(`${e2.message.option} ${e2.message.optionName} ${selected}`);
                html+=`<option value="${e2.message.option}" ${selected}>${e2.message.optionName}</option>`;
                if (selected) configuration+=`${e.message.parameterId}=${e2.message.option};`
              })
    
              html+=`</select><br />`
    
            }//select
    
          })//foreach
    
          //configuration=configuration.slice(0,-1)
          // console.log("config.2 config ", configuration)
    
          //submit button
          //html+=`<br /><button class="shine" onclick="clickSubmit();">Click to Build Geometry</button><br />`;
    
    
          //****I'm sending html back to client and updating an a tag called "input"
          //send html
          sock.emit('recSock', {
            "id" : "input",
            "update" : html
          });
        }

    I've highlighted the basic config call with //**** comments.

    1. async call to OS and then parse into a object config

    server.url=`${server.po.osPath}/api/elements/${server.dwe}/configuration`
    server.dwe is the document address 
    server.po.osPath is the OS server type, they had a prototype server & production server at one time.


    2. further parse config into html 
    3. send html to client and update a tag called "input"

    This is as clear as mud, right?



  • Options
    billy2billy2 Member, OS Professional, Mentor, Developers, User Group Leader Posts: 2,015 PRO
    edited November 2021
    I can find the send code and post it if this is helping. 

    In the send code I:
    1. parse the html and extract the variables
    2. take the leaf that I sent from server to client and update the json (I'm parsing the leaf on the client and updating it from the html elements)
    3. then I send the updated leaf up to my server and it forwards it to OS
    4. then I send all the updated images back to the client from my server & OS servers for updating

    I'm doing more than just getting a config leaf. I'm parsing the data and creating HTML to display on the client. Then an onchange handler in the client sends the round robin response. 

    Here's the code in action:
    https://rustyshed.com/?quill=5fed5590dd784a11e1364a0e



  • Options
    matthew_stacymatthew_stacy Member Posts: 476 PRO
    Hi Billy,

    The rusty shed example is very relevant to what I am attempting to implement.  The code that you sent over is making my eyes glaze over (it's me, not you), but I will wade through it.  Thanks so much for the help.
  • Options
    billy2billy2 Member, OS Professional, Mentor, Developers, User Group Leader Posts: 2,015 PRO
    edited November 2021
    Here's a brief overview.

    It's the rest API protocol used by everybody in the cloud. It doesn't matter what language you're using because it's the same steps. Is it worth learning? Yes, it's the future. You're doing good, you're trying. All you need is on the cloud and it's all free. 

    There's 3 computers involved:
    1. the client (in my case, google chrome browser)
    2. my server (rustyshed)
    3. OS server

    It's asynchronous because you just don't know how long things are going to take.  It's all JSON which is kinda hard if you don't know javascript.

    I built my server from a fresh ubuntu instance. I wouldn't do that today and would spin up a container of ubuntu, nginx & nodejs. In fact I'll probably refactor my site to a newer server install. I'll probably host with google (gcp). When it's up I'll just reroute the DNS server to my new site. 

    I like nodejs because it's built around server communication. I'm also running sockets which makes the client to my server communication simple. When I open my computer in the morning, socket re-connects with the server. It really is painless and tightly integrated with nodejs. Javascript everywhere is both good and bad. I'm not having to convert data from one format to another on 3 different computers. JSON is native to javascript. The bad is keeping track where the code is running. In the code I shared, I'm parsing the returned config object on my server vs. sending it to the client and letting your computer parse the data. If you go with nodejs, to update this issue, you can cut the code out of the server and paste it into the client and it'll work with minor clean up. 

    I like nodejs and would recommend it if your starting out. 


Sign In or Register to comment.