Delphi - DropBox

I state that I have activated everything you need on site dropbox.

Is there any example of how to upload and download files using delphi?

Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

I have a fully working Dropbox.pas unit that I wrote for my company that I'm using for my current project. Unfortunately I cannot provide it to you because it is owned by my company, but I can assist you if you have specific questions. I will outline the basics of my interface to get you started.

1. I use TIdHTTP to make the HTTP requests into their REST web service.
2. I use the open source OAuth.pas (Google it) for the OAuth; however, it has two major flaws. If you choose to go this route of writing your own interface and using OAuth.pas I can outline the bugs and what I had to do to correct them.
3. I use SuperObject JSON parser (Google it) to process the JSON results. I started my project under Delphi 2009 and am now on XE2. I understand that XE2 has JSON support, but I've stuck with SuperObject since it works well and I am familiar with it.

Those are the basic components that make up my application. You need to understand OAuth. The latest version of their API requires OAuth authentication including obtaining the request token, authorizing the user, and finally getting the access token. This is a critical step and there is a lot out there on the subject. You will find that many others will direct you to and tell you to read the info there. This is almost useless. It's like telling someone to read the entire manufacturer's service manual for their car when they ask how to change the oil. It's a much more complicated standard than what you really need to know for real world application, especially for communicating with Dropbox. Search OAuth and find some sites that outline the basic principles, then start playing with the API. Their dev forum is pretty good too.

Your HTTP requests must be formatted in a certain way to include both the OAuth parameters as well as any required for the particular API method you are using. The parameters, including the OAuth ones, are to be alpha sorted. This is one of the flaws of the OAuth.pas project. It does not alpha sort, it is easily corrected. Here is a sample call to get the metadata of a folder named test.

3/21/2012 2:39:28 PM

    GET: /1/metadata/sandbox/test?file_limit=10000&list=true&include_deleted=false&oauth_consumer_key=********************&oauth_nonce=07DE9EE58FE86DB711A77B8675E7183C&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1332358768&oauth_token=********************&oauth_version=1.0&oauth_signature=RTDYiCRIsXrB5yN%2Bkzs%2FMZX2KGo%3D



Open in new window

I know this sounds largely vague, but if you understand HTTP requests and TIdHTTP and then understand OAuth then making calls to the RESTful web service is a piece of cake.
danz67Author Commented:
I have find this article
but when run the project and put parametre for access i get this error

what wrong?
That other post uses version 0 of the API. They are on version 1 now, things are a little different. Review the documentation of the latest version for reference. In most cases it simply means change the "0" from the URLs to a "1" but in some cases there are other differences in the URL. I would start your application using version 1 in case things change. The request_token, authorize, and access_token methods should be the same, but the 1 needs to be in the URL.

The base URLs look like...

The sample code also does not use HTTPS. Not a huge deal, but if you are using TIdHTTP you can use HTTPS if you download OpenSSL library. First, get your stuff working and then Google TIdHTTP and SSL and set it up for SSL access.

That sample code looks good. It does things slightly different than how I did it, but it should still be OK. I setup my TOAuthRequest like this for example...

// When requesting the token...
  OAuthRequest := TOAuthRequest.Create('');
  HMAC := SignatureMethodClass.Create;
    { Generate and sign the request }
    OAuthRequest.HTTPURL :=  '';    OAuthRequest.FromConsumerAndToken(FOAuthConsumer, nil, '');
    OAuthRequest.Sign_Request(HMAC, FOAuthConsumer, nil);

Open in new window

It's a minor difference and probably has no impact.

So, why are you getting 401? Do you have a an API token/secret pair from Dropbox? If not, you need to obtain one first. If you do then chances are good that your app is not yet published. This means you can only access your own account. That is, the account that owns the API token/secret pair you are using. Until your app is published this is how it is. If you are doing these things then trap the return message from Dropbox. Wrap your HTTP.Get calls in a try except.

    { Log exceptions and re-raise }
    on E: EIdHTTPProtocolException do

Open in new window

E.Message above contains a message in JSON format that will be more helpful. Grab that and post it here. ***BUT*** That message WILL contain your super secret API token/secret pair. Anywhere in there that you see oauth_token=<something> or oauth_token_secret=<something> then replace <something> with * or similar to mask that before sharing. If you post it I'll look at it. That will help.
Exploring SharePoint 2016

Explore SharePoint 2016, the web-based, collaborative platform that integrates with Microsoft Office to provide intranets, secure document management, and collaboration so you can develop your online and offline capabilities.

danz67Author Commented:
nothing to do, I always error. I hope you will give me a complete and ready example that works with Delphi 7.
Thanks for your time, hello
Check following links...

Units/Tools to communicate with Dropbox using Delphi...
DropboxDelphi / Dropbox.pas

How to upload files with the Dropbox REST API

Dropbox api for Delphi?
nothing to do, I always error.

I do not understand. My previous reply included code to retrieve the error message. Your 401 error is accompanied by a very useful error message that will describe your problem. Somewhere in your code you are using an HTTP component, presumably TIdHTTP, to send a request to Dropbox. Wrap all of your "get" calls in a try..except and handle the EIdHTTPProtocolException exception. E.ErrorMessage will contain the full error message and this will help. I mistated E.Message in my first reply, but E.ErrorMessage is what you are after.

For example, I have modified my application to use API key that does not yet have production status from Dropbox. I then tried to login to another user's account. In both error messages below an HTTP 401 error was raised, but look at the error message that was returned. It tells me exactly what the error condition was! Please do this and send the message. The post you sent earlier should work fine, but again, it's version 0 of the API. At some point they will discontinue support for this. Modify that code to use version 1 of the API. The URLs have the following substring... "/0/" in them. Change those to "/1/"

        "error": "Access token not found."

Open in new window

        "error": "Only a limited set of users can receive access tokens while this app is in development mode"

Open in new window

danz67Author Commented:

forgive my inability to do what you asked me, I hope you can prove the project I have led Example DropBox Delphi and modify it to do it function properly, including file uploads, as I wrote in my initial request.
I know I ask too much but unfortunately I can not, hello and thanks
The sample app you sent should work for authentication, even if it does use version 0 of the API. I will confirm when I am in the office later. It is nearly identical to my project which works. If you are getting 401 errors during authentication the we must figure out why. I do not understand why you cannot trap the exception and review its message. This is standard debugging practice for any application.
I am on XE2 so I do not know if this will compile under D7, but try the following code. Use the attached unit in your project. Add it to your form's uses list and add two buttons and implement the OnCreate and OnDestroy handlers. Set the code in there as follows. Does your app have application folder access only or full access to Dropbox? If full access to Dropbox then FDropbox.Root below should be set to 'dropbox' otherwise if your app has application folder access only then leave it as is.

There are particular challenges here that you will need to overcome. I have not provided everything for you. I would like to see you show some initiative in learning how to do this. I have; however, provided a class that will authorize properly using the latest version of the API. It also has skeleton functions in there for uploading and downloading, but you will encounter problems in each. The download file routine should fail for you. If I recall correctly OAuth.pas returns an invalid signature string after authentication. (Hint) I think it has extra items in it. I have wrapped the HTTP call in try except and even write out the exception to your C:\ drive for you to look at. It should tell you exactly what the problem is. Upload file should fail for the same reason as DownloadFile, but it also uses the HTTP PUT method. OAuth.pas assumes that all calls are GET and thus signs non-GET requests incorrectly. You need to modify OAuth.pas.

I will be glad to help you with any questions you have, but you must try to understand what it is you are doing because if your application is something you want to share with others you will run into more issues with proxy servers and the like that are more complicated than simply putting a file on Dropbox.

The other sample code you have found is poorly written, uses the old API, and does not use HTTPS. This code uses HTTPS and in order for it to work you must download OpenSSL. Google it, it's an open source project. There are 2 DLLs that you need to put into the same folder as your executable.

procedure TForm1.Button1Click(Sender: TObject);
  FDropbox.AppKey := YourAppKey;
  FDropbox.AppSecret := YourAppSecret;

procedure TForm1.Button2Click(Sender: TObject);

procedure TForm1.FormCreate(Sender: TObject);
  FDropbox := TDropbox.Create;
  FDropbox.Root := 'sandbox';

procedure TForm1.FormDestroy(Sender: TObject);

Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
danz67Author Commented:
FDropbox where is declared?
In your form somewhere. Just add it to the private section of your form.
I should have said, for testing put it in your form somewhere. In a real world application you're probably better off creating a singleton somewhere that is accessible to all parts of your application that may need it.
danz67Author Commented:
Let me explain what I did:

1. I created a new project
2. I imported the Dropbox Unit that I have provided
3. I imported OAuth
4. I put 2 buttons
5. I put the code as attached as I have explained

I can only understand this blessed FDropbox where and how it developed.
I think the last point and then we're done, to implement the various methods for uploading and downloading as I take the official documentation of DropBox, I used already in an iPhone app that I made the other day.
Excuse me for my inability, but I have little familiarity with these things, thanks
Unless I am mistaken this is a place to ask for assistance when you get stumped. If you would like to hire me to write the code for you we can work something out. Until then if you are out of your league with Delphi you should perhaps start running through some of the demos to understand the basics of it. I'd also learn key debugging skills. It does not appear that you are familiar with exception handling and how to debug the error messages so I do not feel that you are capable of developing and maintaining the application with your current knowledge. I am more than willing to help you if you get into a bind with this. But I cannot give you my complete code that my company owns nor will I write the complete Dropbox code for you for free. It is unfortunate, but you seem unwilling to try this for yourself.

I think the last point and then we're done, to implement the various methods for uploading and downloadin

I assume that you have tried those methods in the code I sent. What error did you get? If it was an EIdHTTPProtocolException I've already handled that for you and placed the error message in a file for you. Look at the code and you will see where the error is saved to file. Assuming that you get an EIdHTTPProtocolException in DownloadFile or UploadFile it will be logged and the error message will tell you what is wrong. Be careful posting that to someone though because it will contain your API key/secret pair. You should mask those out prior to showing anyone.
danz67Author Commented:
Maybe I explained incorrectly (Google translate).
I have a good knowledge of Delphi, if you go on my site see what I can do. I not very familiar with Delphi but with this type of approach. I understand that you can not write code for me for free, so if it's a question of money let me know if you're willing to do this work for me. Thanks for your valuable time.
danz67Author Commented:
I am committed and I was able to run the code you gave me, I was very tired and could not concentrate. After pressing the button1 it opens the browser with request for access to Dropbox (or better authenticate the application), now I upload the files and I think we should use the put option, but how do I find a list of files on a grid?

Thanks for everything, hello
I will be in office tomorrow and can help better with my pc up. I'm glad you were able to authenticate. In my experience that was the hardest part.
> how do I find a list of files on a grid

This may have been lost in translation. I am not sure what you mean here.
OAuth.pas is open source. I've tried unsuccessfully to contact the author with my changes, but it seems to have a few issues. To TOAuthRequest I've added a new property called Method.

    property Method: string read FMethod write FMethod; // TOAuthRequest assumes HTTP GET always. Sometimes you need other methods.

Open in new window

Also, TOAuthSignatureMethod_HMAC_SHA1does not order the parameters correctly. This is evident when using Dropbox. The parameters in the URL including the OAuth params must be in alphabetical order before signing. To accommodate this you must modify the TOAuthSignatureMethod_HMAC_SHA1class in OAuth.pas or create a subclass as I've done and write a new build_signature method. If you go the subclass route the code I previously sent should be modified to create an instance of your TOAuthSignatureMethod_HMAC_SHA1 descendant. Here is my build_signature code.

@summary The original class has 2 main bugs. First, it assumes that GET is the
         only HTTP method used and has no support for POST, DELETE, etc. Second,
         the original class would always construct the base string by placing
         URL parameters first followed by the OAuth parameters. Per section 9.1.1
         of the OAuth specifications ( this
         is incorrect. The base string should be constructed such that all parameters
         including the OAuth ones are sorted in alphabetical order.
function TYourOAuthSignatureMethod_HMAC_SHA1.build_signature(Request: TOAuthRequest; Consumer: TOAuthConsumer; Token: TOAuthToken): string;
  function Base64Encode(const Input: TIdBytes): string;
    Result := TIdEncoderMIME.EncodeBytes(Input);

  function EncryptHMACSha1(Input, AKey: string): TIdBytes;
    with TIdHMACSHA1.Create do
      Key := ToBytes(AKey);
      Result := HashValue(ToBytes(Input));
  Parm, consec, toksec: string;
  SignableParams, Fields: TStringList;
  I: Integer;
//  inherited; // <------ NO!

  Fields := TStringList.Create;
  SignableParams := TStringList.Create;
    { Request.Fields is a string. We need the fields broken out into a list. }
    Fields.Delimiter := '&';
    Fields.DelimitedText := Request.Fields;

    { Params must be sorted to be OAuth compliant. See section 9.1.1 here: }
    SignableParams.Sorted := True;

    { Add all URL parameters }
    for I := 0 to Fields.Count - 1 do

    { Add all OAuth parameters, excluding oauth_signature }
    for I := 0 to Request.Parameters.Count - 1 do
      if Request.Parameters[I] <> 'oauth_signature' then

    { Build out the base string parameter }
    Parm := TOAuthUtil.urlEncodeRFC3986(Request.Scheme) +
      TOAuthUtil.urlEncodeRFC3986(Request.Host) +

    for I := 0 to SignableParams.Count - 1 do
      if I = 0 then
        Parm := Parm + '&'
        Parm := Parm + TOAuthUtil.URLEncodeRFC3986('&');

      Parm := Parm + TOAuthUtil.URLEncodeRFC3986(SignableParams[I]);

    { Set the base string }
    Request.BaseString := IfThen(Request.Method = '', 'GET', Request.Method) + '&' + Parm;

    { Generate the signature }
    if Token <> nil then
      consec := TOAuthUtil.urlEncodeRFC3986(Consumer.Secret);
      toksec := TOAuthUtil.urlEncodeRFC3986(Token.Secret);
      consec := consec + '&' + toksec;
      Result := Base64Encode(EncryptHMACSha1(Request.BaseString, consec))
      consec := TOAuthUtil.urlEncodeRFC3986(Consumer.Secret);
      consec := consec + '&';
      Result := Base64Encode(EncryptHMACSha1(Request.BaseString, consec));

Open in new window

I am not sure what implications, if any, this will have on other projects using OAuth for other web services, but for Dropbox it works well.
danz67Author Commented:
> This may have been lost in translation. I am not sure what you mean here.

Let me explain. I am interested in viewing file dropbox, directly into a grid
You would like a listing of all files that are stored in Dropbox and you would like to display them in a grid. Is this correct? Is so, use the /metadata Dropbox API method. It returns metadata for a file or folder. You can iterate the data populating any control that you want.

Read the documentation on Dropbox's site. It covers all of these things well for you. Using the class I sent you it is a fairly simple task to make the calls into the REST API and process the results. In an earlier reply I mentioned that I use SuperObject to process the JSON. You will need to process the JSON for /metadata. For upload and download files you can probably get away without it, but for /metadata you will need to process the results. Delphi 7 does not have a JSON parser so SuperObject is your best bet. Google SuperObject and you will find it. There are others, but this is the one I use and have found it to be adequate for the JSON returned by Dropbox.

Best of luck to you, but I am going to abandon this discussion. I do not see you attempting anything on your own and coming back with specific questions and full descriptions of your problems. I see only questions that look like someone is asking others for working code to do what they want. You are the developer and should be writing your code!

Keep the OAuth post above around as you might need that. ;-) It's an open source project after all so this is my contribution.
danz67Author Commented:
Everything you say is right, and accept all of your suggestions that I have been very useful. I posted this last question just because you asked me before.

Now it's up to me ... Hello and thank you all;)
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.