Permalink
Browse files

Standardize Error objects for Promises

Summary:
public

Promises are coming.  And as part of it, we are standardizing the error objects that will be returned.  This puts the code in place on the Android side to always send the proper error format.

It will be an error object like this
  {
    code : "E_SOME_ERROR_CODE_DEFINED_BY_MODULE", // Meant to be machine parseable
    message : "Human readable message",
    nativeError : {} // Some representation of the underlying error (Exception or NSError) , still figuring out exactly, but hopefully something with stack info
  }

Reviewed By: nicklockwood

Differential Revision: D2840128

fb-gh-sync-id: 174d620e2beb53e1fc14161a10fd0479218d98a6
  • Loading branch information...
Dave Miller facebook-github-bot-5
Dave Miller authored and facebook-github-bot-5 committed Jan 19, 2016
1 parent 554292d commit 0c5f279c9df869db2afb3e1d92a54e6d930551ad
@@ -62,7 +62,7 @@ - (dispatch_queue_t)methodQueue
RCT_REMAP_METHOD(shouldReject, shouldReject_resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
{
- reject(nil);
+ reject(nil, nil, nil);
}
RCT_EXPORT_METHOD(markTestCompleted)
@@ -37,7 +37,7 @@ typedef void (^RCTPromiseResolveBlock)(id result);
* The error may be nil but it is preferable to pass an NSError object for more
* precise error messages.
*/
-typedef void (^RCTPromiseRejectBlock)(NSError *error);
+typedef void (^RCTPromiseRejectBlock)(NSString *code, NSString *message, NSError *error);
/**
* This constant can be returned from +methodQueue to force module
@@ -335,8 +335,8 @@ - (void)processMethodSignature
return NO;
}
- RCT_BLOCK_ARGUMENT(^(NSError *error) {
- NSDictionary *errorJSON = RCTJSErrorFromNSError(error);
+ RCT_BLOCK_ARGUMENT(^(NSString *code, NSString *message, NSError *error) {
+ NSDictionary *errorJSON = RCTJSErrorFromCodeMessageAndNSError(code, message, error);
[bridge enqueueCallback:json args:@[errorJSON]];
});
)
View
@@ -52,6 +52,10 @@ RCT_EXTERN BOOL RCTClassOverridesInstanceMethod(Class cls, SEL selector);
RCT_EXTERN NSDictionary<NSString *, id> *RCTMakeError(NSString *message, id toStringify, NSDictionary<NSString *, id> *extraData);
RCT_EXTERN NSDictionary<NSString *, id> *RCTMakeAndLogError(NSString *message, id toStringify, NSDictionary<NSString *, id> *extraData);
RCT_EXTERN NSDictionary<NSString *, id> *RCTJSErrorFromNSError(NSError *error);
+RCT_EXTERN NSDictionary<NSString *, id> *RCTJSErrorFromCodeMessageAndNSError(NSString *code, NSString *message, NSError *error);
+
+// The default error code that will be sent in the .code value of the Error object to js
+RCT_EXTERN NSString *const RCTErrorUnspecified;
// Returns YES if React is running in a test environment
RCT_EXTERN BOOL RCTRunningInTestEnvironment(void);
View
@@ -21,6 +21,8 @@
#import "RCTLog.h"
+NSString *const RCTErrorUnspecified = @"EUNSPECIFIED";
+
NSString *RCTJSONStringify(id jsonObject, NSError **error)
{
static SEL JSONKitSelector = NULL;
@@ -313,27 +315,34 @@ BOOL RCTClassOverridesInstanceMethod(Class cls, SEL selector)
return error;
}
-// TODO: Can we just replace RCTMakeError with this function instead?
NSDictionary<NSString *, id> *RCTJSErrorFromNSError(NSError *error)
+{
+ return RCTJSErrorFromCodeMessageAndNSError(RCTErrorUnspecified, nil, error);
+}
+
+// TODO: Can we just replace RCTMakeError with this function instead?
+NSDictionary<NSString *, id> *RCTJSErrorFromCodeMessageAndNSError(NSString *code, NSString *message, NSError *error)
{
NSString *errorMessage;
NSArray<NSString *> *stackTrace = [NSThread callStackSymbols];
NSMutableDictionary<NSString *, id> *errorInfo =
- [NSMutableDictionary dictionaryWithObject:stackTrace forKey:@"nativeStackIOS"];
+ [NSMutableDictionary dictionaryWithObject:stackTrace forKey:@"nativeStackIOS"];
if (error) {
errorMessage = error.localizedDescription ?: @"Unknown error from a native module";
errorInfo[@"domain"] = error.domain ?: RCTErrorDomain;
- errorInfo[@"code"] = @(error.code);
} else {
errorMessage = @"Unknown error from a native module";
errorInfo[@"domain"] = RCTErrorDomain;
- errorInfo[@"code"] = @-1;
}
+ errorInfo[@"code"] = code ?: RCTErrorUnspecified;
+ // Allow for explicit overriding of the error message
+ errorMessage = message ?: errorMessage;
return RCTMakeError(errorMessage, nil, errorInfo);
}
+
BOOL RCTRunningInTestEnvironment(void)
{
static BOOL isTestEnvironment = NO;

2 comments on commit 0c5f279

@philikon

This comment has been minimized.

Show comment
Hide comment
@philikon

philikon Jan 31, 2016

Contributor

I'm surprised that RCTPromiseRejectBlock needs different info and therefore gets a different signature than RCTResponseErrorBlock. Either way, https://facebook.github.io/react-native/docs/native-modules-ios.html#promises probably wants to be updated :)

Contributor

philikon replied Jan 31, 2016

I'm surprised that RCTPromiseRejectBlock needs different info and therefore gets a different signature than RCTResponseErrorBlock. Either way, https://facebook.github.io/react-native/docs/native-modules-ios.html#promises probably wants to be updated :)

@satya164

This comment has been minimized.

Show comment
Hide comment
@satya164

satya164 Jan 31, 2016

Collaborator

Would be great if you could send a PR @philikon :)

Collaborator

satya164 replied Jan 31, 2016

Would be great if you could send a PR @philikon :)

Please sign in to comment.