1
votes

I have tried several StackOverflow questions, and I caanot find the correct answer on this. I am using the POSTMAN plugin for Chrome to check my REST calls and I cannot figure out why I cannot read the response. In the comments you will see all the different attempts I have made to get the response.

NSDictionary* session_params = @{SESSION_USERNAME_KEY:SESSION_USERNAME_VALUE, SESSION_PASSWORD_KEY:SESSION_PASSWORD_VALUE};
NSURL* url = [NSURL URLWithString:SESSION_URL];
RKObjectManager* objectManager = [RKObjectManager managerWithBaseURL:url];
//GET THE **** THING TO INTERPRET A TEXT response

//[RKMIMETypeSerialization registerClass:[RKXMLReaderSerialization class] forMIMEType:RKMIMETypeTextXML];
//[objectManager setAcceptHeaderWithMIMEType:@"text/html"];
//[objectManager setAcceptHeaderWithMIMEType:RKMIMETypeTextXML];
//[RKMIMETypeSerialization registerClass:[RKXMLReaderSerialization class] forMIMEType:@"text/html"];
//[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:@"text/html"];
//[objectManager setRequestSerializationMIMEType:@"text/html"];

//END
NSMutableURLRequest* request = [objectManager requestWithObject:nil method:RKRequestMethodPOST path:SESSION_URL parameters:session_params];


RKObjectRequestOperation* operation = [objectManager
                                       objectRequestOperationWithRequest:request success:^(RKObjectRequestOperation* operation, RKMappingResult* result)
                                       {
                                           NSLog(@"RESULT [%@]", result);
                                       }
                                       failure:^(RKObjectRequestOperation *operation, NSError *error) {
                                           NSLog(@"ERROR [%@]", error);
                                       }];

    [operation start];

I think the most irritating thing is that the stuff I need is contained in the NSLocalizedRecoverySuggestion value. It is a session key I require.

OUTPUT:

E restkit.network:RKObjectRequestOperation.m:547 Object request failed: Underlying HTTP request operation failed with error: Error Domain=org.restkit.RestKit.ErrorDomain Code=-1016 "Expected content type {( "application/x-www-form-urlencoded", "application/json" )}, got text/html" UserInfo=0x1c52aed0 {NSLocalizedRecoverySuggestion=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJCbG8uUmVnQWxlcnQuQnJva2VyIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdC9CbG8uUmVnQWxlcnQuQVBJL2FwaSIsIm5iZiI6MTM5MjY0MTY2MSwiZXhwIjoxMzkyNjQ1MjYxLCJ1bmlxdWVfbmFtZSI6IkJ1dHRvbnMiLCJyb2xlIjoiUmVnQWxlcnRDb25zdW1lciJ9.JCTMGJRKlOxEtNrcGodpce-tqsRS4zlApNisKQW6iSw, AFNetworkingOperationFailingURLRequestErrorKey=, NSErrorFailingURLKey=http://..., NSLocalizedDescription=Expected content type {( "application/x-www-form-urlencoded", "application/json" )}, got text/html, AFNetworkingOperationFailingURLResponseErrorKey=} 2014-02-17 14:54:20.808 AppName[5600:6403] E restkit.network:RKObjectRequestOperation.m:213 POST 'http://...' (200 OK / 0 objects) [request=0.0000s mapping=0.0000s total=0.1925s]: Error Domain=org.restkit.RestKit.ErrorDomain Code=-1016 "Expected content type {( "application/x-www-form-urlencoded", "application/json" )}, got text/html" UserInfo=0x1c52aed0 {NSLocalizedRecoverySuggestion=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJCbG8uUmVnQWxlcnQuQnJva2VyIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdC9CbG8uUmVnQWxlcnQuQVBJL2FwaSIsIm5iZiI6MTM5MjY0MTY2MSwiZXhwIjoxMzkyNjQ1MjYxLCJ1bmlxdWVfbmFtZSI6IkJ1dHRvbnMiLCJyb2xlIjoiUmVnQWxlcnRDb25zdW1lciJ9.JCTMGJRKlOxEtNrcGodpce-tqsRS4zlApNisKQW6iSw, AFNetworkingOperationFailingURLRequestErrorKey=, NSErrorFailingURLKey=http://..., NSLocalizedDescription=Expected content type {( "application/x-www-form-urlencoded", "application/json" )}, got text/html, AFNetworkingOperationFailingURLResponseErrorKey=}

CODE THAT WORKED Thanks to Wain for pointing me on the correct path there. I am a little disappointed that RestKit cannot handle such a simple request, and I need RestKit because this is just a session token to calling the other methods, but whatever works I guess:

NSDictionary* session_params = @{SESSION_USERNAME_KEY:SESSION_USERNAME_VALUE, SESSION_PASSWORD_KEY:SESSION_PASSWORD_VALUE};

NSURL* url = [NSURL URLWithString:SESSION_URL];

AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
NSMutableURLRequest *request = [httpClient requestWithMethod:@"POST" path:SESSION_URL parameters:session_params];

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];

[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSString* response = [operation responseString];
    NSLog(@"response: %@",response);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"error: %@", [operation error]);
}];
[operation start];
2

2 Answers

3
votes

This bit:

"Expected content type {( "application/x-www-form-urlencoded", "application/json" )}, got text/html"

tells you that you have told RestKit to expect form-urlencoded or json, but that the server is returning html.

You would probably want to use setAcceptHeaderWithMIMEType with JSON mime type to tell the server what you want back. But, in this case you probably just shouldn't be using RestKit.

RestKit is for mapping arbitrary JSON / XML data into your data model. You just have a key coming back. No mapping is required. So, don't use RestKit, use AFNetworking instead (which you have full access to because RestKit uses it internally.

1
votes

Thanks to Wain and Quintin, this was quite useful to me :)

I think some names changed in more recent versions of Restkit or AFNetworking. I used AFNetworking as explained in other answers since the server did not return json but empty plain/text instead. This was only on a particular endpoint where I was looking for a token in the headers of the response.

Sharing my piece of code here too:

-(void) find_some_token_with_success:(void (^)(AFRKHTTPRequestOperation *operation, id responseObject))success failure:(void (^)(AFRKHTTPRequestOperation *operation, NSError *error))failure {

    NSURL *baseURL = [NSURL URLWithString:@"https://example.com"];

    AFRKHTTPClient *client = [AFRKHTTPClient clientWithBaseURL:baseURL];
    [client setDefaultHeader:@"Accept" value:RKMIMETypeJSON];
    [client setDefaultHeader:@"some_custom_header" value:@"some_custom_value"];

    NSMutableURLRequest *request = [client requestWithMethod:@"GET" path:@"/api/v1/some_non_json_endpoint" parameters:nil];

    AFRKHTTPRequestOperation *operation = [[AFRKHTTPRequestOperation alloc] initWithRequest:request];

    [operation setCompletionBlockWithSuccess:success failure:failure];
    [operation start];
}

Then I used something like this to get the header I was looking for:

-(void) get_the_token:(void (^)(NSString *token))withTokenCallback failure:(void (^)(AFRKHTTPRequestOperation *operation, NSError *error))failure {
    [self xsrftoken_with_success:^(AFRKHTTPRequestOperation *operation, id responseObject) {
        NSString *token = [self get_the_token_from_response:[operation response]];
        withTokenCallback(token);
    } failure:failure];
}

-(NSString *) get_the_token_from_response: (NSHTTPURLResponse *) response;
{
    NSDictionary *headerDictionary = response.allHeaderFields;
    NSString *token = [headerDictionary objectForKey:@"SOME-TOKEN-KEY"];
    return token;
}

So all of this can simply be used like this:

- (void)testGetSometokenInARequest
{
    XCTestExpectation *expectation = [self expectationWithDescription:@"Query timed out."];

    [[SomeRequestWithoutJsonResponse alloc]
     get_the_token:^(NSString *token) {
         [expectation fulfill];
         NSLog(@"token: %@", token);
         // this token should be 100 characters long
         XCTAssertTrue([token length] == 100);
     }
     failure:^(AFRKHTTPRequestOperation *operation, NSError *error) {
         NSLog(@"error: %@", [operation error]);
     }];

    [self waitForExpectationsWithTimeout:10.0 handler:nil];
}

In other words, get_the_token takes a callback with the desired token and a failure callback.

Make sure you still include <RestKit/RestKit> so you have access to Restkit's AFNetowkring :)


Alternative working solution using restkit:

RestKit: How to handle empty response.body?

And you register a serializer for that kind of Mimetype like this:

[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:@"text/plain"];