I enter the parameter and take data with the MVC project. It pulls the data but prints the result in the responsestring variable in the catch parseerror line. How can I withdraw this data?
parsing error: Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
raw response: Optional("\"/Uploads/GV8ptzoREovS-119.png\"")
#objc func gorselCEK(){
var urlComponent = URLComponents(string: ".../MobilService/KategoriGorsel/")!
urlComponent.queryItems = [
URLQueryItem(name: "id", value: "7")
]
var request = URLRequest(url: urlComponent.url!)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
// print("request failed \(error)")
return
}
do {
if let json = try JSONSerialization.jsonObject(with: data) as? String,
let sifre : String = json {
print("sifre", sifre)
}
} catch let parseError {
print("parsing error: \(parseError)")
let responseString = String(data: data, encoding: .utf8)
print("raw response: \(responseString)")
}
}
task.resume()
}
Please read the error message:
JSON text did not start with array or object and option to allow fragments not set.
So as the object is not a collection type you have to set the option:
if let sifre = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? String {
And the URLRequest is redundant. The content type header is not considered in a GET request anyway.
Related
I'm using a generic function for POST requests in my app. I have the following function:
func PostRequest<In:Codable>(object: In, endpoint: String){
do{
let url = URL(string: "http://localhost:8080/\(endpoint)/")
var request = URLRequest(url: url!)
request.httpMethod = "POST"
request.httpBody = try JSONEncoder().encode(object)
URLSession.shared.dataTask(with: request) {data, response, error in
guard let data = data, error == nil else{
print(error?.localizedDescription ?? "No Data")
return
}
let JSONResponse = try? JSONSerialization.jsonObject(with: data, options: [])
if let JSONResponse = JSONResponse as? [String: Any] {
print(JSONResponse)
}
}.resume()
}catch{
print(error)
}
}
And in this case, the object is the following struct:
struct MarkAsDelivered: Codable{
let whoCollected: String
let deliveryID: Int
}
When I print the result of JSONEncoder().encode(object) as a string, it returns the following, as would be expected:
{
"whoCollected":"TESTNAME",
"deliveryID":140
}
however, when i view this JSON object on my backend, it returns it as the following:
{
"{\"whoCollected\":\"TESTNAME\",\"deliveryID\":140}" : ""
}
From what I can tell, it is using the JSON object as a key.
Does anyone know what has caused this issue. Any assistance would be greatly appreciated.
as #burnsi mentioned in the comments to my question, I was indeed missing the content type. Specifying it fixed my issue:
func PostRequest<In:Codable>(object: In, endpoint: String){
do{
let url = URL(string: "http://localhost:8080/\(endpoint)/")
var request = URLRequest(url: url!)
request.httpMethod = "POST"
//Added content type on line below:
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.httpBody = try JSONEncoder().encode(object)
URLSession.shared.dataTask(with: request) {data, response, error in
guard let data = data, error == nil else{
print(error?.localizedDescription ?? "No Data")
return
}
let JSONResponse = try? JSONSerialization.jsonObject(with: data, options: [])
if let JSONResponse = JSONResponse as? [String: Any] {
print(JSONResponse)
}
}.resume()
}catch{
print(error)
}
}
I make a GET call and receive a json response. I need to use that json response as one parameter for a subsequent POST call.
I’ve tried to:
-parse the data into an object and pass the [object] as parameter
-parse the data into a string and pass the string as parameter
-parse the data as dict and pass the dict as parameter
but it’s not working, I believe it’s a data thing or a secret I’m missing
How do you use a json response as parameter for a subsequent api call?
//MARK: - PIXLAB facedetect
func facedetectGET(uploadedUrl: String) {
var urlComponents = URLComponents(string: "https://api.pixlab.io/facedetect")
urlComponents?.queryItems = [
URLQueryItem(name: "img", value: uploadedUrl),
URLQueryItem(name: "key", value: Constants.pixlabAPIkey),
]
let url = urlComponents?.url
if let url = url {
// Create URL Request
var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 10.0)
request.httpMethod = "GET"
request.addValue("Bearer \(Constants.pixlabAPIkey)", forHTTPHeaderField: "Authorization")
// Get URLSession
let session = URLSession.shared
// Create Data Task
let dataTask = session.dataTask(with: request) { (data, response, error) in
// Check that there isn't an error
if error == nil {
do {
let json = try JSONSerialization.jsonObject(with: data!, options: [])
//make a dict
//let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [String: Any]
print("SUCCESS: image detected")
print(json)
//make json a string utf8 so it can be used as parameter in next call
//let jsonString = String(data: json as! Data, encoding: .utf8)
//let jsonData = json.data(using: .utf8)!
//parse json
//decode the json to an array of faces
let faces: [Face] = try! JSONDecoder().decode([Face].self, from: data!)
let facesString = String(faces)
//use dispatch main sync queue??"bottom": Int,
//mogrify call
mogrify(uploadedUrl: uploadedUrl, cord: faces)
}
catch {
print(error)
}
}
}
// Start the Data Task
dataTask.resume()
}
}
//MOGRIFY CALL
func mogrify(uploadedUrl: String, cord: Any) {
let mogrifyurl = URL(string: "https://api.pixlab.io/mogrify")!
//let param: [Face] = result.faces
let param: [String: Any] = ["img": uploadedUrl, "cord": cord]
var request = URLRequest(url: mogrifyurl)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("Bearer \(Constants.pixlabAPIkey)", forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"
request.httpBody = try! JSONSerialization.data(withJSONObject: param, options: [])
URLSession.shared.dataTask(with: request) { (data, response, error) in
if error != nil {
print(error!)
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!)
print(json)
} catch {
print("error")
}
}.resume()
}
this is how pretty the response looks
enter image description here
and this is how it looks when I pass it as parameter
enter image description here
A POST needs the body as Data. If you're just forwarding the body of the GET to the body of the POST, it would be easiest to leave it as Data.
You could also deserialize the response into an object in your get, and then re-serialize it back into Data in the POST code, but why?
I did lots of white magic, voodoo and lots of praying (aka try and error) and I made it work…
basically decoded the json data, then got an array subdata and encode it back into a data variable as input for the post call
maybe there is an easier and more elegant way but this works....
do {
//decode the json to an array of faces
let cord = try! JSONDecoder().decode(Cord.self, from: data!)
print(cord.faces)
let cordData = try! JSONEncoder().encode(cord.faces)
let coordinates = try JSONSerialization.jsonObject(with: cordData, options: [])
print(coordinates)
//mogrify call
mogrify(uploadedUrl: uploadedUrl, cord: coordinates)
} catch {
print(error)
}
post call
//MOGRIFY CALL
func mogrify(uploadedUrl: String, cord: Any) {
let mogrifyurl = URL(string: "https://api.pixlab.io/mogrify")!
// let param: [Face] = result.faces
let param: [String: Any] = ["img": uploadedUrl, "key": Constants.pixlabAPIkey, "cord": cord]
var request = URLRequest(url: mogrifyurl)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("Bearer \(Constants.pixlabAPIkey)", forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"
request.httpBody = try! JSONSerialization.data(withJSONObject: param, options: [])
URLSession.shared.dataTask(with: request) { (data, response, error) in
if error != nil {
print(error!)
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!)
print("MOGRIFY response")
print(json)
} catch {
print("error")
}
}.resume()
}
I have the parameters which has to be saved to database using post method api.
The property_image_url is ["https://res.cloudinary.com/dtwvevtm7/image/upload/v1617203478/j8mqat97ssrctsnzpjlc.jpg","https://res.cloudinary.com/dtwvevtm7/image/upload/v1617203479/j1rhedrsnrud7fkva1bl.jpg"]
The parameters are as follows:
["price": "dry", "listing_description": "Dghb", "listing_type": "Residential", "property_image_url": "[\"https://res.cloudinary.com/dtwvevtm7/image/upload/v1617203478/j8mqat97ssrctsnzpjlc.jpg\",\"https://res.cloudinary.com/dtwvevtm7/image/upload/v1617203479/j1rhedrsnrud7fkva1bl.jpg\"]", "address": "chennai ", "listing_use": "SubLease", "property_video_url": "", "title": "huffy"]
Here when the value is property_image_url,it is showing unnescessary white space and escape character.
The code used to post the data via API is given below:
let url = URL(string: url)! //change the url
//create the session object
let session = URLSession.shared
//now create the URLRequest object using the url object
var request = URLRequest(url: url)
request.httpMethod = "POST" //set http method as POST
do {
request.httpBody = try JSONSerialization.data(withJSONObject: parameter, options: .fragmentsAllowed) // pass dictionary to nsdata object and set it as request body
} catch let error {
print(error.localizedDescription)
}
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.addValue(self.usertoken, forHTTPHeaderField: "x-token")
//create dataTask using the session object to send data to the server
let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
print("data is",data)
guard error == nil else {
return
}
guard let data = data else {
return
}
do {
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
print("new listing json is",json)
DispatchQueue.main.async {
self.navigationController?.view.makeToast("Listing Updated successfully", duration: 3.0, position: .bottom)
let vc = self.storyboard?.instantiateViewController(withIdentifier: "Home") as! Home
self.navigationController?.pushViewController(vc, animated: true)
}
}
} catch let error {
print(error.localizedDescription)
}
})
task.resume()
}
This post method is throwing error saying
["errors": <__NSArrayM 0x283120810>(
Title Required,
Listing Type Required,
Listing Use Required
)
]
Here,in the parameter all these values are filled but still it is showing like that these values are empty.
Let me know what is the issue in passing the parameter and calling the API.
I am building an app using Swift 3.0 for study purpose.
One of the functions is to fetch and save data from(to) SQL Server database tables. One of the columns is to store IMAGE(photo) in table: data type in table is Image (system.Byte[]) in SQL Server.
I can get the photo column through web api and show it in Image component like this:
let encodedImageData = My web api url
let imageData = NSData(base64EncodedString: encodedImageData options: .allZeros)
let image = UIImage(data: imageData)
let imageView.image = image
I had problem to save the Image to the database through web api (can save other columns, but had problem with Image column).
I tried this:
let data = UIImagePNGRepresentation(image) as NSData?
but failed.
my web api and invoke as below:
func post(parameters : Dictionary<String, String>, urlString : String) {
var request = URLRequest(url: URL(string: urlString)!)
let session = URLSession.shared
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.httpBody = try! JSONSerialization.data(withJSONObject: parameters)
let task = session.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print("error: \(error)")
return
}
do {
if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
let success = json["success"] as? Int // Okay, the `json` is here, let's get the value for 'success' out of it
print("Success: \(success)")
} else {
let jsonStr = String(data: data, encoding: .utf8) // No error thrown, but not dictionary
print("Error could not parse JSON: \(jsonStr)")
}
} catch let parseError {
print(parseError) // Log the error thrown by `JSONObjectWithData`
let jsonStr = String(data: data, encoding: .utf8)
print("Error could not parse JSON: '\(jsonStr)'")
}
}
task.resume()
}
#IBAction func insert(){
let imageData = UIImagePNGRepresentation(myimageview.image!) as NSData?
post(parameters: ["Name": nametxt.text!,"Address": addresstxt.text!,"photoname": photonametxt.text!,"photo": String(describing: imageData),"url": urltxt.text! ], urlString: "http://XXXXXXX/api/myfavorites")
}
Can someone help me have a look at image save method to database table in Swift?
I think you are using the wrong data structure for your image. Instead of using NSData and String(describing:) (which definitely does not do what you want), you should directly use a base64 encoded string, like the following code:
#IBAction func insert(){
let imageBase64String = UIImagePNGRepresentation(myimageview.image!)?.base64EncodedString()
post(parameters: ["Name": nametxt.text!,"Address": addresstxt.text!,"photoname": photonametxt.text!,"photo": imageBase64String,"url": urltxt.text! ], urlString: "http://XXXXXXX/api/myfavorites")
}
When the parameter (params) values are incorrect, it still login to another view. In the console, both response body and response header return values when printed. Where have I gone wrong?
func login() {
let request = NSMutableURLRequest(URL: NSURL(string: "http://someurl/verify/")!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
let params =
[
"username":username.text!,
"password":password.text!,
"deviceid":"r49rvnjff",
"method":"method",
"payload":"payload"
]
as Dictionary<String,String>
print(params)
do {
request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(params, options: .PrettyPrinted)
}
catch {
print(error)
return
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
if error == nil {}
let json: NSDictionary?
do {
json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableLeaves) as? NSDictionary
}
catch let dataError {
print(dataError)
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: '\(jsonStr)'")
return
}
if let parseJSON = json {
let authenticated = parseJSON["authenticated"] as? String
print("authenticated:\(authenticated)")
if authenticated != "False" {
dispatch_async(dispatch_get_main_queue()) {
self.performSegueWithIdentifier("segue", sender: self)
}
}
}
else {
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: \(jsonStr)")
}
})
task.resume()
}
Thanks in advance!
What does your invalid response look like? might it be that its returning "false" and not "False" (which is what you are checking for), in any case I would recommend verifying your response from the server so that you can have the authenticated parameter be a boolean, so you can unwrap your optional as so:
if let authenticated = json["authenticated"] as? Bool {
if (authenticated)
{
// ...
}
}
Also, I noticed that your else block will never be hit because your json property is unwrapped. Your serialization is successful so json is not nil, hence the if let parseJSON = json will always work.
I would suggest the following approach:
if let authenticated = json["authenticated"] as? Bool
{
if (authenticated)
{
dispatch_async(dispatch_get_main_queue()) {
self.performSegueWithIdentifier("segue", sender: self)
}
}
else
{
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: \(jsonStr)")
}
}
Good luck!