You might see that the Dropbox Community team have been busy working on some major updates to the Community itself! So, here is some info on what’s changed, what’s staying the same and what you can expect from the Dropbox Community overall.

Forum Discussion

Keith B.7's avatar
Keith B.7
Helpful | Level 7
9 years ago

Objective-C API 2 - dealing with error codes

Hello,

 

In transitioning my API 1 Obj-C code over to API 2, I'm slightly confused over how to deal with certain error codes in API 2 - or even how to locate them properly.

 

# 1. Create Folder Errors

 

When creating a folder in API 1, if something went wrong, the delegate's -restClient:createFolderFailedWithError: method would be called. I could then check the (NS)error code. For example, I could check (error.code == 403) to see if the method failed because the folder already existed. In that case, I wouldn't have to cancel all following operations, since such an error may not be fatal.

 

How do I do this in API 2? API 1's endpoint reference lists specific codes for each API call (such as the 403 for "folder already exists" for the create_folder API call). API 2 has no such specific codes, but only some generic codes--always using 409 for anything endpoint-specific, telling you instead to check the JSON response body.

 

So, in the Obj-C frameworks, how do I detect from the JSON response body that -createFolder: failed specifically because a folder already exists at that path? From hunting through the header files, the closest I can find is to do something like this:

 

DBFILESCreateFolderError *folderError; // From the result callback.

BOOL folderExists = (folderError.isPath && folderError.path.isConflict);

 

(Obviously this does not specifically check that there is a folder already at the path, just that there is a conflict.)

 

Is there a better way?

 

# 2. Delete Files Errors

 

Likewise, with "delete file", API 1 returned a 404 error if the file did not exist on the server - another error that I could ignore since I was trying to delete a nonexistent file. How do I check for this case using the API 2 Obj-C frameworks?

 

# 3. Rate Limit Errors

 

I can see that there is a specific object for rate limit errors (DBAuthRateLimitError) which allows you to get the rety-after value. Great! I had to swizzle in my own replacement method to get this information in API 1. So now all I have to do to get the retry-after value is this, I believe:

 

DBError *error; // Received in result block.

if (error.statusCode == 429)

{

   NSInteger retryAfter = error.structuredRateLimitError.retryAfter.integerValue;

   // Try again after retryAfter...

}

 

That's great! I'm glad this is included. However:

 

- What is the difference between error.backoff and error.structuredRateLimitError.retryAfter.integerValue?

 

From searching the .m files, I *think* these are the same. So presumably I only need to check error.backoff to determine how long to wait before trying again after a 429 error, and do not need to worry about the structuredRateLimitError.retryAfter value?

 

# 4. Reading Error Codes

 

What is the best way of checking an error code in general? Is it to call -statusCode on the DBError object or -code on the DBError's nsError property object? It seems that -nsError can sometimes be nil, so I cannot rely on generalError.nsError.code. Is the -statusCode of DBError always the one to check? And is it always identical to the nsError code when nsError is not nil? I use the NSError domain and code to check for a number of generic HTTP errors as defined in the Apple NSError docs, for instance.

 

# 5. Checking for Over Quota Error

 

API 1 lists 507 as the specific error to check to see if a user is over his or her Dropbox quota. No such error code is listed for API 2. Can I still check for this error code (using generalError.statusCode?), or is it no longer used? If not, how can I check for this failure case so that I can communicate to the user that he or she needs to upgrade or tidy up their Dropbox account in order to continue syncing?

 

Apologies for another long post...

 

Thanks!

Keith

  • Greg-DB's avatar
    Greg-DB
    Icon for Dropbox Staff rankDropbox Staff

    Hi Keith,

     

    1. What you have already is the right way to start this, but you can continue drilling down into the error object, e.g.:

     

     

            [[client.filesRoutes createFolder:@"/test/path"] response:^(DBFILESFolderMetadata *result, DBFILESCreateFolderError *routeError, DBError *error) {
                if (result) {
                    NSLog(@"%@\n", result);
                } else if (routeError) {
                    NSLog(@"%@\n", routeError);
                    if ([routeError isPath]) {
                        if ([routeError.path isConflict]) {
                            if ([routeError.path.conflict isFolder]) {
                                NSLog(@"Could not create folder because a folder already exists at path.");
                            }
                        }
                    } // and so on for other errors
                } else if (error) {
                    NSLog(@"%@\n", error);
                }
            }];

     

     

    You can make your error handling as general or specific as you like this way.

     

     

    2. Similarly, you can check the specific error returned to see if a delete call failed because nothing was found at the path, e.g.:

     

     

            [[client.filesRoutes delete_:@"/test/path"] response:^(DBFILESMetadata *result, DBFILESDeleteError *routeError, DBError *error) {
                if (result) {
                    NSLog(@"%@\n", result);
                } else if (routeError) {
                    NSLog(@"%@\n", routeError);
                    if ([routeError isPathLookup]) {
                        if ([routeError.pathLookup isNotFound]) {
                            NSLog(@"Nothing found at path.");
                        } // and so on for other errors
                    }
                } else if (error) {
                    NSLog(@"%@\n", error);
                }
            }];

     

     

    3. Yes, you can just use one or the other.

     

     

    4. When using the SDK, you don't really need to worry about the actual HTTP error codes, as the SDK translates everything into objects and errors for you, like in the sample snippets above. For higher level errors, there's a good example here.

     

    5. Attempting to upload to an over quota account will result in an route-specific insufficient space error. E.g., in the SDK that would look like:

     

            [[client.filesRoutes uploadData:@"/test/path" inputData:fileData]
              response:^(DBFILESFileMetadata *result, DBFILESUploadError *routeError, DBError *error) {
                  if (result) {
                      NSLog(@"%@\n", result);
                  } else if (routeError) {
                      NSLog(@"%@\n", routeError);
                      if ([routeError isPath]) {
                          if ([routeError.path.reason isInsufficientSpace]) {
                              NSLog(@"Could not upload because the account is over quota.");
                          } // and so on for other errors
                      }
                  } else if (error) {
                      NSLog(@"%@\n", error);
                  }
              }];

     

     

    Hope this helps! 

    • Keith B.7's avatar
      Keith B.7
      Helpful | Level 7

      That helps lots, thank you! I think I'm nearly there... One question on (4):

       

      What about for errors that aren't covered in the framework. For instance, if you recall, I found that I was encountering random 503 "failed to grab file lock" errors, in which case I would use the "retry-after" header. In API 2, the status code for this is 429. In this instance, I assume I still use the DBError's status code to check for this? Or is the "failed to grab file locks" error always the same as a rate limit error? Are you saying I should never need to call the statusCode property?

       

      Thanks again,

      Keith

      • Greg-DB's avatar
        Greg-DB
        Icon for Dropbox Staff rankDropbox Staff

        I don't believe there's any case where you necessarily need to check the status code directly. The translation is here if you're interested, but a 503 will yield a DBRequestErrorInternalServer and a 429 will yield a DBRequestErrorRateLimit, so you don't need to access the statusCode directly for either of those. Further, anything not specifically covered there will be a DBRequestErrorHttp.

About Dropbox API Support & Feedback

Node avatar for Dropbox API Support & Feedback

Find help with the Dropbox API from other developers.

5,915 PostsLatest Activity: 14 hours ago
333 Following

If you need more help you can view your support options (expected response time for an email or ticket is 24 hours), or contact us on X or Facebook.

For more info on available support options for your Dropbox plan, see this article.

If you found the answer to your question in this Community thread, please 'like' the post to say thanks and to let us know it was useful!