I am very new to iOS. I am trying to send data through post method to PHP. In PHP it can't take data like $_POST['data'], but it takes $_GET['data']. My iOS code is as follows.
NSString *strURL = [NSString stringWithFormat:#"http://example.com/app_respond_to_job?emp_id=%#&job_code=%#&status=Worker-Accepted&comment=%#",SaveID2,txtJobcode1,alertTextField.text];
NSURL *apiURL = [NSURL URLWithString:strURL];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:apiURL];
[urlRequest setHTTPMethod:#"POST"];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
_receivedData = [[NSMutableData alloc] init];
[connection start];
NSLog(#"URL---%#",strURL);
Can someone explain why is that, it will be very helpful.
Please Download this file https://www.dropbox.com/s/tggf5rru7l3n53m/AFNetworking.zip?dl=0
And import file in your project
Define in #import "AFHTTPRequestOperationManager.h"
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:[NSURL URLWithString:#"Your Url"]];
NSDictionary *parameters = #{#"emp_id":SaveID2,#"job_code":txtJobcode1.text,#"status":alertTextField.text};
AFHTTPRequestOperation *op = [manager POST:#"rest.of.url" parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success: %# ***** %#", operation.responseString, responseObject);
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[responseObject valueForKey: #"data"];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %# ***** %#", operation.responseString, error);
}];
[op start];
because you send your data via query string in url
i think it will work if you try to pass data in your request's body:[urlRequest setHTTPBody:...]
POST parameters come from the request body, not from the URL string. You'll need to:
Call setHTTPBody on the request and provide the URL-encoded string (sans question mark, IIRC) as the body data
Call setValue:forHTTPHeaderField: to set the Content-Type to application/x-www-form-urlencoded
Either remove the call to [connection start] or use initWithRequest:delegate:startImmediately: so that you aren't starting the connection twice.
That last one is kind of important. You can get strange results if you try to start a connection twice. :-)
Related
I want to access Twilio api using AFNetworking. I tried number of ways but not get success. Please help me, if anyone did Tiwilo post request using AFNetworking.
Case 1: This is my native objective-c working code.
NSString *urlString = [NSString stringWithFormat:#"https://%#:%##api.twilio.com/2010-04-01/Accounts/%#/SMS/Messages", kTwilioSID, kTwilioSecret, kTwilioSID];
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
[request setHTTPMethod:#"POST"];
NSString *bodyString = [NSString stringWithFormat:#"From=%#&To=%#&Body=%#", from, to, message];
NSData *data = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPBody:data];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (connectionError)
{
DLog(#"Error: %#", connectionError);
completionBlock(connectionError, NO);
}
else
{
completionBlock(connectionError, YES);
}
}];
Case 2: Using AFNetorking: Code that is not working:
Code:
NSString *urlString = [NSString stringWithFormat:#"https://%#:%##api.twilio.com/2010-04-01/Accounts/%#/SMS/Messages", kTwilioSID, kTwilioSecret, kTwilioSID];
NSDictionary *dict = #{
#"From" : from,
#"To" : to,
#"Body" : message
};
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager POST:urlString parameters:dict success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"Success: %#", responseObject);
}
failure:
^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
Related Error:
Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (JSON text did not start with array or object and option to allow fragments not set.) UserInfo=0x1775e660 {NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set., NSUnderlyingError=0x175101b0 "Request failed: bad request (400)"}
Case 3: Using AFNetorking: Another Code that is also not working:
Code:
NSString *urlString = [NSString stringWithFormat:#"https://%#:%##api.twilio.com/2010-04-01/Accounts/%#/SMS/Messages", kTwilioSID, kTwilioSecret, kTwilioSID];
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
[request setHTTPMethod:#"POST"];
NSString *bodyString = [NSString stringWithFormat:#"From=%#&To=%#&Body=%#", from, to, message];
NSData *data = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPBody:data];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"%#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error: %#", error);
}];
[operation start];
Related Error:
Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (JSON text did not start with array or object and option to allow fragments not set.) UserInfo=0x177a3e70 {NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
Thank you.
Ricky from Twilio here. First off a quick disclaimer. Making a request to Twilio directly from an iOS app requires you to embed your Twilio account credentials in the app, which is dangerous. My recommendation would be to send the SMS from a server side script that your app makes a request to in order to keep your credentials safe.
That being said, your code is really close. By default, Twilio's REST API returns XML. If you want to parse the response as it's returned by default you can update the code in version 2 to use the AFXMLParserResponseSerializer:
operation.responseSerializer = [AFXMLParserResponseSerializer serializer];
If you'd rather work with JSON then you update the Twilio URL you're making the POST request to and indicate you'd like a JSON response:
NSString *urlString = [NSString stringWithFormat:#"https://%#:%##api.twilio.com/2010-04-01/Accounts/%#/SMS/Messages.json", kTwilioSID, kTwilioSecret, kTwilioSID];
Hope that helps.
It seems that AFNetworking isn't working correctly for me. Specifically when I send apiKey request to server it gives me an unauthorized error. ASIHTTPRequest works fine for me however, so there seems to be something I am doing wrong in AFNetWorking. I know the problem is sending apiKey because if I comment it out AFNetWork works correctly. I still need to send the API key however. Any help will be appreciated.
AFNetWorking
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager.requestSerializer setValue:apiKey forHTTPHeaderField:#"apiKey"];
NSMutableDictionary *userinfo = [[NSMutableDictionary alloc] init];
[manager POST:urlStr parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
[operation setUserInfo:userinfo];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[operation setUserInfo:userinfo];
}];
}
ASIHTTPRequest
NSString *urlStr = [NSString stringWithFormat:#"%#/%#", submitReportUrl, [self urlEncode:path]];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:urlStr]];
[request setDelegate:self];
NSMutableDictionary *userinfo = [[NSMutableDictionary alloc] init];
[userinfo setObject:NSStringFromSelector(self.didFinishSelector) forKey:#"didFinishSelector"];
[userinfo setObject:NSStringFromSelector(self.didFailSelector) forKey:#"didFailSelector"];
[request setUserInfo:userinfo];
[request addRequestHeader:#"apiKey" value:apiKey];
[request setRequestMethod:method];
NSArray *keys = [params allKeys];
for ( NSString *key in keys )
[request addPostValue:[params objectForKey:key] forKey:key];
[self.operationQueue addOperation:request];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
I had the same problem working with the post. So research where was the problem. If you did not add the about line of the code. AFNetworking will automatically add in the header
Content-Type : "text/html"
either one
Cotent-Type : "text/plain"
By adding above code becomes
Content-Type : "application/json"
So the problem is solved. Since the server is expecting JSON.
I'm using the following code to set up my operation manager:
requestSerializerJson = [AFJSONRequestSerializer serializer];
[requestSerializerJson setValue:[taskHandler getBranchesApiConstantForName:#"header_value_content_type"] forHTTPHeaderField:[taskHandler getBranchesApiConstantForName:#"header_name_content_type"]];
[requestSerializerJson setValue:[taskHandler getBranchesApiConstantForName:#"header_value_api_key"] forHTTPHeaderField:[taskHandler getBranchesApiConstantForName:#"header_name_api_key"]];
httpRequestOperationManager = [AFHTTPRequestOperationManager manager];
httpRequestOperationManager.requestSerializer = requestSerializerJson;
httpRequestOperationManager.responseSerializer = [AFJSONResponseSerializer serializer];
httpRequestOperationManager.operationQueue = [[NSOperationQueue alloc] init];
httpRequestOperationManager.operationQueue.maxConcurrentOperationCount = 1;
Then, I've got a method to download multiple JSON strings:
- (void)downloadBranches {
NSLog(#"Test %#", httpRequestOperationManager.requestSerializer.HTTPMethodsEncodingParametersInURI);
for (NSString *branchUuid in taskHandler.addedBranchesUuids) {
NSString *urlString = [NSString stringWithFormat:#"%#%#%#", urlBase, [taskHandler getBranchesApiConstantForName:#"getbranch_suffix"], branchUuid];
NSURL *URL = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSLog(#"Test %#", request.allHTTPHeaderFields);
AFHTTPRequestOperation *op = [httpRequestOperationManager HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
op.responseSerializer = [AFJSONResponseSerializer serializer];
[httpRequestOperationManager.operationQueue addOperation:op];
}
}
All the operations are performed but I get a message from the server which says that I didn't supply the authentication key.
I specifically set it in the 3rd line - for the requestSerializerJson which is then added to the httpRequestOperationManager so all of the requests should be using the headers.
I added an NSLog to print request.allHTTPHeaderFields but it says "(null)".
How can I fix this?
downloadBranches is completely bypassing the serializer by building an NSURLRequest manually. The whole point of the serializer is to do that for you.
You need to call requestWithMethod:URLString:parameters: on your serializer, which will return an NSURLRequest with the headers you want.
Or just use the operation manager's GET:… method inside that for loop; your use case doesn't look like it requires this other stuff at all.
I am implementing following paypal REST API:
curl -v https://api.sandbox.paypal.com/v1/vault/credit-card \
-H 'Content-Type:application/json' \
-H 'Authorization: Bearer {accessToken}' \
-d '{
"payer_id":"user12345",
"type":"visa",
"number":"4417119669820331",
"expire_month":"11",
"expire_year":"2018",
"first_name":"Joe",
"last_name":"Shopper"
}'
I have successfully implement this api in AFNetworking 1.3.3 with following Code. Where PPWebService is subclass of AFHTTPClient
[[PPWebService sharedClient] setParameterEncoding:AFJSONParameterEncoding];
[[PPWebService sharedClient] setDefaultHeader:#"Content-Type" value:#"application/json"];
[[PPWebService sharedClient] setDefaultHeader:#"Authorization" value:[NSString stringWithFormat:#"Bearer %#", accessToken]];
[[PPWebService sharedClient] postPath:#"vault/credit-card"
parameters:creditCard
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary *response = [self JSONToObject:operation.responseString];
creditCardId = response[#"id"];
if(creditCardId)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Credit card" message:#"Saved !!" delegate:nil cancelButtonTitle:#"on" otherButtonTitles:nil];
[alert show];
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Credit card" message:error.description delegate:nil cancelButtonTitle:#"on" otherButtonTitles:nil];
[alert show];
}];
I want to use AFNetworking 2.x.x in my project. But I am not able to do it with this new version.
I have subclass AFHTTPRequestOperationManager. I search internet and people suggest me to use AFJSONRequestSerializer. All other code is very similar. But than also I am getting bad request error.
So how can I send raw JSON string in with POST method in AFNetworking 2.x.x?
EDIT
Code for AFNetworking 2.X.X
Error Status : 404 Bad Request
Response :
{"name":"MALFORMED_REQUEST","message":"The request JSON is not well formed.","information_link":"https://developer.paypal.com/docs/api/#MALFORMED_REQUEST","debug_id":"ab3c1dd874a07"}
I am getting proper response by using Postman as shown in following screenshot.
So finally I got answer. I use subclass of AFHTTPSessionManager to implement API in my project. And use it with singleton object. So this is my singleton method.
+ (MASWebService *)APIClient
{
static MASWebService *_sharedClient = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
NSURL *baseURL = [NSURL URLWithString:BaseURL];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
_sharedClient = [[MASWebService alloc] initWithBaseURL:baseURL sessionConfiguration:config];
_sharedClient.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
_sharedClient.requestSerializer = [AFJSONRequestSerializer serializer];
[_sharedClient.requestSerializer setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
});
return _sharedClient;
}
The main key line is setting Request Serializer HTTP Header "Content-Type" to "application/json"
If you are not subclassing AFHTTPSessionManager and using AFHTTPRequestOperationManager for single request than also it will work because AFHTTPRequestOperationManager is also conform to AFURLRequestSerialization protocol as property of AFHTTPRequestSerializer. I have not done it but it should look like this.
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = #{#"foo": #"bar"};
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
[manager.requestSerializer setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[manager POST:#"http://example.com/resources.json" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
I hope this will work. Inform me in comment if I am wrong somewhere.
Source : AFNetworking 2.0 POST request working example code snippet
So how can I send raw JSON string in with POST method in AFNetworking 2.x.x?
I had the same issue when trying to use SOAP+XML data with AFHTTPRequestOperationManager. Apparently the request serializer should be subclassed to make provision for your special serialisation needs, but this way seems easier:
NSError *error = nil;
NSData *envelopeData = [NSJSONSerialization dataWithJSONObject:params options:options error:nil];
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:#"POST"
URLString:path
parameters:nil
error:&error];
// In my case, I also needed the following:
// [request setValue:action forHTTPHeaderField:#"SOAPAction"];
[request setHTTPBody:envelopeData];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] init];
operation = [self HTTPRequestOperationWithRequest:request
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
// parse response here
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
// parse response here
}];
It hijacks the request serialiser that is created by AFHTTPRequestOperationManager, inserts the parameter data into the HTTP body, and then passes this new request into the AFHTTPRequestOperation.
I'm impementing an application in iOS7, it's kind of a social network app with posts with images and a backend that saves all of the data sent form the client. The iOS client is sending the information of the post via json and after the info is sent, it starts to send the image via multipart form using AFNetworking.
I need to be notified when the image is sent, so that I can refresh the main view of the app with the new posts, including the recently posted by the client. In the practice if I request the backend for the last posts and the multipart hasn't finished, the sending of the image gets interruped and fails to send the image.
The backend is develop in WCF and is a RESTful JSON web service.
Here is the method that sends the post to the backend:
+(void)addPostToServerAddtext:(NSString *)text addimage:(UIImage *)image addbeach:(NSString *)beach location:(NSString*)location;
{
NSLog(#"entro a addPost");
NSString *urlBackend = [[NSBundle mainBundle] objectForInfoDictionaryKey:#"URLBackend"];
NSData* dataImage = UIImageJPEGRepresentation(image, 1.0);
NSString* ImageName = [NSString stringWithFormat:#"%#_%#.jpg",idUser ,dateToServer];
NSString *jsonRequest = [NSString stringWithFormat:#"{\"Date\":\"%#\"...."];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"%#newPost",urlBackend]];
NSMutableURLRequest *request = [ [NSMutableURLRequest alloc] initWithURL:url];
NSData *requestData = [NSData dataWithBytes:[jsonRequest UTF8String] length:[jsonRequest length]];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:[NSString stringWithFormat:#"%d", [requestData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:requestData];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
if (image != nil) {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:[NSString stringWithFormat:#"%#FileUpload",urlBackend]
parameters:nil
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:dataImage name:#"image" fileName:ImageName mimeType:#"image/jpg" ];
}
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success: %#", responseObject);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
}
}
A couple of thoughts:
You say:
The iOS client is sending the information of the post via json and after the info is sent, it starts to send the image via multipart form using AFNetworking.
Technically, you're not waiting for the information to be sent, but you're doing these concurrently. Do you want these to be concurrent? Or sequential? Or why not just a single request that posts the information as well as the image?
I'd suggest using AFNetworking for both requests. You've got a powerful framework for managing network requests, and it feels awkward to see hairy NSURLConnection code in there.
If you keep the NSURLConnection code in there, note that you do not want to start a NSURLConnection, unless you used initWithRequest:delegate:startImmediately: with NO for that last parameter. You're effectively starting it twice, which can cause problems. I'd suggest removing the start call.
Setting all of that aside, what you want to do is to add a completion block parameter to your method, e.g., something like:
+ (void)addPostToServerAddtext:(NSString *)text addimage:(UIImage *)image addbeach:(NSString *)beach location:(NSString*)location completion:(void (^)(id responseObject, NSError *error))completion
{
// ...
if (image != nil) {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:[NSString stringWithFormat:#"%#FileUpload",urlBackend] parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:dataImage name:#"image" fileName:ImageName mimeType:#"image/jpg" ];
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (completion) completion(responseObject, nil);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (completion) completion(nil, error);
}];
}
}
You'd then invoke that like so:
[Persistence addPostToServerAddtext:text addimage:image addbeach:nil location:annotation completion:^(id responseObject, NSError *error) {
if (error) {
// handle error
return
}
// otherwise use the responseObject
}];
Now, I don't know what parameters you want to return in your completion block (I'm assuming you wanted to return what the AFHTTPRequestOperationManager did), but just change the parameters for that completion block as suits your needs.
Unrelated to your original question, but I notice that you're building jsonRequest like so:
NSString *jsonRequest = [NSString stringWithFormat:#"{\"Date\":\"%#\"...."];
That's a little risky if any of those fields include user supplied information (e.g. what if the user used double quotes in the information provided). I'd suggest you build a dictionary, and then build the jsonRequest from that. It will be more robust. Thus:
NSDictionary *dictionary = #{#"Date" : date,
#"Message" : message};
NSError *error = nil;
NSData *request = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:&error];
if (error)
NSLog(#"%s: dataWithJSONObject error: %#", __FUNCTION__, error);
Or, if you use AFNetworking, I believe it will do this JSON conversion of your dictionary for you. But, bottom line, be very wary about creating JSON strings yourself, at least if the request might include any user supplied information.