Error with RestKit POST Request - ios

I am trying to send JSON data in POST request to server using RestKit but I am getting error
Expected content type {(
"application/x-www-form-urlencoded",
"application/json"
)}, got text/plain
The code I have written is:
NSURL *url=[NSURL URLWithString:[NSString stringWithFormat:#"%#%#",BASE_SERVICE_URL,TASK_SERVICE_URL]];
RKObjectMapping *mapping=[RKObjectMapping mappingForClass:[LoginData class]];
[mapping addAttributeMappingsFromDictionary:#{#"s":#"status",
#"message":#"message"}];
RKResponseDescriptor *descriptor=[RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodPOST pathPattern:nil keyPath:#"" statusCodes:0];
NSMutableURLRequest *request=[[NSMutableURLRequest alloc]initWithURL:url];
[request setHTTPMethod:#"POST"];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
NSDictionary *dict=#{#"task":#"storeProfile",
#"fdate":#"01.01.2013",
#"tdate":#"19.08.2013",
#"keyword":#"taxi && cab",
#"AlertHours":#"120",
#"AlertDay":#"0",
#"AlertTimeStart":#"12:00",
#"AlertTimeEnd":#"18:00",
#"topic":#[
#{#"tname":#"Politics"},
#{#"tname":#"Economy"}
],
#"publication":#[
#{#"pname":#"Vijay Times Online"},
#{#"pname":#"Leisure Opportunities"}
]
};
NSError *error=nil;
NSData *jsonData=[NSJSONSerialization dataWithJSONObject:dict options:kNilOptions error:&error];
if (error) {
NSLog(#"%#",error.localizedDescription);
return;
}
[request setHTTPBody:jsonData];
operation=[[RKObjectRequestOperation alloc]initWithRequest:request responseDescriptors:#[descriptor]];
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
LoginData *data=[mappingResult.dictionary objectForKey:#""];
NSLog(#"%#",data.message);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"ERROR:%#",error.localizedDescription);
}];
[operation start];
Could somebody please help me to figure out what exactly the problem is??
I have tried setting content type as follow also:
[request addValue:#"application/application/x-www-form-urlencoded; charset=UTF-8" forHTTPHeaderField:#"Content-Type"];

Try this
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:BASE_URL]];
[objectManager setRequestSerializationMIMEType:RKMIMETypeJSON];

You have to register the class RKNSJSONSerialization . Please include the below code in your method.
[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:#"text/plain"];

Related

AFNetworking2 send parameter as query string in POST request?

I need to send query string in URL as well as JSON in body while making POST request.To send query string in url i override HTTPMethodsEncodingParametersInURI property as suggested in this thread on SO like
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:[NSURL URLWithString:fullUrl]];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
manager.requestSerializer.HTTPMethodsEncodingParametersInURI = [NSSet setWithArray:#[#"POST", #"GET", #"HEAD", #"PUT", #"DELETE"]];
[manager POST:fullUrl parameters:param success:^(AFHTTPRequestOperation *operation, id responseObject) {
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
but it seems doing this add my JSON data into URL as well, hence my request is not executed on server.But i need to send only 'command' parameter into url and some JSON data into request body.
my fullUrl string is looks like http://some_ip_address/config?command=some_command and param is NSDictionary object.
Note that there is a parameter in fullUrl i.e. command and i also send a NSDictionary object as param in
[manager POST:fullUrl parameters:param success:^(AFHTTPRequestOperation *operation, id responseObject) {
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
Edit2: I also tried with NSURLSession
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://my_server_ip/config?command=plugs"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSError *error;
NSData *postData = [NSJSONSerialization dataWithJSONObject:param options:0 error:&error];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request addValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:postData];
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}];
[postDataTask resume];
but get status code: 400 in NSURLResponse.
Edit3: someone suggested to subclass AFHTTPRequestSerializer class in this SO thread so i tried with
#implementation CustomAFHTTPRequestSerializer
-(id)init
{
self = [super init];
return self;
}
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(NSDictionary *)parameters
error:(NSError *__autoreleasing *)error
{
NSString* encodedUrl = [URLString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:encodedUrl] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSError *error1;
NSData *postData = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:&error1];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request addValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:[NSString stringWithFormat:#"%d", [postData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:postData];
return request;
}
#end
And assign it as requestSerializer of operationManager
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [[CustomAFHTTPRequestSerializer alloc] init];
But still get Error Domain=AFNetworkingErrorDomain Code=-1011 "Request failed: bad request (400)
Please help me guys, Any help would be highly appreciated.

Adding custom header in httprequest restkit 0.20 ios

I am trying to add a custom header to all the http request from the app but on server side I am not getting it.
I tried following methods:
1.setting header in NSMutableURLRequest:
[request addValue:headerString forHTTPHeaderField:#"deviceDetails"];
NSLog( #"%#",[request valueForHTTPHeaderField:#"deviceDetails"]);
Here I get null just after setting the header value. Not sure what is happening.
2.setting default header in RKObjectManager
[manager.HTTPClient setDefaultHeader:#"deviceDetails" value:headerString];
Here header seems to be set but on server there is no header field with key "deviceDetails"
Any help would be appreciated.
Code:
NSMutableURLRequest *request =[self _createPostRequestWithParams:[NSJSONSerialization dataWithJSONObject:params options:NSJSONWritingPrettyPrinted error:nil] andPath:path];
[request setTimeoutInterval:20];
NSLog(#"%#",[request valueForHTTPHeaderField:#"deviceDetails"]);
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:BASE_URL]];
[manager setRequestSerializationMIMEType:#"application/json"];
[manager.HTTPClient setAuthorizationHeaderWithUsername:self.offlineService.user.username password:self.offlineService.user.password];
[manager addResponseDescriptor: [self _getResponseDescriptorWithKeyPath:keyPath andResponseClass:responseClass]];
[manager.HTTPClient setDefaultHeader:#"deviceDetails" value:#"String value" encoding:NSUTF8StringEncoding]];
RKObjectRequestOperation *operation = [self _createOperationForRequest:request successcallback:requestSuccessful failurecallback:requestFailure target:target manager:manager];
[operation start];
_createOperationForRequest:
- (RKObjectRequestOperation *)_createOperationForRequest:(NSMutableURLRequest *)request successcallback:(SEL)requestSuccessful failurecallback:(SEL)requestFailed target:(id)target manager:(RKObjectManager *)manager {
RKObjectRequestOperation *operation = [manager objectRequestOperationWithRequest:request
success:^(RKObjectRequestOperation *operation,RKMappingResult *result) {
}
failure:^(RKObjectRequestOperation *operation,NSError *error){
}];
return operation;
}
In above code both basic authentication and device details header are received on the server side.

Post JSON Body + MultiPart RestKit 0.2x fails

I am trying to post an object with an attached file.
NSMutableURLRequest *request =
[objectManager multipartFormRequestWithObject:reqDocObj
method:RKRequestMethodPOST
path:#"syncDocument.json"
parameters:nil
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:UIImagePNGRepresentation([UIImage imageNamed:#"graybox.png"])
name:#"image"
fileName:#"some_file"
mimeType:#"image/jpeg"];
}];
RKObjectRequestOperation *operation =
[objectManager
objectRequestOperationWithRequest:request
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
}
failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"WS: errore operazione di richiesta %#",error);
}
];
[objectManager enqueueObjectRequestOperation:operation];
The objectManager is configured as:
[objectManager setAcceptHeaderWithMIMEType:RKMIMETypeJSON];
[objectManager setRequestSerializationMIMEType:RKMIMETypeJSON];
objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
[EDIT]
My mapepd object is SynchDocObj:
requestDocMapping = [RKObjectMapping mappingForClass:[SynchDocObj class]];
[requestDocMapping addAttributeMappingsFromDictionary:mappingDocDict];
The problem is:
1) In the RKlogs, the request.body = null and the JSON object is put into the form-data
2) The server cannot decode the body because it is null
My question is:
1) Am I sending the JSON object in the wrong way?
2) If yes, how can I send a JSON object with a file upload, i.e. as a multipart request?
Regards!
[SOLUTION]
Following the suggestion of the answer, I think the solution is 1) retrieve the mapped object from the form-data and not the body ; 2) OR post a nil object and putting a JSON string within the form-data.
This:
[objectManager setRequestSerializationMIMEType:RKMIMETypeJSON];
objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
is 2 different ways of saying the same thing - and you don't want to have either of them. You need to send the request as form URL encoded (the default value).
The easiest thing to do is to use the same form as in your current code to create the request, generate the JSON earlier and then use appendPartWithFormData:name: to add it to the request (just before you add the file).
To generate the JSON you can use RestKit (RKMappingOperation) or you can just create a dictionary / array of content and then use NSJSONSerialization to serialise that object to be added to the request.
Analyze my code, it works like a charm:
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[FilledExamCard defineMapping] objectClass:[MappedClassName class] rootKeyPath:nil method:RKRequestMethodPUT];
NSData *jsonPayload = [self getJSONpayloadFromObject:mappedClassObject requestDescriptor:requestDescriptor];
NSURL *baseURL = [NSURL URLWithString:[ZDR_BASE_URL stringByAppendingString:#"PutExamCards"]];
AFHTTPClient *client = [AFHTTPClient clientWithBaseURL:baseURL];
[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:#"text/plain"];
[client setDefaultHeader:#"Accept" value:#"text/plain"];
RKObjectManager *objectManager = [[RKObjectManager alloc] initWithHTTPClient:client];
[objectManager setRequestSerializationMIMEType: RKMIMETypeJSON];
[objectManager addRequestDescriptor:requestDescriptor];
NSMutableURLRequest *request = [objectManager multipartFormRequestWithObject:nil method:RKRequestMethodPUT path:#"" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
// Name may vary depending from server settings
[formData appendPartWithFormData:jsonPayload name:#"model"];
}];
RKObjectRequestOperation *operation = [objectManager objectRequestOperationWithRequest:request success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
// Process data
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
// An error occurred
}];
-(NSData*)getJSONpayloadFromObject:(NSObject*)object requestDescriptor:(RKRequestDescriptor*)requestDescriptor
{
NSDictionary *paramObject = [RKObjectParameterization parametersWithObject:object requestDescriptor:requestDescriptor error:nil];
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:paramObject options:NSJSONWritingPrettyPrinted error:&error];
return jsonData;
}

How to set HTTP request body using AFNetwork's AFHTTPRequestOperationManager?

I am using AFHTTPRequestOperationManager (2.0 AFNetworking library) for a REST POST request. But the manager only have the call to set the parameters.
-((AFHTTPRequestOperation *)POST:(NSString *)URLString
parameters:(NSDictionary *)parameters
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure;
I need to set HTTP request body with a string as well. How can I do it using the AFHTTPRequestOperationManager? Thanks.
I had the same problem and solved it by adding code as shown below:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL
cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10];
[request setHTTPMethod:#"POST"];
[request setValue:#"Basic: someValue" forHTTPHeaderField:#"Authorization"];
[request setValue: #"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody: [body dataUsingEncoding:NSUTF8StringEncoding]];
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
op.responseSerializer = [AFJSONResponseSerializer serializer];
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON responseObject: %# ",responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", [error localizedDescription]);
}];
[op start];
for AFHTTPRequestOperationManager
[requestOperationManager.requestSerializer setValue:#"your Content Type" forHTTPHeaderField:#"Content-Type"];
[requestOperationManager.requestSerializer setValue:#"no-cache" forHTTPHeaderField:#"Cache-Control"];
// Fill parameters
NSDictionary *parameters = #{#"name" : #"John",
#"lastName" : #"McClane"};
// Customizing serialization. Be careful, not work without parametersDictionary
[requestOperationManager.requestSerializer setQueryStringSerializationWithBlock:^NSString *(NSURLRequest *request, NSDictionary *parameters, NSError *__autoreleasing *error) {
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parameters options:NSJSONWritingPrettyPrinted error:nil];
NSString *argString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
return argString;
}];
[requestOperationManager POST:urlString parameters:parameters timeoutInterval:kRequestTimeoutInterval success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (success)
success(responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (failure)
failure(error);
}];
Check what that convenience method (POST:parameters:success:failure) is doing under the hood and do it yourself to get access to actual NSMutableRequest object.
I'm using AFHTTPSessionManager instead of AFHTTPRequestOperation but I imagine the mechanism is similar.
This is my solution:
Setup Session Manager (headers etc)
Manually create NSMutable request and add my HTTPBody, basically copying-pasting code inside that convenience method. Looks like this:
NSMutableURLRequest *request = [manager.requestSerializer requestWithMethod:#"POST" URLString:[[NSURL URLWithString:<url string>] absoluteString] parameters:parameters];
[request setHTTPBody:[self.POSTHttpBody dataUsingEncoding:NSUTF8StringEncoding]];
__block NSURLSessionDataTask *task = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
if (error) {
// error handling
} else {
// success
}
}];
[task resume];
If you dig a little in sources of AFNetworking you will find that in case of POST method parameters are set into body of your HTTP request.
Each key,value dictionary pair is added to the body in form key1=value1&key2=value2. Pairs are separated by & sign.
Search for application/x-www-form-urlencoded in AFURLRequestSerialization.m.
In case of a string which is only a string, not key value pair then you might try to use AFQueryStringSerializationBlock http://cocoadocs.org/docsets/AFNetworking/2.0.3/Classes/AFHTTPRequestSerializer.html#//api/name/setQueryStringSerializationWithBlock: but this is only my guess.
You could create your own custom subclass of AFHTTPRequestSerializer, and set this as the requestSerializer for your AFHTTPRequestOperationManager.
In this custom requestSerializer, you could override
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
withParameters:(id)parameters
error:(NSError *__autoreleasing *)error;
Inside your implementation of this method, you'll have access to the NSURLRequest, so you could do something like this
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
withParameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
NSURLRequest *serializedRequest = [super requestBySerializingRequest:request withParameters:parameters
error:error];
NSMutableURLRequest *mutableRequest = [serializedRequest mutableCopy];
// Set the appropriate content type
[mutableRequest setValue:#"text/xml" forHTTPHeaderField:#"Content-Type"];
// 'someString' could eg be passed through and parsed out of the 'parameters' value
NSData *httpBodyData = [someString dataUsingEncoding:NSUTF8StringEncoding];
[mutableRequest setHTTPBody:httpBodyData];
return mutableRequest;
}
You could take a look inside the implementation of AFJSONRequestSerializer for an example of setting custom HTTP body content.
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
[manager POST:url parameters:jsonObject success:^(AFHTTPRequestOperation *operation, id responseObject) {
//success
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
//fail
}];
This is the best and most concise way that I have found.
May be we can use the NSMutableURLRequest, here is the code :
NSURL *url = [NSURL URLWithString:yourURLString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
[request setHTTPMethod:#"POST"];
NSData *JSONData = [NSJSONSerialization dataWithJSONObject:parameters options:NSJSONWritingPrettyPrinted error:nil];
NSString *contentJSONString = [[NSString alloc] initWithData:JSONData encoding:NSUTF8StringEncoding];
[request setHTTPBody:[contentJSONString dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];

Translating from ASIHTTPRequest to AFNetworking , on iOS

What i want to do is post a json file to my server. I finally did that using ASIHTTPRequest and my code is :
NSURL *url = [NSURL URLWithString:#"http://foo.foo.foo"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setRequestMethod:#"PUT"];
[request addRequestHeader:#"Authorization" value:#"Basic dslfkdsfdsflsdkfslkgflksflksdlfkg"];
[request addRequestHeader:#"Content-Type" value:#"application/json; charset=utf-8"];
[request appendPostData:[jsonString dataUsingEncoding:NSUTF8StringEncoding]];
[request startSynchronous];
NSLog(#"%#", [request responseString]);
What i need now is the exact above code translated to AFNetworking. Any ideas??
Thank you for reading my post :)
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:#"http://foo.foo.foo"]];
client.parameterEncoding = AFJSONParameterEncoding;
[client registerHTTPOperationClass:[AFJSONRequestionOperation class]];
[client setAuthorizationHeaderWithUsername:... password:...];
[client putPath:#"/path/to/resource" parameters:(_your JSON object as a dictionary_)
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"%#", [request responseString]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];

Resources