In my project I need to send JSON object in web service API call. I have converted JSON from array.
do {
let theJSONData = try NSJSONSerialization.dataWithJSONObject(
param ,
options: NSJSONWritingOptions(rawValue: 0))
var theJSONText : String = String(data: theJSONData,
encoding: NSASCIIStringEncoding)!
print(theJSONText)
theJSONText = theJSONText.stringByReplacingOccurrencesOfString("\\", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
print(theJSONText)
let newParam = ["ESignData":theJSONText]
} catch let error as NSError {
print(error)
}
it print string correctly as
{"EntNum":"47","JobNo":"1737753","ClientID":"100","HospNo":"1","QAReason":"","DoctorNo":"1694","Action":"Sign"}
{"EntNum":"47","JobNo":"1737753","ClientID":"100","HospNo":"1","QAReason":"","DoctorNo":"1694","Action":"Sign"}
Now When I try to send this newParam dictionary in API call, it contains "\" in string parameters of JSON string.
WebService.PostURL(mainLink, methodname: ESIGNTHISDOC, param: newParam, userName: AUTH_USERNAME, password: AUTH_PWD, CompletionHandler: { (success, response) in
})
And in that web service method I have print param.
Param = {
ESignData = "{\"EntNum\":\"47\",\"JobNo\":\"1737753\",\"ClientID\":\"100\",\"HospNo\":\"1\",\"QAReason\":\"\",\"DoctorNo\":\"1694\",\"Action\":\"Sign\"}";
}
Now in this I know it is obvious in iOS because of " in string. Now the problem is that there are lots of APIs working in android app, and the API developer doesn't want to update his code according to us.
I know this problem happens because of adding JSON string in dictionary as parameter. But I have not proper justification for that so if any proof will be also helpful for me to convince him.
Any solution to convert the JSON string without backslash in iOS? I need to fix from my side if possible. Any help will be appreciate.
EDIT :
On server side it needs like
ESignData = {"EntNum":"47","JobNo":"1737753","ClientID":"100","HospNo":"1","QAReason":"","DoctorNo":"1694","Action":"Sign"}
If I pass this as parameter in POSTMAN than it gives success message. But not with our object with "\" in it.
EDIT 2:
Now printing the newParam dictionary:
print(newParam)
print("-------------------------")
print(newParam["ESignData"])
And logs :
["ESignData": "{\"EntNum\":\"47\",\"JobNo\":\"1737754\",\"ClientID\":\"100\",\"HospNo\":\"1\",\"QAReason\":\"\",\"DoctorNo\":\"1694\",\"Action\":\"Sign\"}"]
-------------------------
Optional("{\"EntNum\":\"47\",\"JobNo\":\"1737754\",\"ClientID\":\"100\",\"HospNo\":\"1\",\"QAReason\":\"\",\"DoctorNo\":\"1694\",\"Action\":\"Sign\"}")
And by debug :
Printing description of newParam:
▿ 1 elements
▿ [0] : 2 elements
- .0 : "ESignData"
- .1 : "{\"EntNum\":\"47\",\"JobNo\":\"1737754\",\"ClientID\":\"100\",\"HospNo\":\"1\",\"QAReason\":\"\",\"DoctorNo\":\"1694\",\"Action\":\"Sign\"}"
So it shows that it is in our dictionary. All the " are joined by \.
I ran into this exact issue today. For me it appears that the default encoding for any NSURLRequest is a string. So, somewhere between my creating the dictionary request and the server parsing it, the backslashes would appear and the server had problems with my payload.
I solved the issue by explicitly stating that my payload was JSON by setting the content type header.
[authRequest setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
Now when I create JSON data from a dictionary, the backslashes don't appear and the server is able to parse everything correctly.
Code snippet below for completeness:
NSMutableURLRequest *authRequest = [[[NSURLRequest alloc] initWithURL:authURL] mutableCopy];
[authRequest setHTTPMethod:#"POST"];
NSURLSession *session = [NSURLSession sharedSession];
[authRequest setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
NSDictionary *bodyDictionary = #{#"User_Name": user, #"Password_Hash": password};
if ([NSJSONSerialization isValidJSONObject:bodyDictionary]) {
NSError *error;
NSData *bodyData = [NSJSONSerialization dataWithJSONObject:bodyDictionary options:0 error:&error];
if (!error) {
[authRequest setHTTPBody:bodyData];
} else {
NSLog(#"Unable to convert to JSON DATA %#", error.localizedDescription);
}
}
Related
I'm trying to get the response from the server as NSDictionary instead of NSData, so first I'm using AFNetworking library and the server request these settings to be HTTP not JSON serializer as the following :
self.responseSerializer = AFHTTPResponseSerializer() as AFHTTPResponseSerializer
self.requestSerializer = AFHTTPRequestSerializer() as AFHTTPRequestSerializer
self.requestSerializer.HTTPMethodsEncodingParametersInURI = NSSet(array: ["GET"]) as! Set<String>
self.responseSerializer.acceptableContentTypes = NSSet(objects: "application/json","text/json","text/javascript","text/html") as? Set<String>
Next is when i get the response from the server it comes to be NSData and its because I'm using AFHTTPRequestSerializer() and here is my code :
self.POST(addUserURL, parameters: dictionary, progress: nil, success: { (task, responseObject) -> Void in
print(responseObject)
}) { (task, error) -> Void in
}
Also inside AFNetworking block its not allowed to handle try and catch for NSJSONSerializtion which can be a possible solution but it doesn't work.
Use NSJSONSerialization for that as shown in below code :
do {
let jsonObject = try NSJSONSerialization.JSONObjectWithData(responseObject, options: .AllowFragments) as! NSDictionary
// use jsonObject here
} catch {
print("json error: \(error)")
}
As response that you get from the server doesn't have top level object that is either Array or Dictionary you have to specify custom reading options in that should be used by AFNetworking.
In order to do that you have to set responseSerializer property on an instance of AFURLSessionManager class. You can do it as follows:
let sessionManager = OLFURLSessionManager.init() //you probably want to keep session manager as a singleton
sessionManager.responseSerializer = AFJSONResponseSerializer.serializerWithReadingOptions(.AllowFragments)
//you should use that instance of session manager to create you data tasks
After that you should be able to correctly parse response from the server as follows:
I need to retrieve the text from a specific website. However, I only need a few parts of it. How can I accomplish this using swift.
I have found the following in objective-c, but am not sure it provides how to reference it from a specific site:
NSString *webString = [webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.innerText"];
NSScanner *stringScanner = [NSScanner scannerWithString:webString];
NSString *content = [[NSString alloc] init];
while ([stringScanner isAtEnd] == NO) {
[stringScanner scanUpToString:#"Start of the text you want" intoString:null];
[stringScanner scanUpToString:#"End of the text you want" intoString:&content];
}`
I have put an example of what I mean below:
Again, I would like to accomplish this using Swift.
If your HTML was easily targetable with identifiers or class names, I would suggest using a library such as Kanna. But I've had a look at your page and the text you need is lost amidst an ocean of divs...
So I've quickly hacked a way to get your text with componentsSeparatedByString: I'm cutting the HTML in blocks until I get to the part we're interested in.
Note that it's far from being the most efficient way: instead of using componentsSeparatedByString you should come with a way of identifying the HTML block you want and search for it with NSScanner.
That being said, here's my example of a working hack, tested in a Playground:
enum CustomErrors : String, ErrorType {
case InvalidURL = "Invalid URL"
}
do {
let str = "http://www.golfwrx.com/328370/mizuno-to-offer-custom-grips-at-no-additional-charge/"
guard let url = NSURL(string: str) else { throw CustomErrors.InvalidURL }
let html = try String(contentsOfURL: url)
let separator1 = "<div class='mailmunch-forms-before-post' style='display: none !important;'></div><p>"
let temp = html.componentsSeparatedByString(separator1)
let separator2 = "</p>\n<p>"
let temp2 = temp[1].componentsSeparatedByString(separator2)
let separator3 = "</p><div class='mailmunch-forms-in-post-middle'"
let separated = temp2[1].componentsSeparatedByString(separator3)
let result = separated[0]
print(result)
} catch {
print(error)
}
Note: my example is in Swift 2 (Xcode 7).
Sorry about the specifics, I'm an Objective-C guy. but, here is an example of how to use NString to get the contents of a websites HTML
NSString *url = #"http://www.example.com"; // Your URL
NSURL *urlRequest = [NSURL URLWithString:url]; // Make a request with your URL
NSError *err = nil; // Error handler
NSString *html = [NSString stringWithContentsOfURL:urlRequest encoding:NSUTF8StringEncoding error:&err]; // Try to get the HTML in the string
if(err)
{
//Do something as it didn't work! Maybe a connection problem
}
else
{
// Use NScanner on html string
}
http://nshipster.com/nsscanner/ is a good place to learn about NScanner for swift
EDIT: Here is the above translated to swift
var err: NSError? // Error handler
let url: NSURL = NSURL(string: "http://www.example.com") // NSURL, put your website URL in here
let string = NSString(contentsOfURL: url, encoding: NSUTF8StringEncoding, error: &err) // String will now hold your HTML
// Now use NScanner (See Link) to parse the HTML output
My swift is rusty. but this might help you. This is roughly translated but outlines exactly what you need
I've been getting the following error when using the GET method to retrieve a file from a server:
Error: Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (Invalid value around character 0.) UserInfo=0x16e81ed0 {NSDebugDescription=Invalid value around character 0.}
I've tried a number of different things and I believe it could be something to do with the JSON format on the file that I'm trying to get.
Here is the code I've been using:
_username = #"JonDoe";
NSDictionary *parameters = #{ #"username" : _username};
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"text/plain"];
[manager GET:#"http://.........."
parameters:parameters
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
My POST method works fine. I just can't seem to fix this issue with the GET. Any ideas? Thank you.
Judging by the discussion in the comments it appears that your GET request is successful (response code 200), but the response body is not valid JSON (nor a JSON fragment) as you have requested by your use of AFJSONResponseSerializer. A basic AFHTTPResponseSerializer can be used for responses that are not JSON.
I am pretty sure that you have a valid response from server but your response is not a valid format in JSON, probably because you have carachters in front of first { .
Please try this: Put the same URL address manually in your browser and you will see the culprit in the response. Hope it helped.
Hey guys this is what I found to be my issue: I was calling Alamofire via a function to Authenticate Users: I used the function "Login User" With the parameters that would be called from the "body"(email: String, password: String) That would be passed
my errr was exactly:
optional(alamofire.aferror.responseserializationfailed(alamofire.aferror.responseserializationfailurereason.jsonserializationfailed(error domain=nscocoaerrordomain code=3840 "invalid value around character 0." userinfo={nsdebugdescription=invalid value around character 0
character 0 is the key here: meaning the the call for the "email" was not matching the parameters: See the code below
func loginUser(email: String, password: String, completed: #escaping downloadComplete) {
let lowerCasedEmail = email.lowercased()
let header = [
"Content-Type" : "application/json; charset=utf-8"
]
let body: [String: Any] = [
"email": lowerCasedEmail,
"password": password
]
Alamofire.request(LOGIN_USER, method: .post, parameters: body, encoding: JSONEncoding.default, headers: header).responseJSON { (response) in
if response.result.error == nil {
if let data = response.result.value as? Dictionary<String, AnyObject> {
if let email = data["user"] as? String {
self.userEmail = email
print(self.userEmail)
}
if let token = data["token"] as? String {
self.token_Key = token
print(self.token_Key)
}
"email" in function parameters must match the let "email" when parsing then it will work..I no longer got the error...And character 0 was the "email" in the "body" parameter for the Alamofire request:
Hope this helps
I want to create a json string to save in NSUserDefaults and then get it back from it.
I've already added RestKit to my project, to send and receive objects from the server.
However, now i want to flatten and save the data.
How do i use restkit to get a JSON string of my object?
I needed the same functionality (in my case to send he JSON as a multipart attribute), so after a while searching, I get the solution.
You can get the JSON data (and JSON string) using RestKit with that code, you have to pass the object you want to convert, and the mapping you want to use to convert.
RKRequestDescriptor *descriptorObject = ...
Custom *object = ...
NSDictionary *parametersForObject = [RKObjectParameterization parametersWithObject:object requestDescriptor:descriptorObject error:nil];
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parametersForObject
options:NSJSONWritingPrettyPrinted //Pass 0 if you don't care about the readability of the generated string
error:&error];
NSString *jsonString;
if (! jsonData) {
NSLog(#"Got an error: %#", error);
}
else {
jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
I have not find this documented, I just find it browsing the code, I am not sure if it is a public API or a private one. At least, it works for RestKit 0.20
You generally don't. RestKit serialises to JSON only as part of a network communication. In this case you're converting from an internal to external data format. In your case you want an internal data format stored for a while. In this case it's easier to just use NSJSONSerialization. To do this you do need to create a dictionary / array and then use dataWithJSONObject:options:error:.
Technically, to do what you ask you would use RKMappingOperation. This is done using the initWithSourceObject:destinationObject:mapping:, where the source object is the dictionary created from the JSON (JSONObjectWithData), the destination object is a new instance of the object targeted by the mapping and the mapping is your mapping to use.
I have piece of good working code that downloads and parses JSON from server and returns result in +JSONRequestOperationWithRequest:success:failure: of AFJSONRequestOperation. success (and also failure)part of method takes block as an argument with id JSON argument in it. If I understand right - this object is for representation of JSON file or it's content. I need to have a possibility to send this JSON file (or it's text representation in every other text format) to email, using MFMailComposeViewController. So, two questions:
how can I get this JSON content from this file?
do I need register .json filetype to have possibility to send it using MFMailComposeViewController?
how can I get this JSON content from this file?
You can get the JSON data response (before it's converted to Foundation objects by NSJSONSerialization) from
operation.responseString (as NSString), or
operation.responseData (as NSData).
You'll want the latter if you're going to attach it to an e-mail.
do I need register .json filetype to have possibility to send it using
MFMailComposeViewController?
You need to call [MFMailComposeViewController -addAttachmentData:mimeType:fileName:]. You can get the mime-type from the operation.response.allHeaderFields NSDictionary. You can also use the official standard, application/json, or text/json, which is commonly used as well.
The response in the succes if not JSON but the object representation of the JSON. Most likely a NSArray or NSDictionary.
What you need to do is either use a normal HTTP request and send that string to the MFMailComposeViewController or change the JSON object back into a JSON string:
NSError *error = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:JSON options:0 error:&error];
NSString *jsonString = nil;
if (jsonData) {
jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
} else {
NSLog(#"Error creating JSON: %#", error);
}
Then you can pass the jsonString in your MFMailComposeViewController.