Generate Derivative Files
This tutorials builds off the Sync Releases and Revisions tutorial. Please complete that one before starting on this one.
It’s clear by now that Onshape doesn’t use files to store its data, instead it is a data driven solution that is always up to date. Files are a snapshot in time that provide a view of the design at a specific point in time - such as at a release or version. A new file is required for each “snapshot” and managing these files can get quite cumbersome. However, there are situations that require that files be generated from the Onshape data.
In general, we want files to be generated at defined points of time and within the context of a business process – such as a release process. The derived file could be a format such as a PDF of the drawing that is generated following the successful release of the data. Also, a common requirement is to generate STEP files or JT files that can be used in 3D Printing or viewers embedded in PLM solutions. Regardless of the use case Onshape has very good export capabilities for many different file formats.
This business case examines how to automatically generate files derived from the Onshape data. The process described here can be plugged into many different use cases. In this specific example we are plugging the translation use case into the Release Business case just after the release is completed in the third-party application and Onshape is updated. Since we already have all the relevant ID information for the parts to translate from the release package data, we can directly call the translation APIs after receiving notification that the release was successfully executed in Onshape.
Overview
Once we have received an HTTP 200 status from the call to Onshape to release the release Package, we can proceed with the translation. The reason why we may want to wait till the release has successfully completed could be for several reasons:
We are generating a PDF of the drawing and want the “In Progress” watermark removed, and the title block updated with release information
We are generating files for 3D printing or for sending to a vendor to manufacture and we only want to send released data
We can now make an API call to Onshape. In both the following cases we must pass the document Id, the version Id and element Id – all values that were available in the release package. Other values are dependent upon your specific use case and can be referenced in https://cad.onshape.com/glassworks/explorer/#/PartStudio/createPartStudioTranslation
For Assembly translation we can POST to :/api /assemblies/d/{did}/{wv}/{wvid}/e/{eid}/translations.
For Parts we can POST to: /api/partstudios/d/{did}/{wv}/{wvid}/e/{eid}/translations
Three variables of importance are returned from the API call to translate: requestState, id (of the translation) and resultExternalDataIds. We should store or keep this data in memory until the translation is completed. Depending upon the requestState there might be additional data available in the response.
We can now periodically ping the translation web service with the id retrieved in the last step. Using the GET call to /api/translation/{id} we will receive one of three responses in the requestState:
DONE
ACTIVE
FAILED
Depending on the response we can either continue to periodically ping the translation service if we received ACTIVE
Notify the user of a failed translation attempt if we received a FAILED response
Make a call to Onshape to GET the translated file if we received a DONE response. To retrieve the translated file make a GET request to /api/documents/d/{documentId}/externaldata/{externalDataId}
The file can now be stored in your third-party system or stored to an external drive depending upon your specific use case.
Implementation
As use cases go, this is a very straightforward process. The only complexity here is deciding how to receive the notification from Onshape that the translation has completed. There are several ways of implementing this including using a webhook to notify us when the translation completes. In the examples here I will show both the webhook methodology as well as pinging Onshape with a status request every couple of seconds. The status request can be initiated from the client through an AJAX call or, as in the example I use here, from the server.
In our example I have added a button to the interface of my third-party system that enables me to request a translated file. In this use case I have hard coded that the resulting file should be a STEP file – in a production ready implementation, we would expect that one or more formats are available and possibly selected by the user. In addition, a production ready implementation might have automated the translation for whenever a part is released. Other considerations for automation might include identifying what is being released. I.e. if it’s a part then translate to STEP, if it’s a Drawing then translate to PDF, etc. These are all very common use cases.
Initiate the Translation
The code snippet shown here is fairly straightforward. First it gets the ID of the part that was sent from the client, it then uses that ID to retrieve the part from the database. The part stored in our database already has all the required values to successfully communicate with Onshape, such as the document ID, the workspace ID and the element ID – all these values are used in the translation request.
In the body of the request we can see some of the required values that define how the part is to be translated to STEP. In this case I have only included the minimum required key pairs for this translation.
The REST API call to translate an Onshape element returns an object that includes the translationId – this is the value that will be used to ping Onshape and request the status of the translation.
Ping Onshape for Translation
In this code snippet I have simplified things by including a function that waits for a second and then pings Onshape again, It will continue pinging Onshape until it receives back a status that is not “ACTIVE”. Once the status returned is anything except “ACTIVE” it returns the resulting object back to the client.
The id used here is the translationId retrieved from the result object when the translation was initiated.
Once the requestState is changed, this will indicate that the translation has completed either with a FAIL or a DONE status. Depending on the result we can define our logic on the client appropriately.
The following shows the object returned to the client from the translation REST API. Note that the requestState is now set to “DONE”,, meaning that the translation has completed successfully.
With this data we can now request the file directly from Onshape. The ID that we need to use to retrieve the file is the “resultExternalDataIds”. Note that this is an array of values – since it makes sense that we might be translating more than one part.
Retrieve Translated File
With the resultExternalDataIds we can now retrieve the translated file from Onshape. The following code snippet does exactly this.
The Onshape REST API
https://cad.onshape.com/api/d/' + did + ‘/externaldata/’ + id
retrieves the translated file – in this case the ID is resultExternalDataIds[0] value.
Once this is completed, we use the response to save the file directly to our server where the application is hosted. Finally, I’m sending a JSON object to the client that provides a direct link to the file that is now hosted on our server.
The client can then request the translated file from our server, even though this is a function of the server and not related to Onshape, I have included a code snippet here that will send the file to the client.
In our sample implementation Once the translation has completed successfully I display a link to the translated file that calls the “getfile” endpoint shown above.
Clicking the link will cause the file to be downloaded as shown here.
Define Translation Webhooks
As we mentioned at the beginning of this section there is more than one way to receive notification back from Onshape that the translation has completed. We can also define a webhook that will notify us once the translation completes. The drawback with this methodology is that the webhook must be created for each translation and then deleted.
A complete example of this can be found at: https://github.com/onshape-public/app-gltf-viewer/blob/main/services/webhook-service.js
The following function is used in this application to define the webhook:
The following line would call this function once the user requests to initiate a translation.
WebhookService.registerWebhook(req.user.accessToken, req.session.passport.user.id, did)
Finally the endpoint registered with the webhook could be defined as follows:
In this case once the translation is completed, this endpoint receives a notification. If the event is equal to
onshape.model.translation.complete
We can assume that the translation has completed and we can unregister the webhook and retrieve the translated file.
The complete sample including it setup and deployment can be found at: https://github.com/onshape-public/app-gltf-viewer