cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Announcements
Want to learn some quick and useful tips to make your day easier? Check out how Calvin uses Replay to get feedback from other teams at Dropbox 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: 

Re: Objective-C API 2 - dealing with error codes

Objective-C API 2 - dealing with error codes

Keith B.7
Helpful | Level 7
Go to solution

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

1 Accepted Solution

Accepted Solutions

Greg-DB
Dropbox Staff
Go to solution

I see, if you're looking for that case in particular, in API v2 lock contention is now a 429 with a structured too_many_write_operations error. In the SDK that should be a DBAUTHRateLimitError with a TooManyWriteOperations DBAUTHRateLimitReason.

View solution in original post

6 Replies 6

Greg-DB
Dropbox Staff
Go to solution

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
Helpful | Level 7
Go to solution

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
Dropbox Staff
Go to solution

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.

Keith B.7
Helpful | Level 7
Go to solution

Great, thank you! With regard to a 503, though, a DBRequestErrorInternalServer is just a generic "anything over 500" error, isn't it? So if I want to check specifically for a file lock error, is it safe still to check for the 503 error? (That is, will DBError report a status code of 503 in this case?)

 

All the best,
Keith

Greg-DB
Dropbox Staff
Go to solution

I see, if you're looking for that case in particular, in API v2 lock contention is now a 429 with a structured too_many_write_operations error. In the SDK that should be a DBAUTHRateLimitError with a TooManyWriteOperations DBAUTHRateLimitReason.

Keith B.7
Helpful | Level 7
Go to solution

Perfect, thank you!

Need more support?