Dropbox REST API Part 2: API Requests

January 8, 2012

IntroductionDropBox Logo

In the previous article, Dropbox REST API Part 1: Authentication, I showed you how you can obtain an access token using the Dropbox REST API and OAuth.

Once you have an access token, you can use it to access the main Dropbox REST API. Let’s demonstrate this by using some of the API’s requests such as retrieving account information and file (and directory) metadata.

It’s actually surprisingly easy. In the next part we’ll explore other options such as creating, deleting and moving folders.

Let’s get started…

Table Of Contents

Account

I took the source code from the first article (#62) in this series and structured it a bit differently, but in essence it still performs the same functionality. In this post I’ll only list the source code necessary to retrieve account information and file/folder metadata. You can check out how to retrieve an access token by reading the previous article and/or checking out the source code of this post.

Using the refactored code retrieving account information is very simple.

var accessToken = ...;
var api = new DropboxApi("your API key", "your API secret", accessToken);
var account = api.GetAccountInfo();

I created a class called DropboxApi. When creating an instance of this class you pass it your API key and secret (consumer key and secret) and an access token. By calling the GetAccountInfo() method you can retrieve information about the user’s Dropbox account.

The GetAccountInfo() method executes the following code:

public Account GetAccountInfo()
{
    var uri = new Uri(new Uri(DropboxRestApi.BaseUri), "account/info");
    var json = GetResponse(uri);
    return ParseJson<Account>(json);
}

The DropboxRestApi.BaseUri returns the base URL for the REST API, namely https://api.dropbox.com/1. To retrieve the account information you need to append account/info to it. Thus behind the scenes a request is sent to:

https://api.dropbox.com/1/account/info

You need to sign this request using your consumer key, secret and access token. If you don’t sign the request you’ll receive the error “Invalid OAuth request”.

During the authentication phase you already saw how to sign a request using OAuth. Well…you can reuse that same code. Just check out the previous article to see how signing requests works.

To make it easy I moved this code into its own class called OAuth. Using this class you can sign a request using just two lines of code:

var oauth = new OAuth();
var requestUri = oauth.SignRequest(
    uri, "API key", "API secret", accessToken);

Just create a new instance of the OAuth class and call the SignRequest(…) method. Pass in the URI you wish to sign, your API key and secret and your access token.

This will transform:

https://api.dropbox.com/1/account/info

into something like this:

https://api.dropbox.com/1/account/info?oauth_consumer_key=YourAPIKey&oauth_token=YourToken&oauth_nonce=6880853& oauth_timestamp=1326020204&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&oauth_signature=9ukNkB/FZx3gHTT5TWP0hIkNe9z=

The GetAccountInfo() method does this by calling the GetResponse(…) method. This method signs the request, sends it and returns the response.

private string GetResponse(Uri uri)
{
    var oauth = new OAuth();
    var requestUri = oauth.SignRequest(
        uri, _consumerKey, _consumerSecret, _accessToken);
    var request = (HttpWebRequest) WebRequest.Create(requestUri);
    request.Method = WebRequestMethods.Http.Get;
    var response = request.GetResponse();
    var reader = new StreamReader(response.GetResponseStream());
    return reader.ReadToEnd();
}

The Dropbox REST API returns it responses in JSON format. Here’s an example response containing account information:

{
    "referral_link": "https://www.dropbox.com/referrals/r1a2n3d4m5s6t7",
    "display_name": "John P. User",
    "uid": 12345678,
    "country": "US",
    "quota_info": {
        "shared": 253738410565,
        "quota": 107374182400000,
        "normal": 680031877871
    },
    "email": "john@example.com"
}

It contains some general information about the user (id, name, e-mail address…) and his allocated quota. Using the Json.NET library we can easily deserialize this data into a .NET object. Let’s create a simple Account class into which we can deserialize this data.

[JsonObject(MemberSerialization.OptIn)]
public class Account
{
    [JsonProperty(PropertyName = "uid")]
    public int Id { get; internal set; }

    [JsonProperty(PropertyName = "referral_link")]
    public string ReferralLink { get; internal set; }

    [JsonProperty(PropertyName = "display_name")]
    public string DisplayName { get; internal set; }

    [JsonProperty(PropertyName = "email")]
    public string Email { get; internal set; }

    [JsonProperty(PropertyName = "country")]
    public string Country { get; internal set; }

    [JsonProperty(PropertyName = "quota_info")]
    public Quota Quota { get; internal set; }
}

The Quota type is equally simple.

[JsonObject(MemberSerialization.OptIn)]
public class Quota
{
    [JsonProperty(PropertyName = "quota")]
    public long Total { get; internal set; }

    [JsonProperty(PropertyName = "shared")]
    public long Shared { get; internal set; }

    [JsonProperty(PropertyName = "normal")]
    public long Normal { get; internal set; }
}

Don’t forget to install NuGet and to download the Json.NET library.

The last line of code of the GetAccountInfo() method deserializes the JSON data by calling the ParseJson(…) method;

private static T ParseJson<T>(string json) where T : class, new()
{
    var jobject = JObject.Parse(json);
    return JsonConvert.DeserializeObject<T>(jobject.ToString());
}

Just parse the JSON data and use the JsonConvert type to deserialize it into the type specified by the generic T parameter. As long as the type specified by T has been decorated with the correct Json.NET attributes it will deserialize without a problem.

Top of page

Metadata

By now you’ve seen how to retrieve the account information. It’s consists out of 3 steps, namely:

  1. Compose the URI for the request
  2. Sign and send the request
  3. Parse the response (JSON) into a .NET object

Most (if not all) of the Dropbox API requests can be dealt with in the same fashion. For instance, retrieving a list of files/folders that are stored in our Dropbox can be done in the same way.

var api = new DropboxApi(ConsumerKey, ConsumerSecret, accessToken);
var publicFolder = api.GetFiles("dropbox", "Public");
foreach (var file in publicFolder.Contents)
{
    Console.WriteLine(file.Path);
}

Here I retrieve a list of files/folders that are stored in my public Dropbox folder. The first parameter specified the root. Valid values are sandbox and dropbox. The second parameter specifies the path of the file or folder relative to the root.

Retrieving a list of files/folders supports many more parameters, but to keep things simple I’ve chosen to only support these two parameters. For a complete list check out the Dropbox REST API documentation:

https://www.dropbox.com/developers/reference/api#metadata

Apart from the URI and the return value (T) the GetFiles(…) methods looks identical to the GetAccountInfo() method.

public File GetFiles(string root, string path)
{
    var uri = new Uri(new Uri(DropboxRestApi.BaseUri), 
        String.Format("metadata/{0}/{1}", root, path));
    var json = GetResponse(uri);
    return ParseJson<File>(json);
}

The URI is composed, then the request is signed and send. Last, but not least the response (JSON) is parsed and converted to a .NET object of the type File.

The following listing contains a small part of the File type. It contains the metadata for a file or folder at a given path. If it is a directory (IsDirectory property) then the metadata will also include a listing of metadata for the folder’s contents (Contents property).

[JsonObject(MemberSerialization.OptIn)]
public class File
{
    [JsonProperty(PropertyName = "size")]
    public string Size { get; internal set; }

    [JsonProperty(PropertyName = "rev")]
    public string Revision { get; internal set; }

    [JsonProperty(PropertyName = "is_dir")]
    public bool IsDirectory { get; internal set; }

    [JsonProperty(PropertyName = "root")]
    public string Root { get; internal set; }

    [JsonProperty(PropertyName = "path")]
    public string Path { get; internal set; }

    [JsonProperty(PropertyName = "contents")]
    public IEnumerable<File> Contents { get; internal set; }

    //...
}

Example output:

File/Folder Metadata

Retrieving metadata works in exactly the same way as retrieving account information. With this code you are now armed to implement other Dropbox API requests. In the next part of this series I’ll explore some other requests concerning file operations (create, move and delete a folder).

Check out the Dropbox REST API documentation if you want to explore it further.

https://www.dropbox.com/developers/reference/api

You can download the source code accompanying this article from the download page. If you have any questions or suggestions please drop me an e-mail or submit a comment.

Top of page

Advertisements

40 Responses to “Dropbox REST API Part 2: API Requests”


  1. […] Dropbox REST API Part 2: API Requests (Christophe Geers) […]


  2. […] Dropbox REST API Part 2: API Requests (Christophe Geers) […]

  3. cap Says:

    Hi again, i was testing this and i have doubt with the path of the getFiles method:

    For example if we want to access the Public folder of the Dropbox, we can do it by this:

    var publicFolder = api.GetFiles(“dropbox”, “Public”);

    But i can’t access for example the folder (dropbox/Apps/My App), what wold be the right path for that folder?

  4. sunwangji Says:

    Yes, it threw the same exception in my side when getting files or folder. Any idea? Our app is on the development status.

    • Christophe Says:

      According to the Dropbox REST API documentation:

      http://www.dropbox.com/developers/reference/api

      an error code of 400 means

      “Bad input parameter. Error message should indicate which one and why.”

      Can you inspect the exception and see which message it returns? It should tell you which input parameter is incorrect. You can always copy the generated URL and paste in the browser’s address bar. You should then see the error message.

      Since my sample only uses the root and the path and none of the optional parameters you are likely trying to retrieve the metadata for a path that does not exist.

      Note that the sandbox environment is not a copy of the dropbox environment. It does not contains the same files, directories.

      Just try it without a path first. Only try to get the metadata for the root.

      var root = api.GetFiles(“dropbox”, “”);

      or

      var root = api.GetFiles(“sandbox”, “”);

      Then you can dig deeper and specify a path by using the returned metadata.

      • maha Says:

        i was not able to access my root contents in dropbox.

        it got exception stating- “system.net.webexception the remote server returned an error when accessing dropbox contents”

        when i removed public and just gave “” i was able to retrieve the file and folder names from my root.

        thanks a lot Christophe……

  5. sandeep sharma Says:

    i found this error please reply soon

    The remote server returned an error: (403) Forbidden at line 1 (marks as one)

    private string GetResponse(Uri uri)
    {
    var oauth = new OAuth();
    var requestUri = oauth.SignRequest(uri, _consumerKey, _consumerSecret, _accessToken);
    var request = (HttpWebRequest) WebRequest.Create(requestUri);
    request.Method = WebRequestMethods.Http.Post;
    // 1 var response = request.GetResponse();
    var reader = new StreamReader(response.GetResponseStream());
    return reader.ReadToEnd();
    }

    • Christophe Says:

      403 Forbidden usually from an invalid app key pair or other permanent error. Check your app key + secret and access token.

      Your application is probably not authorized or you are using an invalid access token. Hence you are not granted access, thus the 403: Forbidden error.

  6. Mason Says:

    Hi Christophe,

    Thanks for the great set of posts on working with Dropbox API in .net. It’s the best I’ve found on the web.

    However, I can’t get the files or thumbs?

    I try this
    var publicFolder = api.GetFiles(“dropbox”, “/Apps/Test2000”);

    and I get this
    The remote server returned an error: (403) Forbidden.

    I experimented with various path params like “Apps/Test2000” and @\Apps\Test2000, etc and I either get 400 or 403 errors.

    Interestingly, the getUserInfo works fine.

    Note, I saved the accessToken in a db

    var accessToken = oauth.GetAccessToken(new Uri(DropboxRestApi.BaseUri), Configuration.App.Configuration.ConsumerKey, Configuration.App.Configuration.ConsumerSecret, requestToken);
    if (accessToken != null)
    t.Update(new { token = accessToken.Token, secret = accessToken.Secret, isAuthorized = 1 }, found.id);

    As I understand from article 1 in the series, once that accessToken is gotten, one does not have to go through the authentication/authorization process again hence I use the one form the db. Which works fine for getUserInfo so the token, consumerToken and consumerSecret must be valid.

    I’m totally stumped and it is causing all kinds of delays in my project going forward. Please help.

    Thank you

    • Christophe Says:

      Judging by the path you are using (“Apps/Test2000”) I have the impression that you have set the access type of your application to “app folder” instead of “dropbox”.

      To quote the REST API documentation:

      “The default root level access type, app folder (as described in core concepts), is referenced in API URLs by its codename sandbox. This is the only place where such a distinction is made.”.

      Try specifying “sandbox” instead of “dropbox” for the GetFiles(…) method. Adjust the root parameter depending on your app’s access level.

      • Mason Says:

        Thanks! I didn’t realize the differentiation. Yes, my app is just a folder app, not full dropbox.

        Tweaked your suggestion slightly to this:
        var publicFolder = api.GetFiles(“sandbox”, “”);

        and it worked, but did not return what I thought it would. It returned meta data about the folder, but not the contents of the folder. I have 5 image files in the folder and it returned

        + Contents Count = 0
        IsDirectory true bool
        ThumbnailExists false bool

        Content = 0 and ThumbnailExist = false. Huh? Makes no sense.

        What I’m trying to do are 2 things and perhaps I’m not using the right api call.

        1. Display thumbnails of all images in the folder on a web page.
        2. Allow the user to select a thumbnail and then I download it and store it locally on my server.

        My app needs to provide 2 ways for a user to upload an image.
        1. Normal file upload control
        2. Dropbox

        The dropbox is really just used as a temp placeholder for the images. Is this type of functionality possible?

        P.S. What a great idea for your next blog article! 🙂

  7. Mason Says:

    Update, something got corrupted with the dropbox folder. I am now seeing the contents. However, not able to get thumbnails. I find the documentation confusing,but this is my understanding.

    Each file returned has the ThumbnailExists bool. If its true, then I would have to make another API call to get the thumbnail,

    Now I know the file is there as here is the code
    foreach(var f in publicFolder.Contents)
    {
    if (f.ThumbnailExists)
    {
    api.GetThumbnails(“sandbox”, f.Path);
    // just do 1 as a test, return view
    return View();
    }
    }

    Api code
    Here is how I make the api call. Extending your pattern for files

    var uri = new Uri(new Uri(DropboxRestApi.BaseContentUri), String.Format(“thumbnails/{0}/{1}”, root, path));
    var json = GetResponse(uri);

    Added uri because it uses content uri:
    public const string BaseContentUri = “https://api-content.dropbox.com/” + ApiVersion + “/”;

    final uri is:

    and it returns
    The remote server returned an error: (403) Forbidden.

    Any ideas/thoughts would be greatly appreciated.

    Many Thanks for your continued support!

    • Christophe Says:

      Check out the fourth article of this series. From a quick glance at the documentation downloading a thumbnail for an image works in the same fashion as downloading a file. Also make sure you correctly URL encode the path parameter (see article #3). Also debug the GetResponse(…) method, just before sending the request copy/past the signed request URI in your browser. You should get some more information about the error.

      PS: Your final request URI seems incorrect. The path parameter contains two slashes (//home2.png). Check out article #3 & #4. Best to write the URI in this fashion:

      https://api-content.dropbox.com/1/thumbnails?root=sandbox&path=%2Fhome2.png (/ is encoded as %2F).

      Article #3 explains the encoding issue in more detail.

      • Mason Says:

        i removed the / as the first character as this was causing an issue. I’m close, but can’t quite figure it out. The documentation states that it returns a thumbnail image

        Returns

        A thumbnail of the specified image’s contents.

        The HTTP response contains the content metadata in JSON format within an x-dropbox-metadata header. Note, not sure what that means?

        Second line of GetResponse
        var requestUri = oauth.SignRequest(uri, _consumerKey, _consumerSecret, _accessToken);

        Debugger is stopped. I extract the uri from this and place directly in a browser url and I get a thumbnail image. I didn’t even call anything, just put in the url. Yet I cannot view source so not sure whats happening.

        If I call this
        var reader = new StreamReader(response.GetResponseStream());
        return reader.ReadToEnd();

        the return value is like binary mumbo jumbo.

      • Christophe Says:

        Check out article #4 on how to download a file. You can follow the same logic for downloading a thumbnail…which is also a file. The article also mentions how you can extract the JSON data from the header. You cannot read the response stream as a string. Just read the article and you should find your answers.

  8. Mason Says:

    Thanks. I just tried and get an error

    var file = api.DownloadFile(“sandbox”, path); trace into DownloadFile…

    This line of the downloadFile method
    var response = request.GetResponse();

    throws The remote server returned an error: (403) Forbidden.

    This is the request uri

    https://api-content.dropbox.com/1/files?root=sandbox&path=home2.png?…

    Stumped and frustrated, but know I’m close so any help would be appreciated. And again, thanks for the quick responses and your continued support.

    • Christophe Says:

      Your request URL is incorrect. It contains two question marks ?.

      • Mason Says:

        Ha, just noticed you changed the signrequest method. Good catch. Tried it with new method and it works fine. However, with all due respect and you are way better at this than me, I don’t think I need to download the file to display the thumbnail. I get back the file and it even has a field ThumbnailExists=true. So now I have gone through all the bandwidth of downloading a file and have no idea how to display it as a thumbnail. I don’t want the file, I just want the thumbnail link. Certainly thats a lot less bandwidth than downloading the entire file. If I look at the doc for thumbnails, it doesn’t match. It says “Returns A thumbnail of the specified image’s contents.” It even gives parameters for image type and size. I don’t want to download the file, I simply want the thumbnail image link so I can display it on a web page. Then once a user selects it, then I will download it and save to my server and for that your download code is perfect. So I’m just missing the one vital step…displaying that darn thumbnail image.

        Have you tried to display a thumbnail on a web page? I just can’t seem to get it to work and this is a major stumbling block for me.

        Thanks again! 🙂

  9. Mason Says:

    Darn, its late and I’m tired. Just realized that I called download file, not thumbnail. Sorry about that. I will try with thumbnail api instead and see what I get.

    • Christophe Says:

      ThumbnailExists only indicates that the file is an image and can be converted to a thumbnail via the thumbnails calls. If you execute the thumbnails call then Dropbox will generate a thumbnail for you and will send that file back to you. It’s still a file download, although you are downloading the thumbnail this time and not the actual image. It’s up to your application to save and display it on a web page. You cannot retrieve a URL to a thumbnail image stored on Dropbox. The best you can do is to store images on Dropbox and have it generate thumbnails for it, which you can download.

      • Mason Says:

        Thank you for the explanation. So if I understand you correctly, I would have to download the smaller thumbnail image, save it to my server and then create a link from that image on my server to display it on a webpage?

        Thank you

      • Christophe Says:

        Bingo.

        Also check out their sharing feature. In the past you could only generate a public URL for any file in your Dropbox’s public folder. But now you can do this for any file/folder in your Dropbox. More information can be found here:

        https://www.dropbox.com/help/167

        Generating a public URL is supported by the API:

        https://www.dropbox.com/developers/reference/api#shares

        But this generates a link to the actual file (or image) itself and not a thumbnail version of it. You have to retrieve the thumbnail image first and store it yourself. But you can leave the actual image on your Dropbox and generate URLs for them.

      • Mason Says:

        Christophe, thank you so much for taking the time to explain. I understand it now. I had a different understanding and you really cleared things up for me.

        Thank you! 🙂

  10. Joe Says:

    Should I be required every time to allow the app to access my dropbox account. Every time I run this program I get the access request page.

  11. Manish Says:

    Hi i want to share dropbox file using my application i can’t b able to share plz help me how can i do that

  12. James Says:

    All works an absolute treat. Thanks so much for sharing this .NET implementation.

  13. vince Says:

    hi, while trying the getaccountinfo, the getresponse part always redirect to the login page of dropbox, and not returning the json format,i also found that the level is bypasscache, is the level wrong? i also tried logging in before trying it but still redirects to the login page using c#’s webbrowser component? am i doing something wrong?

  14. vince Says:

    hi, problem solved hehe, forgot to include the /1/ the api level in the uri hehe, great, thanks for the tutorial by the way

  15. Blackmind Says:

    Using “sandbox” (all lowercase) as root and string.Empty as path with did the trick

  16. nsadi Says:

    Hey!
    First, thanks! great articles 🙂
    I wanted to ask if there is any way to PREVIEW files that are currently in dropbox?
    for example, using GetFiles() to get the list, and then preview a specific file (same as clicking on a file inside dropbox)

  17. Vikram Says:

    Hi,

    First of all I would like to say deep thanks for great work especially for .NET developers and community.

    I am writing application to be able to upload files to DropBox in same manner as Dropbox software allows.

    Is there any way such that I can ask user for his username and password for Dropbox? And then my application gets authorized automatically without opening page in browser?


  18. […] been looking at this: http://cgeers.com/2012/01/08/dropbox-rest-api-part-2-api-requests/ which does exactly what I want it do, except its in like a command line window. I have no […]

  19. dev Says:

    Hi i do all things by setp by step but when i request for account info i get following error-
    “The remote server returned an error: NotFound.”
    my request url is –
    https://api.dropbox.com/1/account/info?oauth_consumer_key=st5lzbjx39alzyf&oauth_token=wS4aDrSohF8gpWxP&oauth_nonce=8476645&oauth_timestamp=1388733705&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&oauth_signature=Tidh9RE96Bu4WKW1N3m7gPgaGQM%3d

    and when i copy this url to browser i get following error-
    {“error”: “Access token not found.”}
    please help me.

  20. kosoft Says:

    I have received null response
    my code

    String.Format(“metadata/{0}/{1}”, “dropbox”, “Public”);

    var reader = new StreamReader(response.GetResponseStream());
    string str= reader.ReadToEnd();

    here str is null

  21. pkellner Says:

    I’m getting the same error on code that I believe use to work. that is “”Access token not found.” with similar info to you. I’m wondering if the api has changed somehow. If I play the token and secret back immediately after I get it works, but if I come back and run it again hardcoding my token and secret I get the error. Arg..


Comments are closed.

%d bloggers like this: