0
votes

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!)

1
Oh and one more thing in case it matters: the web service is hosted on an Amazon AWS Server - alex da franca
And the web service log says? - Wain
no error in the web services log. If I turn on the logs on the server I can see the request to the path "user" and nothing else. It just seems, as it it sits there and waits for the payload to stream in (or to stop to stream in for that matter) - alex da franca
Instead of the line: RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:[self responseDescriptors]]; I used now RKObjectRequestOperation *operation = [objectManager objectRequestOperationWithRequest: success: failure: .. but still get the same server time out. How can I change the format of the POST payload. Apparently the server expects another format - alex da franca
That is requestSerializationMIMEType - Wain

1 Answers

0
votes

So to answer my own question, the backend server setup required me to set the requestSerializationMIMEType to @"text/plain".

[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:@"text/plain"];
sharedManager.requestSerializationMIMEType = @"text/plain";

I am not sure, whether the better solution would be to change the backend server setup, as it doesn't seem to be very common that it only works with @"text/plain". when there is not even a constant for @"text/plain". I'll open another separate question for that.