How to pass JSON request - objective-c

I am new to AFNetworking framework. I try to send JSON request to the server to get JSON response, so i tried something like this:
NSURL *url = [NSURL URLWithString:#"http://data.mycity.gov/api/views/INLINE/rows.json?method=index"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:[NSString stringWithFormat:#"application/json"] forHTTPHeaderField:#"Content-Type"];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"Success");
} failure:^(NSURLRequest* req,NSHTTPURLResponse *req2, NSError *error,id mex) {
NSLog(#"Failed");
NSLog(#"%#",[error description]);
}];
[operation start];
So i always find my self into the failure block, with this error description:
Error Domain=com.alamofire.networking.error Code=-1011 "Expected status code in (200-299), got 400" UserInfo=0x7b58030 {NSErrorFailingURLKey=http://data.mycity.gov/api/views/INLINE/rows.json?method=index, NSLocalizedDescription=Expected status code in (200-299), got 400}
Any ideas? am i missing something?

Status Code of 400 means - Bad Request
The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications.
When I try to go to that URL:
http://data.mycity.gov/api/views/INLINE/rows.json?method=index"
, I get a not found error
Make sure the API you are using is correct, if the web service returns JSON, you should be able to type that URL into your browser and get a JSON response.

It seems your server is returning 400, "Bad Request". Check that your URL is correct.
BTW your stringWithFormat is redundant. You can replace
[NSString stringWithFormat:#"application/json"]
with
#"application/json"

Related

NSUrlSession proxy request fails with error code 310 (kCFErrorHTTPSProxyConnectionFailure)

I'm trying to send a POST request to a specific URL through a proxy server. To test that the code I'm writing is working, I installed squidman on my machine and started a proxy server on port 33074. I tested the proxy server by changing the network settings to use the proxy when making HTTP/HTTPS requests and it's working ok.
Now I wrote the following code:
NSDictionary* proxyConfig = #{
(NSString*) kCFNetworkProxiesHTTPSEnable: #(1),
(NSString*) kCFNetworkProxiesHTTPSProxy: #"127.0.0.1",
(NSString*) kCFNetworkProxiesHTTPSPort: #"33074",
};
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
[sessionConfig setTimeoutIntervalForRequest:60];
[sessionConfig setConnectionProxyDictionary:proxyConfig];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"https://the-host-where-im-posting"]];
[request setHTTPMethod:#"POST"];
[request setValue:[[NSString alloc] initWithFormat:#"%lu",length] forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:data];
NSURLSession *session = [self createHttpSession];
NSURLSessionDataTask* dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if(httpResponse.statusCode == 200){
//...
} else {
LOGERROR(#"Error: %#", error);
}
}
The problem is that the request is not successfull and the following error is logged:
Error: Error Domain=kCFErrorDomainCFNetwork Code=310 "(null)" UserInfo={_kCFStreamErrorCodeKey=-2096, _kCFStreamErrorDomainKey=4}
Additional Info:
1. It should be noted that the requests submits perfectly without setting the proxyConfig dictionary.
2. A similar error gets reported if I'm trying to submit the request using HTTP through the proxy (by correspondingly changing the keys in the proxyConfig dictionary) with a small diff in the Err Code and _kCFStreamErrorCodeKey: 306 instead of 310 and -2094 instead of -2096.
3. The process making the request runs as a daemon.
What exactly am I doing wrong ? What am I missing ?
I was setting the kCFNetworkProxiesHTTPSPort field from the proxyConfig dictionary to a value of type NSString. After carefully reading the documentation for it I observed the following:
Key for the port number associated with the HTTPS proxy; value is a CFNumber which is the port number.
The library was encountering an object that was not a CFNumber and was using the default port for HTTPS communication to connect to the proxy instead (443). That's bad error handling imho. It was essentially silently trying to make a request using a port that I was not aware of. Changing the proxyConfig dictionary to the following fixed the problem:
NSDictionary* proxyConfig = #{
(NSString*) kCFNetworkProxiesHTTPSEnable: #(1),
(NSString*) kCFNetworkProxiesHTTPSProxy: #"127.0.0.1",
(NSString*) kCFNetworkProxiesHTTPSPort: #(33074),
};

Basic and OAuth Authentication headers at the same time

Is it possible to use Basic and OAuth authorization headers in the same request with AFNetworking (avoiding the overwriting) ?
I have this code:
NSURL *url = [NSURL URLWithString:#"https://www.infojobs.net/"];
AFOAuth2Client *OAuthClient = [[AFOAuth2Client alloc] initWithBaseURL:url clientID:kClientID secret:kClientSecret];
[OAuthClient registerHTTPOperationClass:[AFJSONRequestOperation class]];
[OAuthClient authenticateUsingOAuthWithPath:#"oauth/authorize" code:self.authorizationCode redirectURI:kInfoJobsRedirectURLString success:^(AFOAuthCredential *credential) {
NSLog(#"Credentials: %#", credential.accessToken);
if (![credential.accessToken isEqualToString:#""]) {
self.isAuthenticated = YES;
[AFOAuthCredential storeCredential:credential withIdentifier:#"kInfoJobsAccessToken"];
[[InfoJobsAPI sharedClient] setAuthorizationHeaderWithToken:credential.accessToken];
// (!) This overwrites the Authorization header set with the accessToken
[[InfoJobsAPI sharedClient] setAuthorizationHeaderWithUsername:kClientID password:kClientSecret];
success(credential);
}
} failure:^(NSError *error) {
NSLog(#"Error: %#", error.localizedDescription);
}];
And I need a request like this:
GET /api/1/application HTTP/1.1
Host: api.infojobs.net
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Authorization: OAuth 07d18fac-77ea-461f-9bfe-a5e9d98deb3d
....
But I can't set the "Basic" and "OAuth" Authorization headers in the same request because AFNetworking seems to overwrite this header as seen in documentation
It's possible to use "Basic" and "OAuth" in a same Authorization header, maybe splitting both with a "\n" ?
Thanks, and sorry for my poor english
Edit
Finally, I can use the "Basic" and "Oauth" authentications in the same header, this is the code:
[[InfoJobsAPI sharedClient] setAuthorizationHeaderWithUsername:kClientID password:kClientSecret];
AFOAuthCredential *credential = [AFOAuthCredential retrieveCredentialWithIdentifier:#"kInfoJobsAccessToken"];
NSMutableURLRequest *request = [self requestWithMethod:#"GET" path:#"/api/2/candidate" parameters:nil];
[request addValue:[NSString stringWithFormat:#"OAuth %#", credential.accessToken] forHTTPHeaderField:#"Authorization"];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
DLog(#"Response : %#",JSON);
}failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
DLog(#"Error : %#",error);
}];
[operation start];
According to the HTTP specification there can be only one Authorization header in a request. So the behavior the library is showing is correct according to that specification: the second call to setAuthorizationHeader... overwrites the previous one.
What you'll typically see in HTTP is that there is a handshaking phase, where the server tells the client what authorization protocols it can accept. The client can then choose from those protocols, which one it wants to use.

AFNetworking - Requests with ETag

I am trying to do a request on a server, which responds with an Etag for cache purposes. I have written the following code for it, but the response for these calls is random most of the time i.e. sometimes response status code is 200 and some times 304(expected). Am I doing something wrong in my code or is there something specific with AFNetworking that I should keep in mind.!
NSURL *url = [NSURL URLWithString:#"http://ia.media-imdb.com/images/M/MV5BNzI0NTY5NzQwMV5BMl5BanBnXkFtZTcwOTQyNTA5OA##._V1._SY90_.jpg"];
NSMutableURLRequest *aRequest = [NSMutableURLRequest requestWithURL:url];
[aRequest setValue:#"\"61-smtLpBSL_SY90_#1\"" forHTTPHeaderField:#"If-None-Match"];
NSLog(#"headers: %#", aRequest.allHTTPHeaderFields);
AFImageRequestOperation *operation = [AFImageRequestOperation imageRequestOperationWithRequest:aRequest imageProcessingBlock:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
NSLog(#"%# %d", response.allHeaderFields, response.statusCode);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"Request failed with error: %#", error);
}];
[operation start];
I had the same problem, I managed to fix this by changing my request to
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:60];
I have tried your code and I receive status 200 - OK which is like it should be.
Code 304 - Not modified, I wasn't able to get. I have tried running command several times fast and slow but I always get 200 as a response.
Do you have more details when exactly it happens that you get 304 as response code?
304 response code generally means that the content hasn't been modified and you should get original request that had 200 as a response included in it.
Here you can read a bit more about Etag: ETag vs Header Expires
I also had a problem with the Etag logic and AFNetworking. My problem was just the cachePolicy not correctly set...
var manager = AFHTTPRequestOperationManager()
manager.requestSerializer = AFHTTPRequestSerializer()
manager.requestSerializer.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData
manager.requestSerializer.setValue(etag, forHTTPHeaderField: "If-None-Match")
manager.GET(fullPath, parameters: parameters, success: {}, failure: {}))
I hope it will help someone !

How would i create a GET method to a webserver with AFNetwork

I was wondering how i would get AFNetworking code to visit a link on my web server(PHP Script) and get the response data, and put it into a string?
Could anyone post an example of this?
Thanks alot!
here is the required code to get response from server using AFNETWorking.Just add AFNetworking Library and the Required frameWorks.After that use the below code.
NSURL *url = [[NSURL alloc] initWithString:#"http://itunes.apple.com/search?term=harry&country=us&entity=movie"];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"JSON");
self.movies = [JSON objectForKey:#"results"];
[self.tbleView reloadData];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Request Failed with Error: %#, %#", error, error.userInfo);
}];
self.movies is name of mutable Array you can use any name instead of this.
Also you can check here
https://github.com/AFNetworking/AFNetworking
AFHTTPRequests get passed default NSURLRequest objects. stock ones - no modification for AFNetwork
to build THAT see
How to add GET parameters to an ASIHttpRequest?

AFNetworking PUT and Delete with Rails

In looking at the AFNetworking documentation, the Put and Delete methods take in a path and a dictionary of parameters. I am using Rails as my backend which expects these two types to take the form of Put /object/1.json and Delete /object/1.json. Should I build up a path string by adding in the Id or do I send a Put or Delete with the Id as one of the params in the Dictionary?
Typically when I do with PUT and similar type HTTP requests when using AFNetworking is something like this:
// Create an HTTP client with your site's base url
AFHTTPClient *client = [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:#"http://example.com"]];
// Setup the other parameters you need to pass
NSDictionary *parameters = #{#"username" : #"bob", #"password" : #"123456"};
// Create a NSURLRequest using the HTTP client and the path with your parameters
NSURLRequest *request = [client requestWithMethod:#"PUT" path:#"object/1.json" parameters:parameters];
// Create an operation to receive any response from the server
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
// Do stuff
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
// Handle error
}];
// Begin the operation
[operation start];
If you look in AFHTTPClient.h there are examples for how to format your base url and your paths. There's more information on these methods in the AFNetworking documentation