I have a web service that sends and accepts JSON, and handles all special characters by HTML-encoding them. I can parse and read the web service data perfectly fine using the following (error checking removed for brevity):
cleanJsonString = [self stringByDecodingXMLEntities:jsonString];
NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData: [cleanJsonString dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES]
options: NSJSONReadingMutableContainers
error: &parseError];
The problem comes into play when I need to serialize user input to send data back to the server. I'm currently using the following:
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:myDictionaryObject
options:NSJSONWritingPrettyPrinted
error:&parseError];
NSString *myString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
The problem is that this does not account whatsoever for special characters. No errors occur on the client side, but the web service is receiving bad data. I know I could brute force it by recursing the dictionary object and encoding every string before serializing. But would it be safe to just do one single encode operation on the entire JSON string without corrupting it? Or, even more ideally, is there such a parameter that would handle encoding during the serialization process. Any advice or suggestions greatly appreciated.
Related
i am trying to do a generic - hmac verification with an iOS app and an express node.js app.
generating the hmac using given samples at: http://www.jokecamp.com/blog/examples-of-creating-base64-hashes-using-hmac-sha256-in-different-languages/#js
having the following problem:
subclassed AFHTTPRequestOperationManager to gain access to POST:
i want to hmac the nsdictionary parameters.
so convert the nsdicionary to json - hmac it - and set hmac header in request.
on the receiver side, i use crypto-js and express to access the req.body - and hmac the json object.
problem is! - those keys are not in same order, even if i force the sort on the keys in nsdictionary, the transoformed json does not come in the order way.
after hours of googling i accepted that json objects cannot be orderd, in an reliable way.
so what is the best-practice to hmac an nsdictionary, by ignoring the order?
(i could hmac on only a few keys, but that would be way to less generic, mean adding a dictionary key would require code change in ios and express)
generating the hmac only based on the URI - works fine, but its a way to open :)
UPDATE:
to be a bit more specific.
on the app i transform my nsdictionary to json by and then calculate the hmac of the json_string
NSDicationary * dic = #{#"key1", "value1",#"key2", "value2"}
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic
options:(NSJSONWritingOptions) (prettyPrint ? NSJSONWritingPrettyPrinted : 0)
error:&error];
NSString * json_str = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]
and i do a AFNetworking POST request calling passing my nsdictionary as parameters:
- (AFHTTPRequestOperation *)POST:NSString *)URLString parameters:(id)parameters success:(void (^)(AFHTTPRequestOperation *operation,id responseObject))success failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
on the receiver app (node.js/express) i get the ctx.req.body containing the javascript object from the POST request -> but here it does not have the same order as in the json encoded string from the app (and i have not found a way to preserve order)
as i am not knowing what keys are in nsdictionary a static key-hmac would not work.
Since the JSON is just a string there is no ordering issue after it has been created. The point is to create the HMac value after converting the dictionary to a JSON string.
On the sender create the JSON representation and HMac the JSON. Send the HMAc result along with the JSON.
On the receiver HMac the received JSON and compare with the received HMac value.
The two HMacs should be equal.
Another option is to write a method on each side that examines each dictionary element key/item in the same predefined order and compose a string or data object from that. Then HMAC that result.
I have to pass JSON dictionary as POST data to a Webservice. One key involves an Amazon S3 URL string.
The sample request json which works has the URL as....
https:\/\/myappbucket.s3.amazonaws.com\/2014230407_102323.jpg?response-content-type=image\/png&Signature=123456%3D&Expires=139756222548&AWSAccessKeyId=ABCDEF
Notice the backslashes just before the forwardslashes? I have never seen a URL like that, but thats how I'm supposed to pass it.
I tried
stringByAddingPercentEscapesUsingEncoding
and
stringByReplacingPercentEscapesUsingEncoding
while using NSASCIIStringEncoding and NSUTF8StringEncoding
Can anyone make sense of this?
if we try to convert url into legal url trough stringByAddingPercentEscapesUsingEncoding than it adds all percent escapes necessary to convert the receiver into a legal URL string.Uses the given encoding to determine the correct percent escapes.
if we use stringByReplacingPercentEscapesUsingEncoding than it replaces all percent escapes with the matching characters as determined by the given encoding.
mostly to get valid url, we can use NSUTF8StringEncoding to remove backslashes just before the forwardslashes in url.
Generally, you should use a JSON serializer library (e.g. NSJSONSerialization) in order to obtain a JSON from a JSON representation and not try to create the JSON yourself.
A JSON representation is a NSDictionary or NSArray object containing other objects which recursively represent your JSON. Your URL will be represented as a NSString.
What you need to do is simply have a valid URL as a NSString, properly encoded according RFC 3968 and assign it the JSON representation, e.g.:
NSURL* url = ...;
NSDictionary* jsonObject = #{#"url": [url path]};
Now, you can serialize the JSON representation to a JSON:
NSError* error;
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:jsonObejct
options:0
error:&error];
That's it, and you don't bother how the JSON encoded string looks like (encapsulated in the NSData object as a UTF-8 character sequence).
Purposefully, when you POST this JSON, you SHOULD specify a corresponding request header:
ContentType: application/json
which lets you just use the JSON data as body data as is:
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
request.HTTPBody = jsonData;
Side note: [url path] returns a URL as a string according RFC 1808 which is obsoleted by RFC 3968 since January 2005 already. Today, there are newer APIs since iOS 7.0, see NSURLComponents.
I am trying to make an HTTP PUT request to a CouchDB server. I am converting an NSString instance to NSData. I then convert this NSData instance to an NSArray and attempt to PUT this to CouchDB. So something like this:
//convert string to NSData
NSData *docData = [#"{\"name\":\"nick\"}" dataUsingEncoding:NSUTF8StringEncoding];
//NSData to NSArray
NSArray *arrayJson = [NSArray arrayWithObjects:[NSJSONSerialization JSONObjectWithData:docData options:kNilOptions error:nil],nil];
I am then creating an HTTP PUT request using AFNetworking (which is rad btw ;))
The problem is that this creates a json string which looks like:
[{"name":"nick"}]
This is valid JSON but Couch complains with 400 Bad JSON. Removing the [ ]s fixes the problem. I'm sure these brackets are the result of converting NSData to NSArray but I'm not sure how else to accomplish this using NSJSONSerialization. Can anyone help?
Thanks!
Edit
For clarity sake let me explain the problem I was having further. I am creating a document using the CouchDB HTTP API using a PUT HTTP request. The document could be hand coded JSON and that is why I have this parsing challenge. Couch expects a single document to create. Therefore it expects a single JSON object. NOT an array of them. That seems to be why [{"key":"value"}] returns a 400 HTTP response from Couch. Even if the array contains a single object. Seems a bit picky that the API wouldn't just infer correctly based on the array length.. but I guess you could argue either way. See the selected answer below. This is what I was looking for. Thanks to all those who responded!
You can let NSJSONSerialization do the conversion from Foundation object to string. This guarantees proper escaping and makes the code more readable.
If you have a key-value pair as in your sample above, you could do:
NSError* error = nil;
NSDictionary* jsonDict = #{#"name": #"nick"};
NSData* putData = [NSJSONSerialization dataWithJSONObject:jsonDict options:kNilOptions error:&error];
You should be able to directly put that into the content of your PUT request, without wrapping it in an additional array. If the endpoint that handles the request requires you to send an array, you should create the array as an Foundation object (NSArray) and serialize that as JSON before sending it to the server:
NSArray* jsonArray = #[#{#"name": #"nick"}];
The title of your question is "Deserialize JSON without wrapping in [ ]" - Shouldn't that be "Serialize JSON without wrapping in [ ]"?
I changed it, please change it back if I misunderstood your question.
I have an iPad application that uses table view controllers to present lists of data. I want to connect these tables to data in a SQL Server. I have very little experience in this realm of programming and I am not sure where to begin. In the long run I'd like adding/editing/deleting data on the app to sync with the server as well. I understand that this is a very broad question, so I am mainly looking for suggestions to help me get started. I, for example, do not want to start researching and learning Core Data if it is not the framework that can accomplish my goal.
In short, how can I connect my application to a SQL Server so that I can access its data and sync it to a device? Any example code/walkthroughs would be much appreciated.
I am currently working in an iOS application that requires this same functionality. For mySQL database queries on the server, I am using server-side PHP scripts that can accept variables, such as the table name or database search term.
What I do is I make an HTTP GET request using objective-C's NSMutableURLRequest, then have the server process the request (in PHP), and then return the database query results to my application in JSON format. I use SBJsonParser to parse the returned data into an NSData, and then an NSArray object.
An example of making an HTTP request in Objective-C:
NSString *urlString = [NSString stringWithFormat:#"http://website.com/yourPHPScript.php?yourVariable=something"];
NSURL *url = [NSURL URLWithString: urlString];
NSMutableURLRequest *request1 = [[NSMutableURLRequest alloc] initWithURL:url];
/* set the data and http method */
[request1 setHTTPMethod:#"GET"];
[request1 setHTTPBody:nil];
/* Make the connection to the server with the http request */
[[NSURLConnection alloc] initWithRequest:request1
delegate:self];
There is more code that you need to add to actually respond to the request when it returns, and I can post an example of that if you would like.
I actually dont know if this is the best way to do this, but It has worked for me so far. It does require that you know PHP though, and I don't you if you have any experience with it.
UPDATE:
Here is some sample code showing how to respond to the request. In my case, since I am getting a JSON encoded response, I use the SBJsonParser to parse the response.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
/* This string contains the response data.
* At this point you can do whatever you want with it
*/
NSString *responseString = [[NSString alloc] initWithData:receivedData
encoding:NSUTF8StringEncoding];
/* Here I parse the response JSON string into a native NSDictionary using an SBJsonParser */
SBJsonParser *parser = [[[SBJsonParser alloc] init] autorelease];
/* Parse the JSON into an NSDictionary */
NSDictionary *responseArr = [parser objectWithString:responseString];
/* Do whatever you want to do with the response */
/* Relsease the connection unless you want to re-use it */
[connection release];
}
Also add these methods, assuming you have an NSMUtableData instance variable titled receivedData.
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[receivedData appendData:data];
}
I would not recommend connecting directly to a SQL server. You could, in theory, try to compile FreeTDS or unixODBC for iOS. I did not try it, but from my experience, at least FreeTDS should be fairly portable.
However, there are many other (and for most purposes better and easier) way of synchronizing data with a SQL Server. For example, you could use RestKit on the iPad side and a simple REST service on the SQL Server side. Or you could use OData which has a iOS library (which I just recently learned about, I have to admit).
Is there an easy way to dump the response data from a TTURLRequest? I'm getting a server side error and I'd like to be able to quickly log the response in the console without having to tail the server logs. I'm using Three20's TTURLRequest in conjunction with TTURLJSONResponse, and so far I haven't been able to view that data easily unless the response is a JSON string. Any suggestions? Thanks!
Try to print the NSERROR
NSData *returnData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];