Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to upload PDF file to dropbox or google drive in React Native? #1

Closed
singhlovey opened this issue Mar 23, 2018 · 12 comments
Closed

Comments

@singhlovey
Copy link

singhlovey commented Mar 23, 2018

Hi,

First of all thanks for creating this plugin. I have integrated this plugin and now the thing is I want to upload PDF file to Dropbox as well as Google Drive.

I am able to get access token. But not able to upload pdf file to google drive or Dropbox. I know I am missing some steps. Below is my code that I have implemented.

REQUEST :-
RNFetchBlob.fetch('POST', 'https://www.googleapis.com/upload/drive/v3?uploadType=media', {
Authorization : user.accessToken,
'data': JSON.stringify({
path : "http://xyz.com/" + this.state.pdf,
mode : 'add',
autorename : true,
mute : false
}),
'Content-Type' : 'application/pdf',
})
.then((res) => {
console.log("response in success " + JSON.stringify(res));

  })
  .catch((err) => {
    console.log("response in error " + JSON.stringify(err));
    // error handling ..
  })

It will give below response inside success.

RESPONSE :-

response in success {"data":"Not Found","taskId":"njehngge5xm4hl33iynfog","type":"utf8","respInfo":{"respType":"","headers":{"alt-svc":"hq=":443"; ma=2592000; quic=51303432; quic=51303431; quic=51303339; quic=51303335,quic=":443"; ma=2592000; v="42,41,39,35"","server":"UploadServer","date":"Fri, 23 Mar 2018 06:50:13 GMT","content-length":"9","content-type":"text/html; charset=UTF-8","vary":"X-Origin","x-guploader-uploadid":"AEnB2UrlSTCFYVYabN_dzHqqr55dBKjosk8u0IQ3D4bcysJyp_KkaYSW4yrE2P4gziHgfKOUrZpfAxaSpBwV6D4-a0142hiYhA"},"redirects":["https://www.googleapis.com/upload/drive/v3?uploadType=media"],"timeout":false,"taskId":"njehngge5xm4hl33iynfog","state":"2","status":404,"rnfbEncode":"utf8"}}

Pleas help. I am stuck in this from past few days. Let me know if this is not sufficient information for you.

Thanks

@harzkr
Copy link

harzkr commented Mar 25, 2018

Hi @singhlovey ,
First of all, if you are using the simple upload from google drive rest,
https://developers.google.com/drive/v3/web/simple-upload
the url for post request is incorrect, a '/files' is missing, if you compare it with, the multipart link,
https://developers.google.com/drive/v3/web/multipart-upload

It's a mistake on the google docs end, and the correct link should be,
'https://www.googleapis.com/upload/drive/v3/files?uploadType=media'
I have tested it and it works alright.

Next the required headers for google drive upload are not correct, the ones in your request are only for dropbox, so you should try the above with this url,
'https://content.dropboxapi.com/2/files/upload' as mentioned in the example of react-native-fetch-blob docs, and the content-type should be 'application/octet-stream', as mentioned there.

RNFetchBlob.fetch('POST', 'https://content.dropboxapi.com/2/files/upload', {
    // dropbox upload headers
    Authorization : "Bearer access-token...",
    'Dropbox-API-Arg': JSON.stringify({
      path : '/img-from-react-native.png',
      mode : 'add',
      autorename : true,
      mute : false
    }),
    'Content-Type' : 'application/octet-stream',
    // Change BASE64 encoded data to a file path with prefix `RNFetchBlob-file://`.
    // Or simply wrap the file path with RNFetchBlob.wrap().
  }, RNFetchBlob.wrap(PATH_TO_THE_FILE))
  .then((res) => {
    console.log(res.text())
  })
  .catch((err) => {
    // error handling ..
  })

and where is your RNFetchBlob.wrap(PATH_TO_THE_FILE), the data to your file.

Okay and back to the google drive thing,
dont forget to add, 'Content-Length' header as mentioned there and wrap your file as above, modify the url as I mentioned first, and you will be good to go!

@singhlovey
Copy link
Author

@harzkr
Thanks for your reply.

Okay I have done the changes as mentioned above but i am not understanding which file path I need to pass under 'path' property of an object and for PATH_TO_THE_FILE.

Here I am passing file path which exists under my project's folder.

I am little bit confused here. can you please clarify which should be the correct file path?

Thanks

@harzkr
Copy link

harzkr commented Mar 26, 2018

@singhlovey

Okay so for the dropbox api, the path property of the object, inside JSON.stringify, is the path in which the uploaded file gets stored at within the dropbox folder system. So in the above case, it gets stored as the png file under the root/home directory of dropbox, if you were to give a value,
'/folder1/folder2/img-from-react-native.png' , it will get stored in folder2 inside folder1 etc etc.

And as you mention, yes, the PATH_TO_THE_FILE, is the path of the stored file inside your project. It may be in /content/com.projectname/ or /data/data/.. or from external storage,
you might want to have a look at this link from the wiki docs,

https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API

for a complete idea of the file and directory system.(Please be careful while visiting the link, the project has been shifted, so make sure it's exactly the above, with wkh237, copy and paste it rather than clicking it)

Well do remember that the path in JSON.stringify is ONLY for dropbox api, there is NO 'data' part for google drive.

I hope I was clear and you'd be able to resolve the issue!

@singhlovey
Copy link
Author

singhlovey commented Mar 26, 2018

@harzkr

I have made the changes as per your suggestions.
Now my code look like as shown below.

     RNFS.readDir(RNFS.DocumentDirectoryPath) 
        .then((result) => {
        console.log('GOT RESULT', JSON.stringify(result));
       RNFetchBlob.fetch('POST', 'https://www.googleapis.com/upload/drive/v3/files?uploadType=media',{
         Authorization : String(user.accessToken),
         'Content-Type' : 'application/octet-stream',
        'Content-Length' : result[1].size
        }, "RNFetchBlob-file://" + RNFS.DocumentDirectoryPath + '/demo.pdf')
     .then((res) => {
         console.log("response in success" + res.text())
     })
  .catch((err) => {
    console.log("response in error" + err)
  })
   .then((contents) => {
     // log the file contents
     console.log(contents);
   })
   .catch((err) => {
   console.log(err.message, err.code);
   });

But now I got error :- RNFetchBlob request error: TypeError: expected dynamic type string', but had type int64'null

NOTE:- I am using react-native-fs plugin to fetch path of storage files.

Please let me know where I am wrong?

@harzkr
Copy link

harzkr commented Mar 26, 2018

@singhlovey

I think the problem is with the result[1].size, it should be a string and not an integer.
And though there is nothing particularly wrong with your method, just to be sure, that the right headers are passed, you can make the content length and other variables string before you call the function, and call the function stand-alone,
For example in your code,

    //new line 
     var func = this
     RNFS.readDir(RNFS.DocumentDirectoryPath) 
        .then((result) => {
            console.log('GOT RESULT', JSON.stringify(result));
             //new lines
             func.setState({
              size:result.size.toString(),
             })
            .then((contents) => {
                // log the file contents
                console.log(contents);
            })
           .catch((err) => {
           console.log(err.message, err.code);
       });

And call this function later, just be sure that the state has updated,

          RNFetchBlob.fetch('POST', 'https://www.googleapis.com/upload/drive/v3/filesuploadType=media',{
              Authorization : String(user.accessToken),
              'Content-Type' : 'application/octet-stream',
              'Content-Length' : this.state.size
          }, "RNFetchBlob-file://" + RNFS.DocumentDirectoryPath + '/demo.pdf')
          .then((res) => {
             console.log("response in success" + res.text())
         })
         .catch((err) => {
            console.log("response in error" + err)
         })

That should work

@singhlovey
Copy link
Author

singhlovey commented Mar 27, 2018

@harzkr

Many thanks to you!!!
I have modify some code and It works :)

QUERY :- How can I set pdf file name. currently it shows untitled.
NOTE:- I have tried to add like this also [{name : 'demo', filename : 'demo.pdf', data : RNFetchBlob.wrap(RNFS.DocumentDirectoryPath + '/demo.pdf')}] but still giving me untitled name.

One more thing. I have done this for google drive. Now I want to do the same for dropbox. can you suggest any react native plugin for dropbox login or authentication so that I can get access token of dropbox?

or how to authenticate user with dropbox in react native to upload file to dropbox as well?

Thanks

@harzkr
Copy link

harzkr commented Mar 27, 2018

@singhlovey

That's wonderful you got it working and you are welcome.

Well coming to authenticating with dropbox api, since I haven't been using it in any case scenarios, I do not have an idea of the packages that might be available for react native for the same.

However, you can check out auth0 it self, it's pretty reliable, darn easy to set up, is free for a limited time,
but does come at a price for regular usage. Here are some links, you might want to look at.

https://auth0.com/authenticate/react-native/dropbox/
https://auth0.com/pricing

But the best I'll say is to directly use the dropbox api itself, which you must have seen here,

https://www.dropbox.com/developers/documentation/http/documentation

Right at the beginning itself under 'Authorization', they have provided everything you will need for authorization, make a GET request at, with your parameters created at the app dashboard at Dropbox,
(more info on everything about setting up here https://www.dropbox.com/developers/reference/oauth-guide )

https://www.dropbox.com/oauth2/authorize

You will get a response object like this [REDIRECT_URI]?code=ABCDEFG&state=[STATE]

Then call this url with a POST request with the above code( all descriptions in the docs), and you will get your bearer token.

https://api.dropboxapi.com/oauth2/token

That should take care of the authentication, and as I mentioned I haven't used dropbox api, but the instructions on the docs are pretty simple and achieve the results in a straightforward manner.
Hope that helps!

@singhlovey
Copy link
Author

@harzkr

Thanks. I will try and get back to you if any problem.

QUERY :- How can I set pdf file name. currently it shows untitled.
NOTE:- I have tried to add like this also [{name : 'demo', filename : 'demo.pdf', data : RNFetchBlob.wrap(RNFS.DocumentDirectoryPath + '/demo.pdf')}] but still giving me untitled name. How to set meaningful pdf file name?

Thanks

@harzkr
Copy link

harzkr commented Mar 27, 2018

Hey Hi @singhlovey
I saw your edited comment now, which you have asked above,

Yeah the simple upload request for google drive is only for the file and not for any metadata, so no format will work which will upload the name to the file through that url.

You can see more here https://developers.google.com/drive/v3/reference/files/create
where two separate urls are given for file upload and uploading the metadata separately.

So there is resumable and multipart uploads, which you can check here,
https://developers.google.com/drive/v3/web/multipart-upload
https://developers.google.com/drive/v3/web/resumable-upload

Both of them have direct sending of the metadata, but the body part of the request is a bit muddled up, you would have to create the multipart body exactly as specified there(and it does become a problem sometimes)

Here are a few links discussing the metadata issue, you can have a look,
https://stackoverflow.com/questions/41492692/upload-and-name-a-file-using-google-drive-rest-api-v3-and-angular-2
https://stackoverflow.com/questions/10317638/how-do-i-add-create-insert-files-to-google-drive-through-the-api/10323612#10323612

They mainly achieve it using the drive file api from googleapis, you can check out the drive.files.create
from the API explorer here https://developers.google.com/apis-explorer/#p/

So basically there are a lot of options, but the simplest one( according to me), which I use,
is the updating of file, https://developers.google.com/drive/v3/reference/files/update

I post a request to https://www.googleapis.com/drive/v3/files with a json file with my name, mimetype. content etc., and then get the fileid from there , and then update the fileid with the patch request to
https://www.googleapis.com/upload/drive/v3/files/fileId , with my contents, and there you will have it,
I am posting my code below for your reference, my use case is an audio/aac file upload.

       //read the file and get the size, name etc. and set them in state variables
        var func = this
        const res = await fetch('https://www.googleapis.com/drive/v3/files', {
          method: 'POST',
          headers: {
            'Authorization': auth,
            'Content-Type':'application/json'
          },
          body:JSON.stringify({
            "name": func.state.name,"mimeType": "audio/aac","description": "Stuff about the file"
          }),
        })
        const json = await res.json()
        console.log(json)
        func.setState({
          fileiden:json.id
        }, function(){
          
     RNFetchBlob.fetch('PATCH',`https://www.googleapis.com/upload/drive/v3/files/${func.state.fileiden}`,{
              'Authorization' : auth,
              'Content-Type' : 'audio/aac',
              'Content-Length':func.state.size.toString()
            },RNFetchBlob.wrap(func.state.target))
            .then((res) => {
              console.log("response",res.json())
            })
            .catch((err) => {
              console.log("error",err)
            })
        })

You can get the job done, through any of the methods above, hope I was clear, if not, do ask me

@Southporter
Copy link

This issue seems to have been resolved and inactive. Closing due to inactivity.

@uendar
Copy link

uendar commented Jun 17, 2019

I use the same method to get the id from the file as above :

fetch('https://www.googleapis.com/drive/v3/files', {
                   method: 'POST',
                   headers: {
                     "Authorization" : `Bearer ${this.state.accesToken}`,
                     'Content-Type':'application/json'
                   },
                   body:JSON.stringify({
                     "name": file.fileName,"mimeType": file.type
                   })
                 }).then((response)=>{
                     console.log(response.status)
                     if(response.status === 200){
                       return response.json();
                     }else{
                       this.setState({isUploading:false})
               
                     }
                 }).then((responseJson)=>{
                     console.log(responseJson)
                    if(responseJson.id ){
                      console.log(responseJson.id)
                     }
                 }).catch((err)=>{
                     console.log(err)
                 });

but i get 401. Any idea how to resolve this @harzkr

@harzkr
Copy link

harzkr commented Jun 18, 2019

Hey Hi @uendar
It has been a while since I used the API, though on checking out the errors page for google drive API, it seems your credentials are incorrect, 401, and in general it is the response for invalid authorisation.
Have a look at their page maybe it will help you resolve this.
Screen Shot 2019-06-18 at 9 11 14 AM

Traviskn pushed a commit that referenced this issue Sep 26, 2019
Hash - changed to chunk size instead of reading entire file
Sevellion added a commit to Sevellion/rn-fetch-blob that referenced this issue Nov 2, 2020
rpenfold pushed a commit that referenced this issue Apr 4, 2022
Syncing with main branch, support for 0.60
cguino pushed a commit to BeApp/rn-fetch-blob that referenced this issue Jul 5, 2023
[FEAT] Add Flow specs - New Arch Migration 1/n
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants