Wanted: Up-to-date example for JSON/POST with basic auth using AFNetworking-2
UPDATE: The JSON portion of the following was found to work for PUT/POST, but NOT for GET/HEAD/DELETE
After some wrangling, and help outside SO, I got something working, which I wanted to leave as a memento. In the end, I was really very impressed with AFNetworking-2. It was so simple, I kept trying to make it harder than it should have been. Given a jsonDict
method that returns the json packet to send, I created the following:
- (void) submitAuthenticatedRest_PUT
{
// it all starts with a manager
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
// in my case, I'm in prototype mode, I own the network being used currently,
// so I can use a self generated cert key, and the following line allows me to use that
manager.securityPolicy.allowInvalidCertificates = YES;
// Make sure we a JSON serialization policy, not sure what the default is
manager.requestSerializer = [AFJSONRequestSerializer serializer];
// No matter the serializer, they all inherit a battery of header setting APIs
// Here we do Basic Auth, never do this outside of HTTPS
[manager.requestSerializer
setAuthorizationHeaderFieldWithUsername:@"basic_auth_username"
password:@"basic_auth_password"];
// Now we can just PUT it to our target URL (note the https).
// This will return immediately, when the transaction has finished,
// one of either the success or failure blocks will fire
[manager
PUT: @"https://101.202.303.404:5555/rest/path"
parameters: [self jsonDict]
success:^(AFHTTPRequestOperation *operation, id responseObject){
NSLog(@"Submit response data: %@", responseObject);} // success callback block
failure:^(AFHTTPRequestOperation *operation, NSError *error){
NSLog(@"Error: %@", error);} // failure callback block
];
}
3 setup statements, followed by 2 message sends, it really is that easy.
EDIT/ADDED: Here's an example @jsonDict implementation:
- (NSMutableDictionary*) jsonDict
{
NSMutableDictionary *result = [[NSMutableDictionary alloc] init];
result[@"serial_id"] = self.serialID;
result[@"latitude"] = [NSNumber numberWithDouble: self.location.latitude];
result[@"longitude"] = [NSNumber numberWithDouble: self.location.longitude];
result[@"name"] = self.name;
if ([self hasPhoto])
{
result[@"photo-jpeg"] = [UIImageJPEGRepresentation(self.photo, 0.5)
base64EncodedStringWithOptions: NSDataBase64Encoding76CharacterLineLength];
}
return result;
}
It should just return a dictionary with string keys, and simple objects as values (NSNumber, NSString, NSArray (I think), etc). The JSON encoder does the rest for you.
Related videos on Youtube
Travis Griggs
Updated on October 14, 2022Comments
-
Travis Griggs over 1 year
I have a toy app which submits an https JSON/POST using basic auth security. I've been told I should consider using AFNetworking. I've been able to install AFNetwork-2 into my XCode project (ios7 target, XCode5) just fine. But none of the examples out there seem to be relevant to current versions of AFNetworking-2, but rather previous versions. The AFNetworking docs are pretty sparse, so I'm struggling how to put the pieces together. The non-AFNetworking code looks something like:
NSURL *url = [NSURL URLWithString:@"https://xxx.yyy.zzz.aaa:bbbbb/twig_monikers"]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy: NSURLRequestUseProtocolCachePolicy timeoutInterval: 10.0]; NSData *requestData = [NSJSONSerialization dataWithJSONObject: [self jsonDict] options: 0 error: nil]; [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"]; NSData *plainPassText = [@"app_pseudouser:sample_password" dataUsingEncoding:NSUTF8StringEncoding]; NSString *base64PassText = [plainPassText base64EncodedStringWithOptions: NSDataBase64Encoding76CharacterLineLength]; [request setValue:[NSString stringWithFormat: @"Basic %@", base64PassText] forHTTPHeaderField: @"Authorization"]; FailedCertificateDelegate *fcd=[[FailedCertificateDelegate alloc] init]; NSURLConnection *c=[[NSURLConnection alloc] initWithRequest:request delegate:fcd startImmediately:NO]; [c setDelegateQueue:[[NSOperationQueue alloc] init]]; [c start]; NSData *data=[fcd getData]; if (data) NSLog(@"Submit response data: %@", [NSString stringWithUTF8String:[data bytes]]);
I'm not looking for someone to write my code for me. I just can't seem to figure out how to map the AFNetworking-2 parts over to that. Any links, or examples, or explanations much welcome.
UPDATE 1
The above is a non AF version that is known to work. Moving trying to get it all in one go, I just tried:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; manager.requestSerializer = [AFJSONRequestSerializer serializer]; [manager.requestSerializer setAuthorizationHeaderFieldWithUsername:@"app_pseudouser" password:@"sample_password"]; AFHTTPRequestOperation *operation = [manager PUT: @"https://172.16.214.214:44321/twig_monikers" parameters: [self jsonDict] success:^(AFHTTPRequestOperation *operation, id responseObject){ NSLog(@"Submit response data: %@", responseObject);} failure:^(AFHTTPRequestOperation *operation, NSError *error){ NSLog(@"Error: %@", error);} ];
Which produces the following error:
2013-10-09 11:41:38.558 TwigTag[1403:60b] Error: Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn’t be completed. (NSURLErrorDomain error -1012.)" UserInfo=0x1662c1e0 {NSErrorFailingURLKey=https://172.16.214.214:44321/twig_monikers, NSErrorFailingURLStringKey=https://172.16.214.214:44321/twig_monikers}
Watching on the server side, nothing ever makes it through. I don't know if it is because the https, or what, but I can flip the app back to the original code, and it gets through just fine.
-
Travis Griggs over 10 yearsOuch, anything I can do to avoid the downvotes? The AFNetworking home page explicitly encourages questions to be asked on SO.
-
Jano over 10 yearsWhy are you going for AFNetworking-2 instead NSURLSession?
-
Travis Griggs over 10 years@Jano Some colleagues encouraged me to look at AFNet after seeing stuff like the above. Having watched some presentations on AFNet-2, there appears to be those that still feel that using AFNet-2 (which wraps around NSURLSession) offers compelling advantages.
-
PostCodeism over 10 yearsWow there were downvotes here? It's good to see justice has prevailed. Some people are real jerks - people, help the guy or STFU!
-
Rok Jarc over 10 yearsAgreed: even when looking at the first revision of the question i see no reason for downvoting this.
-
Travis Griggs over 10 yearsThe down votes were at origination time. It's all been uphill since then. I've noticed a real trend lately amongst the SO community to be overly curative. It's disappointing.
-
-
jerik over 10 yearsHow does the code for the jsonDict look like? Is it serialized as string?
-
jerik over 10 yearsPerfect. Solves perhaps my image uploading issue as well. Thanks!
-
Joshua Dance over 10 yearsFrom the AFNetworking docs it says that the default requestSerializer is "set to an instance of
AFHTTPSerializer
, which serializes query string parameters forGET
,HEAD
, andDELETE
requests, or otherwise URL-form-encodes HTTP message bodies." -
PostCodeism over 10 yearsOk but I have that exact same setup for a GET request and it gives me a 3840 error: JSON text did not start with array or object and option to allow fragments not set
-
PostCodeism over 10 yearsThis didn't work for me. AFNetworking 2 doesn't work with a token and GET request: stackoverflow.com/questions/20480072/…
-
Travis Griggs over 10 yearsI ran into this myself yesterday. I've asked on the AFNetworking github forum and had it confirmed that it's not a bug per se (github.com/AFNetworking/AFNetworking/issues/1678). I'll update the answer above to reflect that and see if I can't contribute to your new question.
-
Trianna Brannon almost 9 yearsThanks, this works exactly the same for a POST as well if you switch out the PUT.