cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Announcements
What’s new: end-to-end encryption, Replay and Dash updates. Find out more about these updates, new features and more here.

Dropbox API Support & Feedback

Find help with the Dropbox API from other developers.

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

downloading an image using dropbox API

downloading an image using dropbox API

squidlauncher64
Explorer | Level 3

Hello,

 

I am trying to download an image from dropbox api in react native. I am getting a success code: '200' and the response says that it is ok. I have included some of the javascript code below: 

 

const response = await fetch('https://content.dropboxapi.com/2/files/download', {
            method: 'POST',
            headers: {
              Authorization: `Bearer ${accessToken}`,
              'Dropbox-API-Arg': JSON.stringify({
                path: '/example.jpg'
              }),
            }
          });
      if (!response.ok) {
        console.error('Failed to fetch folder contents:', response.status, response.statusText);
        return;
      }
      else{
        console.log('response is ok')
      }
 
   const fileContentData = await response.blob();
   const fileData = encode(fileContentData)
 

I don't understand where the data is going/being placed. Would it be in the blob? or is it in response.text()? I did console.log the response.text and saw lots of data there that was random ascii characters which I assumed was the binary data from the image. I tried to encode the data from response.text and got an error stating that there were characters that could not be turned into base64. I also tried converting the blob into base64 and only got around 20 to 50 characters which doesn't seem correct when my image is around 4 mB. I am a beginner at interacting with APIs maybe there's something I am missing? maybe I need to turn the response.text into a blob object? Any help would be greatly appreciated.

1 Accepted Solution

Accepted Solutions

Здравко
Legendary | Level 20

Hi @squidlauncher64,

You didn't account that 'blob' method doesn't return actual blob, but Promise object wrapping this blob! That's where all your troubles come from. Also when you try to stringify some object, you're getting object declaration (no actual data) and that's why appear so short result - "[object Object]" - i.e. one more mess. 🙂

You have to handle correct type in correct way. A simplistic example follows:

var reader = new FileReader();
await fetch(...all staff here...).then((r)=>r.blob()).then((b)=>reader.readAsDataURL(b));
var b64encoded = reader.result;
var rawBase64 = b64encoded.slice(b64encoded.search(',')+1);

Depending on what you need either full encoded result (b64encoded) can be used or only the actual/raw base64 encoded string part (rawBase64). 😉

Hope this helps.

View solution in original post

9 Replies 9

Greg-DB
Dropbox Staff

The /2/files/download endpoint is a "content-download" style endpoint, meaning that on a successful call, the raw requested file data is returned in the response body.

 

I see you're not using an official Dropbox SDK, so you may need to refer to the documentation for your client/platform for information on how to handle data in responses like this. We can't offer support for that itself as it's not made by Dropbox.

 

For example, there's some documentation for fetch here, with an example of using blob() to retrieve image data.

squidlauncher64
Explorer | Level 3

From my understanding, you are saying that the image data should be located within response.body. Is that correct? I am not using the dropbox SDK but I am interacting with the dropbox API following the instructions as described by the download http documentation. When I console.logged the response I got from the dropbox api here is what it said: 

 

LOG {"_bodyBlob": {"_data": {"__collector": [Object], "blobId": "bbf7e68a-80ac-4c97-ae88-c2808166666e", "offset": 0, "size": 4808078}}, "_bodyInit": {"_data": {"__collector": [Object], "blobId": "bbf7e68a-80ac-4c97-ae88-c2808166666e", "offset": 0, "size": 4808078}}, "bodyUsed": false, "headers": {"map": {"accept-encoding": "identity,gzip", "accept-ranges": "bytes", "cache-control": "no-cache", "content-length": "4808078", "content-type": "application/octet-stream", "date": "Fri, 18 Aug 2023 16:38:30 GMT", "dropbox-api-result": "{\"name\": \"test.jpg\", \"path_lower\": \"/pictures/test/misc/test.jpg\", \"path_display\": \"/Pictures/Test/MISC/test.jpg\", \"id\": \"id:q1a6odEFxL4AAAAAAAAo_A\", \"client_modified\": \"2023-07-30T18:40:28Z\", \"server_modified\": \"2023-07-30T18:40:28Z\", \"rev\": \"601b8a5decf8269e55553\", \"size\": 4808078, \"media_info\": {\".tag\": \"metadata\", \"metadata\": {\".tag\": \"photo\", \"dimensions\": {\"height\": 3960, \"width\": 2640}, \"time_taken\": \"2019-07-09T10:39:36Z\"}}, \"is_downloadable\": true, \"content_hash\": \"40b0819017193231c2ba795f6f54e871623e6ac845814912fcb751749c984075\"}", "etag": "W/\"601b8a5decf8269e55553\"", "original-content-length": "4808078", "server": "envoy", "strict-transport-security": "max-age=31536000; includeSubDomains; preload", "x-dropbox-request-id": "92f211e8055140f6bb43cc0354b0f485", "x-dropbox-response-origin": "far_remote", "x-robots-tag": "noindex, nofollow, noimageindex", "x-server-response-time": "501"}}, "ok": true, "status": 200, "statusText": "", "type": "default", "url": "https://content.dropboxapi.com/2/files/download"} 

 

This is using the code shown in my first post. It says in the log 'bodyUsed: false' which makes me believe that response.body doesn't exist. So where would the image data be? 

 

I did find this one sentence that might describe where the data is according to dropbox's documentation. 'The response body contains file content, so the result will appear as JSON in the Dropbox-API-Result response header.' I have checked the Dropbox-API-Result and have only found the file metaData there. There is a chance I am doing something weird in my request to dropbox and thats why the body isn't being sent? Maybe the image data is somewhere else? Any help would be greatly appreciated.  

Greg-DB
Dropbox Staff

The file data would be in the response body, but not necessarily in a variable named 'response.body'. Exactly how you access it will depend on the network client you're using.

 

In this case, I see you're using 'fetch' as your network client, so I suggest referring to the fetch documentation I linked to in my previous message for information on how that works and how to access the data using that. For instance, it looks like using 'response.blob()' would make sense for your use case; that should contain the actual file data. I don't have context on exactly what you want to do with that data though, so what you do with it from there is up to you.

 

For reference, according to the documentation, the 'bodyUsed' property indicates if the body has already been read, not if it exists in the response to begin with.

 

For reference, the 'Dropbox-API-Result' header is a response header, which is separate from the response body. The 'Dropbox-API-Result' response header only contains the file metadata, not the file data.

squidlauncher64
Explorer | Level 3

You are correct about how the response object works, and how bodyused works. I didn't quite understand that so thank you for pointing me to the documentation. What I am trying to do is download an image from dropbox using the api that the user selects and display it for the user. I know that the image component in react native can take base64 data. I tested it with a local asset image. So the general process as I understand it is, 1) download the image from dropbox as a blob. 2) convert it to base64 3) display it on the screen for the user. I am running into problems with the second step and I want to make sure I am using this correctly. The code I am using is included below:

 

  const startUp = async () => {
   
    const response = await fetch('https://content.dropboxapi.com/2/files/download', {
            method: 'POST',
            headers: {
              Authorization: `Bearer ${accessToken}`,
              'Dropbox-API-Arg': JSON.stringify({
                path: '/Pictures/Test/MISC/test.jpg'
              }),
            }
          });
      if (!response.ok) {
        console.error('Failed to fetch folder contents:', response.status, response.statusText);
        return;
      }
      else{
        console.log('response is ok')
      }
 
      const fileContentData = await response.blob()
      const fileData = encode(fileContentData)
      console.log('fileData:', fileData)
 
Now I know that the encode function works because I use it for authentication with dropbox api. I use it for PKCE authentication for encoding the code challenge. Now when I run this I get:
 
LOG fileData: W29iamVjdCBPYmplY3Rd
 
This seems too short to me for a 4 mb picture. Another interesting thing is that I have changed it from the test.jpg to another image and it output the sane base64 string. I have tried using the code like this according to the documentation and I get an error stating that it cannot create a URL from the blob: 
 
  const startUp = async () => {
   
    const response = await fetch('https://content.dropboxapi.com/2/files/download', {
            method: 'POST',
            headers: {
              Authorization: `Bearer ${accessToken}`,
              'Dropbox-API-Arg': JSON.stringify({
                path: '/Pictures/Test/MISC/test.jpg'
              }),
            }
          });
      if (!response.ok) {
        console.error('Failed to fetch folder contents:', response.status, response.statusText);
        return;
      }
      else{
        console.log('response is ok')
      }
 
      const fileContentData = await response.blob()
      const imageUrl = URL.createObjectURL(fileContentData);
      const fileData = encode(imageUrl)
      console.log('fileData:', fileData)
 
Now all this code can be wrong because I am a complete novice when it comes to using apis. With this I have some questions: Why is the base64 encoded data so short? From the documentation it seems like I am getting the 'response.blob' correctly. why does the second code throw the error? Do you see anything wrong with these code snippets I have provided?
 
On a side note: The main idea for using dropbox api directly and not using dropbox sdk is because I have interacted with spotify api in another project so I thought this would be rather straight forward just following the documentation. I have never used an sdk before and kind of seem intimidated by it. My main concern is performance. I would like the image to be ready for the user as soon as possible. Thats kind of why I am not saving the image anywhere. I am directly going from base64 encoding to image. So the question is would using the dropbox sdk improve performance? would it download the images faster and display it to the user quicker than using the dropbox api? would the dropbox sdk store the image somewhere else that i'd have to fetch i.e. a downloads folder? Where would it put the image? 
 
Thanks again for all your help!
 

Здравко
Legendary | Level 20

Hi @squidlauncher64,

You didn't account that 'blob' method doesn't return actual blob, but Promise object wrapping this blob! That's where all your troubles come from. Also when you try to stringify some object, you're getting object declaration (no actual data) and that's why appear so short result - "[object Object]" - i.e. one more mess. 🙂

You have to handle correct type in correct way. A simplistic example follows:

var reader = new FileReader();
await fetch(...all staff here...).then((r)=>r.blob()).then((b)=>reader.readAsDataURL(b));
var b64encoded = reader.result;
var rawBase64 = b64encoded.slice(b64encoded.search(',')+1);

Depending on what you need either full encoded result (b64encoded) can be used or only the actual/raw base64 encoded string part (rawBase64). 😉

Hope this helps.

Greg-DB
Dropbox Staff

@squidlauncher64 I see Здравко helpfully offered insight on the issue.

 

As for your other questions, no, the Dropbox SDK wouldn't improve the performance; it uses the same API endpoints. It's just meant to make it easier for you to interact with the API, but it's not necessary. It also wouldn't save the data somewhere for you; it would likewise give the data to you directly for you to use as needed.

squidlauncher64
Explorer | Level 3

Hello @Здравко, Thank you for, your response, explaining how promises work, and sending me this code snippet. It really gave me a good place to troubleshoot and understand the issue. I was able to implement the code snippet provided and it worked! Thank you so much!

squidlauncher64
Explorer | Level 3

Thanks again for all your help @Greg-DB!

squidlauncher64
Explorer | Level 3

Hello @Здравко

 

Thank you for your response. Thank you for explaining the issue with resolving the promise and for the code snippet. This gave me a clearer understanding of the problem as a place to troubleshoot. I was able to solve my problem using the code snippet you provided with some modification. Thank you so much!

Need more support?
Who's talking

Top contributors to this post

  • User avatar
    squidlauncher64 Explorer | Level 3
  • User avatar
    Greg-DB Dropbox Staff
  • User avatar
    Здравко Legendary | Level 20
What do Dropbox user levels mean?