0

I'm trying to post a base64-encoded PDF file to a Zendesk file upload API endpoint but the file URL returned from the API shows that the file is corrupted.

First I receive the PDF as a base64-encoded string from a separate API call. Let's call it base64String.

If I do window.open("data:application/pdf;base64," + base64String) I can view the PDF in my browser.

Now I am trying to follow the documentation here for uploading files via the API. I can successfully complete a cURL call as shown in the example. However, the jQuery AJAX call will corrupt the PDF file.

client.request({
  url: '/api/v2/uploads.json?filename=test.pdf',
  type: 'POST',
  data: atob(base64String),
  contentType: 'application/binary'
}).then(function(data) {
  window.open(data.upload.attachment.content_url);  // corrupt file
}, function(response) {
  console.log("Failed to upload file to Zendesk.");
  console.log(response);
});

Like I said, this will succeed but when I visit the content_url the PDF does not display. I am quite sure the file is being corrupt in the POST request.

I have tried uploading the file as a base64 string (without decoding with atob()) with no luck among other things.

UPDATE

I'm still not able to view the PDF after converting the base64 string to blob.

var blob = base64ToBlob(base64String);
console.log(blob);  // Blob {size:39574, type: "application/pdf"}

client.request({
  url: '/api/v2/uploads.json?filename=test.pdf',
  type: 'POST',
  data: blob,
  processData: false,
  contentType: 'application/pdf'
}).then(function(data) {
  window.open(data.upload.attachment.content_url);  // corrupt file
}, function(response) {
  console.log("Failed to upload file to Zendesk.");
  console.log(response);
});

function base64ToBlob(byteString) {
  // write the bytes of the string to an ArrayBuffer
  var ab = new ArrayBuffer(byteString.length);
  var ia = new Uint8Array(ab);
  for (var i = 0; i < byteString.length; i++) {
    ia[i] = byteString.charCodeAt(i);
  }

  // write the ArrayBuffer to a blob, and you're done
  var blob = new Blob([ab], {type: 'application/pdf'});
  return blob;
};
rosendin
  • 611
  • 1
  • 10
  • 18
  • Why do you set `contentType` to `"application/binary"`? – guest271314 Feb 13 '17 at 22:23
  • 1
    If you look at the [cURL example](https://developer.zendesk.com/rest_api/docs/core/attachments#upload-files) they have that header. – rosendin Feb 13 '17 at 22:24
  • Have you tried handling the POST request to the server with another language to make sure that it's a client problem? – user2867288 Feb 13 '17 at 22:26
  • It is a unique convention but it hasn't given me issues in the past. – rosendin Feb 13 '17 at 22:29
  • _"content_type string yes The content type of the image. Example value: "content_type": "image/png""_ Or, is that the response? Have you tried posting the full `data URI`, instead of only `base64` portion of `data URI`? `base64String` by itself is not a valid `data URI` representation of the file. _"It is a unique convention but it hasn't given me issues in the past."_ What have you tried in the past that was successful? – guest271314 Feb 13 '17 at 22:29
  • Try passing full `data URI` without wrapping in `atob()` call and setting `contentType` to `"application/pdf"`; or sending file as a `Blob` or `ArrayBuffer`, if the server can handle either of the two data types. – guest271314 Feb 13 '17 at 22:36
  • So posting `"data:application/pdf;base64," + base64String` instead of `atob(base64String)` did not work. I tried with `application/binary` and `application/pdf` `contentType`s. – rosendin Feb 13 '17 at 22:37
  • _"I can successfully complete a cURL call as shown in the example"_ How did you achieve success using `cURL`? What are the formats which server can handle? – guest271314 Feb 13 '17 at 22:40
  • Basically from within the file's directory I ran the cURL command but changed `@file.dat` to the name of my file. AFAIK `application/binary` and `application/pdf` both work in cURL. – rosendin Feb 13 '17 at 22:47
  • What did you pass as the file object at `cURL`? What is the value of `data.upload.attachment.content_url` at `.then()`? – guest271314 Feb 13 '17 at 22:50
  • Where does documentation describe expecting a `data URI` or `Blob` from `POST` request? – guest271314 Feb 13 '17 at 22:58
  • I passed a basic PDF file in the cURL request. `data.upload.attachment.content_url` is a download link for the file. – rosendin Feb 13 '17 at 23:03
  • Have you tried using `FormData()` with `contentType` set to `false`, `var fd = new FormData(); fd.append("file", blob); data:fd;`? Or using `XMLHttpRequest()` `request.send(blob)` or `fetch()` `fetch("url", {method:"POST", body:blob})` to `POST` `Blob`, instead of `jQuery.ajax()`? – guest271314 Feb 13 '17 at 23:08

1 Answers1

0

I learned that the Zendesk app framework uses a jQuery AJAX wrapper for requests and the arraybuffer type is unsupported, so the file was getting corrupted. The app framework team has fixed the issue.

rosendin
  • 611
  • 1
  • 10
  • 18