0

I am trying to download BIM360 docs files using javascript. I am able to get file response from BIM360 but unable to save file with proper content. Here is my JS code -

$(document).ready(function () {
    var anchor = $('.vcard-hyperlink');
    $.ajax({
        url: <file downloaded URL>,
        type: "GET",
        headers: {
            "Authorization": "Bearer " + <accessToken>
        },
        beforeSend: function (jqxhr) {

        },
        success: function (data) {
            // create a blob url representing the data
            var blob = new Blob([data]);
            var url = window.URL.createObjectURL(blob);
            // attach blob url to anchor element with download attribute
            var anchor = document.createElement('a');
            anchor.setAttribute('href', url);
            anchor.setAttribute('download', "test.docx");
            anchor.click();
            window.URL.revokeObjectURL(url);

        },
        error: function (jqxhr, textStatus, errorThrown) {
            console.log(textStatus, errorThrown)
        }
    });
});
sushilprj
  • 2,203
  • 1
  • 14
  • 19
  • Just a FYI that you should NOT use such approach, all communication with Forge should be performed server-side and the data should be exposed to your client page through controlled custom endpoints exposed by your own server app... Exposing a token to the client app would make your data vulnerable, it should be considered as a security issue. Give me the url of your app and I will harvest all the design data from your A360 account (potentially delete your files as well, depending which scope you used for that token) :) Use one of the server-side SDK that we made available to you – Felipe Jun 18 '18 at 12:33
  • Thanks @Philippe, I am using data:read scope and don't want stream the data from my server due to that I am using JS download approach. – sushilprj Jun 18 '18 at 15:08

1 Answers1

1

To download files from BIM360 service, I used a custom Ajax transports of the jQuery to creates new XMLHttpRequest and passes all the received data back to the jQuery, see here for the detail of the Ajax transports with jQuery.

/**
 *
 * jquery.binarytransport.js
 *
 * @description. jQuery ajax transport for making binary data type requests.
 * @version 1.0 
 * @author Henry Algus <henryalgus@gmail.com>
 *
 */
// use this transport for "binary" data type
$.ajaxTransport("+binary", function(options, originalOptions, jqXHR) {
    // check for conditions and support for blob / arraybuffer response type
    if (window.FormData && ((options.dataType && (options.dataType == 'binary')) || (options.data && ((window.ArrayBuffer && options.data instanceof ArrayBuffer) || (window.Blob && options.data instanceof Blob))))) {
        return {
            // create new XMLHttpRequest
            send: function(headers, callback) {
                // setup all variables
                var xhr = new XMLHttpRequest(),
                    url = options.url,
                    type = options.type,
                    async = options.async || true,
                    // blob or arraybuffer. Default is blob
                    dataType = options.responseType || "blob",
                    data = options.data || null,
                    username = options.username || null,
                    password = options.password || null;

                xhr.addEventListener('load', function() {
                    var data = {};
                    data[options.dataType] = xhr.response;
                    // make callback and send data
                    callback(xhr.status, xhr.statusText, data, xhr.getAllResponseHeaders());
                });

                xhr.open(type, url, async, username, password);

                // setup custom headers
                for (var i in headers) {
                    xhr.setRequestHeader(i, headers[i]);
                }

                xhr.responseType = dataType;
                xhr.send(data);
            },
            abort: function() {
                jqXHR.abort();
            }
        };
    }
});

The following code snippet is the code I used for downloading a file from BIM360 bucket via Forge Data Management API. With the above custom Ajax transports and dataType: 'binary', the API response will be processed as a blob. Afterward, we just need to create a blob URL and a temporary HTML link to open the blob URL for saving the downloaded file.

To obtain the actual file storage URL, you have to call API GET Item Versions, and the download link is the value of the storage.meta.link.href attribute of each item version data in the API response.

$(function() {

  $('a#download').click(function(event) {
    event.preventDefault();

    const filename = '2f536896-88c8-4dee-b0c1-cdeee231a028.zip';

    const settings = {
      crossDomain: true,
      url: 'https://developer.api.autodesk.com/oss/v2/buckets/wip.dm.prod/objects/' + filename,
      method: 'GET',
      dataType: 'binary',
      processData: false,
      headers: {
        Authorization: 'Bearer YOUR_ACCESS_TOKEN',
        Content-Type: 'application/octet-stream'
      }
    };

    $.ajax(settings).done(function (blob, textStatus, jqXHR) {
        console.log(blob );
        console.log(textStatus);

      if( navigator.msSaveBlob )
        return navigator.msSaveBlob(blob, filename);

      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.style = 'display: none';
      document.body.appendChild(a);

      a.href = url;
      a.download = filename;
      a.click();
      URL.revokeObjectURL(url);
    });
  });
})

Hope it helps.

Eason Kang
  • 6,155
  • 1
  • 7
  • 24