I am trying to send a POST request to a web service using Restkit 0.22.0. I have setup the request descriptor and the response descriptor and the request is being sent, but the server never gets the payload (or doesn't "know" where the payload ends) and therefore doesn't come back to my app. The result is a server timeout after 60 seconds.
There is something I am missing when setting up request descriptor or the request. It seems, that the server either doesn't get any payload at all or doesn't know when the payload ends, either due to a missing content-length property in the http headers or due to a missing "end of stream" sign.
If I try the same with postman it works.
What I see in the Xcode log is:
2014-03-15 20:43:14.819 testIOS[52095:60b] T restkit.network:RKObjectRequestOperation.m:148 POST 'http://api.test.com:3000/0.1/user/':
request.headers={
Accept = "application/json";
"Accept-Language" = "en;q=1, fr;q=0.9, de;q=0.8, zh-Hans;q=0.7, zh-Hant;q=0.6, ja;q=0.5";
"Content-Type" = "application/json; charset=utf-8";
"User-Agent" = "testIOS/1 (iPhone Simulator; iOS 7.1; Scale/2.00)";
"X-NewRelic-ID" = "UAEBVFNWGwAEV1ZQBgM=";
}
request.body={"name":"alex"}
It looks like it is correct so far, although I do not know, whether this request.body is formatted properly like so. Then it takes 60 seconds until I get the next output in the log window with the following error:
2014-03-15 20:44:14.948 testIOS[52095:3707] E restkit.network:RKObjectRequestOperation.m:547 Object request failed: Underlying HTTP request operation failed with error: Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo=0xd342700 {NSErrorFailingURLStringKey=http://api.test.com:3000/0.1/user/, NSErrorFailingURLKey=http://api.test.com:3000/0.1/user/, NSLocalizedDescription=The request timed out., NSUnderlyingError=0xd656c20 "The request timed out."}
2014-03-15 20:44:14.949 testIOS[52095:3707] E restkit.network:RKObjectRequestOperation.m:208 POST 'http://api.test.com:3000/0.1/user/' (0 / 0 objects) [request=60.1298s mapping=0.0000s total=60.1320s]:
error=Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo=0xd342700 {NSErrorFailingURLStringKey=http://api.test.com:3000/0.1/user/, NSErrorFailingURLKey=http://api.test.com:3000/0.1/user/, NSLocalizedDescription=The request timed out., NSUnderlyingError=0xd656c20 "The request timed out."}
response.body=(null)
2014-03-15 20:44:14.950 testIOS[52095:60b] error is: Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo=0xd342700 {NSErrorFailingURLStringKey=http://api.test.com:3000/0.1/user/, NSErrorFailingURLKey=http://api.test.com:3000/0.1/user/, NSLocalizedDescription=The request timed out., NSUnderlyingError=0xd656c20 "The request timed out."}
Here's are is the code (which I think must be wrong somewhere or missing the important bits):
+ (void)setupRK
{
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:baseURL];
objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
[objectManager.HTTPClient setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
if (status == AFNetworkReachabilityStatusNotReachable) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"No network connection"
message:@"You must be connected to the internet to use this app."
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
}
}];
[RKObjectManager setSharedManager:objectManager];
// Log all HTTP traffic with request and response bodies
RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);
}
+ (RKObjectRequestOperation *)loginRKOperationForUser:(STF_RKObj_User *)user
{
RKObjectManager *objectManager = [RKObjectManager sharedManager];
RKObjectMapping *userMapping = [STF_RKObj_User objectMapping];
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:userMapping method:RKRequestMethodAny pathPattern:nil keyPath:nil statusCodes:statusCodes];
[objectManager addResponseDescriptor:responseDescriptor];
RKObjectMapping *objMapping = [STF_RKObj_User objectMapping];
RKRequestDescriptor *reqDescr = [RKRequestDescriptor requestDescriptorWithMapping:[objMapping inverseMapping] objectClass:[STF_RKObj_User class] rootKeyPath:nil method:RKRequestMethodPOST];
[objectManager addRequestDescriptor:reqDescr];
NSMutableURLRequest *request = [objectManager requestWithObject:user method:RKRequestMethodPOST path:@"user/" parameters:nil];
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]];
return operation;
}
and then call it from another class like this:
- (void)loginWithUserObject:(STF_RKObj_User *)userObj
{
RKObjectRequestOperation *operation = [STF_REST_Operations loginRKOperationForUser:userObj];
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(@"mappingResult: %@", mappingResult);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
[self logoutUser];
self.loginCallback(NO, error);
[self setLoginCallback:nil];
}];
[operation start];
}
I can't for the live of me figure out what I am missing. Been googling all day...help...
TIA
UPDATE:
Phew, I got it to work now without the help of the backend programmer by just setting the requestSerializationMIMEType to @"text/plain".
[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:@"text/plain"];
sharedManager.requestSerializationMIMEType = @"text/plain";
This clearly can't be a proper server setup, as there is no constant for a mime type of "text/plain" in the Restkit framework. This leaves me with the question whether "bad things will happen to me", if I just set the requestSerializationMIMEType to this "arbitrary value" of "text/plain". For now it works, but will I run into new problems later?
(Many thanks to Wain for pointing me into the right direction and suggesting to use Charles!)
requestSerializationMIMEType- Wain