I'm trying to handle a JSON response using Alamofire from an Alamofire request:
Alamofire.request(.POST, dbURL, parameters: ["username": username, "password": password]) .responseJSON { response in ... }
I'm reading the response with
let JSONResponse = response.result.value!
The value of this returns
({ keyOne = 2; keyTwo = 4; keyThree = 2; keyFour = 6;})
And to get data from this,
JSONResponse.valueForKey("exampleKey")
The problem I get is that this doesn't return simple data, it returns this (the responses are all numbers, but I can't use integerForKey because of obvious reasons):
(2)
(4)
(2)
(6)
How can I get, read and/or save the data from this function without the brackets?
I tried brute force-removing the brackets using stringByReplacingOccurencesOfString() but this is ugly and doesn't work in the first place.
If your json is this { "keyOne":2, "keyTwo":4, "keyThree":2, "keyFour":6 }
then this code should return the proper int values for you.
if let jsonURL = NSBundle.mainBundle().URLForResource("sample", withExtension: "json")
{
Alamofire.request(.GET, jsonURL, parameters:nil) .responseJSON {
response in
if let JSONResponse = response.result.value as? [String:Int]
{
print(JSONResponse)
if let val = JSONResponse["keyOne"] {
print ("val = \(val)")
}
}
}
}
Related
I am trying to upload (post) a JSON string using Alamofire and I'm getting an error that leads me to believe there is some issue in the dictionary encoding.
The array I am encoding is an array of objects, all of type String. It looks like this:
class SavedDeliveries: Codable { //not sure if this is the issue (I use this to store default values locally)
var fullName = ""
var address = ""
var city = ""
var zip = ""
var phone = ""
var orders = ""
var ordersListed = ""
var pickup = ""
}
The code including the Alamofire call looks like this:
func postData() {
let headers: HTTPHeaders = [
"Content-Type": "application/json",
"X-Master-Key": "xxx", //API Key
"X-Bin-Name": "deliverydata"]
let jsonEncoder = JSONEncoder()
let jsonData = try! jsonEncoder.encode(deliveryList)
let json = String(data: jsonData, encoding: String.Encoding.utf8)
print(json!) // printing the JSON and it is correct when validated.
AF.request("https://api.jsonbin.io/v3/b", method: .post, parameters: json, encoding: JSONEncoding.default, headers: headers).responseString { (response) in
switch response.result {
case .success:
print("was successful")
case let .failure(error):
print(error)
}
}
}
I expect it to upload the JSON file but I'm getting an error message that says this:
Cannot convert value of type 'String?' to expected argument type 'Parameters?' (aka 'Optional<Dictionary<String, Any>>')
Not sure if the AF call parameter is expecting a certain kind of dictionary key:value format. If this is not the right call format for uploading JSON, what do I need to change?
Thanks for any help. I'm not a full-time Swift developer but manage an app that is usually within my capabilities. This one has me stumped.
I guess I don't understand much about HTTP requests or Alamofire, but I was able to solve this issue with the following mods to my code (without Alamofire, which seems like overkill in this case).
func postData() {
// Prepare URL
let url = URL(string: "https://api.jsonbin.io/v3/b")
guard let requestUrl = url else { fatalError() }
// Prepare URL Request Object
var request = URLRequest(url: requestUrl)
request.httpMethod = "POST"
// Set HTTP Request Body
let header: HTTPHeaders = [
"Content-Type": "application/json",
"X-Master-Key": "xxx",
"X-Bin-Name": "deliverydata"
]
request.headers = header
let jsonEncoder = JSONEncoder()
let jsonData = try! jsonEncoder.encode(deliveryList)
let json = String(data: jsonData, encoding: String.Encoding.utf8)
request.httpBody = json!.data(using: String.Encoding.utf8)
// Perform HTTP Request
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
// Check for Error
if let error = error {
print("Error took place \(error)")
return
}
// Convert HTTP Response Data to a String
if let data = data, let dataString = String(data: data, encoding: .utf8) {
print("Response data string:\n \(dataString)")
}
}
task.resume()
}
To make such a request using Alamofire, I'd recommend:
let headers: HTTPHeaders = [
"Content-Type": "application/json",
"X-Master-Key": "xxx", //API Key
"X-Bin-Name": "deliverydata"]
AF.request("https://api.jsonbin.io/v3/b",
method: .post,
parameters: deliveryList,
headers: headers).responseString { response in
switch response.result {
case .success:
print("was successful")
case let .failure(error):
print(error)
}
}
Even better, create a Decodable response type and use responseDecodable to parse it.
I would also suggest not using empty strings as your default values, that can easily lead to sending bad or invalid data to the backend.
Here i have using swiftyJson pod library for response data. normal json response data i could able to get data but for complex i could not make it.
here is my code to get data from response:
private func makeHTTPGetRequest(path: String, onCompletion: #escaping ServiceResponse) {
let user = "David****"
let password = "**************"
let loginString = "\(user):\(password)"
guard let loginData = loginString.data(using: String.Encoding.utf8) else {
return
}
let base64LoginString = loginData.base64EncodedString()
print("base 64 login :\(base64LoginString)")
let headers = ["Authorization": "Basic \(base64LoginString)"]
// using URL and request getting a json
let request = URLRequest(url: NSURL(string: path)! as URL)
let config = URLSessionConfiguration.default
config.httpAdditionalHeaders = headers
let session = URLSession.init(configuration: config)
session.dataTask(with: request) { (data:Data?, response: URLResponse?, error:Error?) in
if let jsonData = data { // if data has a data and success
do {
let json: JSON = try JSON(data: jsonData)
onCompletion(json,nil)
print("json data:\(json)")
}catch {// error
onCompletion(JSON(),error)
}
} else { // if the data is nil
onCompletion(JSON(),error)
}
}.resume()
}
Used this function in viewController.swift
func addDummyData() {
// Call API
RestApiManager.sharedInstance.getRandomUser { (json:JSON) in
// return json from API
if let results = json["results"].array { // get results data from json
print("results:\(results)")
for entry in results { // save data to items.
self.items.append(UserObject(json: entry))
}
print("array= \(self.items)")
DispatchQueue.main.async { // back to the main que and reload table
self.tableView.reloadData()
}
}
}
}
Model class:
import SwiftyJSON
class UserObject {
// var pictureURL: String!
var username: String!
required init(json: JSON) {
// pictureURL = json["picture"]["medium"].stringValue
username = json["WorkOrder"].stringValue
}
}
Here is my json response:
{
"d": {
"results": [
{
"__metadata": {
"id": "http://*******:****/sap/opu/odata/sap/ZPRJ_PM_APPS_IH_SRV/WorkOrderF4Set('000000504780')",
"type": "ZPRJ_PM_APPS_IH_SRV.WorkOrderF4"
},
"WorkOrder": "000000504780",
"Description": "General Maintenance testing"
},
}
}
From json response i'm trying to get WorkOrder and Description
Any help much appreciated pls....
Please read the JSON carefully. The outermost object is a dictionary with a key d.
To get the results array you have to write
if let results = json["d"]["results"].array { ...
And you don't need a class and never declare properties as IUO which are initialized in an init method
struct User {
let workOrder: String
let description: String
init(json: JSON) {
workOrder = json["WorkOrder"].stringValue
description = json["Description"].stringValue
}
}
Side note: Since Swift 4 SwiftyJSON has become obsolete in favor of Codable. It's built-in and much more efficient.
I have a very simple Swift code to retrieve JSON data. But somehow it doesn't work properly.
Alamofire.request("*URL*").validate().responseJSON { response in
print(response.result.value)
if response.result.isSuccess {
if let userList:[[String:Any]] = response.result.value as? [[String:Any]] {
for user:[String:Any] in userList {
if let userName = user["name"] as? String {
self._myList.append(User(name: userName, value: true))
}
}
}
self.tableView.reloadData()
} else {
print(response.result.error)
}
}
During the execution, I get this error message in the console :
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.})))
The print after calling Alamofire.request is showing "nil" in the console.
What I don't understand is it's working if I use .responseString instead of .responseJSON (but it shows only a String). I really need to use .responseJSON as I need to parse the result.
My JSON that appears on the web browser is very simple as well :
[{"name":"MrX","value":"0"}]
Any idea ?
Mika.
use this
import Alamofire
import SwiftyJSON
let baseURL: String = "http://baseURL.com"
Alamofire.request(baseURL)
.responseJSON { response in
guard response.result.error == nil else {
// got an error in getting the data, need to handle it
print("error calling GET")
print(response.result.error!)
return
}
if let value = response.result.value {
let json = JSON(value) // JSON comes from SwiftyJSON
print(json) // to see the JSON response
let userName = json["name"].array // .array comes from SwiftyJSON
for items in userName! {
self._myList.append(User(name: items, value: true))
}
DispatchQueue.main.async {
self.tableView?.reloadData()
}
}
}
and take the .validate() out, if you take that out you will see more detailed error description. Hope that helps.
I read answers in SO and checked the official Alamofire documentation but most of these answers increase the confusion whether the JSON data gets added to the URL parameters or the body.
The HTTP request must contain a parameter key, which is equal to my API key to access the API and the JSON containing the image data and some data related to the API.
the URL with the request parameter looks like this:
https://vision.googleapis.com/v1/images:annotate?key=My_API_Key
and the JSON structure is at This link.
My Swift code looks like this.
import SwiftyJSON
import Alamofire
// all imports are done
func requestAPI(body:JSON) -> JSON {
let APIKey:String = "My_API_KEY"
let header = ["Content-Type":"application/json"]
let url:String = "https://vision.googleapis.com/v1/images:annotate"
let parameters = ["key":APIKey]
var response = Alamofire.request(.POST,url,headers:header,parameters:parameters)
response.validate().responseJSON { response in
switch response.result {
case .Success:
if let value = response.result.value {
let json = JSON(value)
print("JSON: \(json)")
print(response.request)
}
case .Failure(let error):
print(error)
}
}
return body //dummy return
}
I did go through the Alamofire documentation.
From the
POST Request With URL-Encoded Parameters
section of the documentation,
let parameters = [
"foo": "bar",
"baz": ["a", 1],
"qux": [
"x": 1,
"y": 2,
"z": 3
]
]
Alamofire.request(.POST, "https://httpbin.org/post", parameters: parameters)
// HTTP body: foo=bar&baz[]=a&baz[]=1&qux[x]=1&qux[y]=2&qux[z]=3
My understanding of this is that the JSON passed as the parameters argument is added as the parameters to the URL (similar to the key:My_API_Key part of my request) for the HTTp POST request. and using the .JSON as an encoding option adds the parameters argument as a JSON body for the request. How do I do both (A parameter key that is to be URL encoded and the JSON data that is to be added to the HTTP body)? the request method of Alamofire seems to be doing either of the 2 using the same argument.
I tried creating a NSURLMutableRequest and adding the body. but while accessing the rawValue of a SwiftyJSON JSON object, I get the following error.
error: call can throw, but it is not marked with 'try' and the error is not handled
if let bodyData:NSData = body.rawData(){
this is the code.
func requestAPI(body:JSON) -> JSON {
let APIKey:String = "My_API_Key"
let header = ["Content-Type":"application/json"]
let url = NSURL(string:"https://vision.googleapis.com/v1/images:annotate")
let parameters = ["key":APIKey]
var request = NSMutableURLRequest(URL:url!)
request.HTTPMethod = "POST"
if let bodyData:NSData = body.rawData(){
request.HTTPBody = bodyData
}
let encoding = Alamofire.ParameterEncoding.URL
(request, _) = encoding.encode(request, parameters: parameters) // Parameters are added here
var response = Alamofire.request(.POST,url!,headers:header,parameters:parameters)
response.validate().responseJSON { response in
switch response.result {
case .Success:
if let value = response.result.value {
let json = JSON(value)
print("JSON: \(json)")
//return json
print(response.request)
}
case .Failure(let error):
print(error)
}
}
return body //dummy return
}
Where and how do I set both the HTTP body of the request to JsonData and encode the URL with the parameters?
I am trying to access nested JSON results using swiftyJSON and Alamofire. My print value is nill and I believe I am not doing this correctly. What should my parameters be? I am trying to get the quote value located at http://quotes.rest/qod.json
func getAPI() {
Alamofire.request(.GET, "http://quotes.rest/qod.json", parameters: ["contents": "quotes"])
.responseJSON { response in
if let JSON = response.result.value {
print(JSON["quote"])
}
}
}
In your JSON quotes is an array so if you want to access quote of the first object you should do it by accessing first object:
func getAPI() {
Alamofire.request(.GET, "http://quotes.rest/qod.json", parameters: ["contents": "quotes"])
.responseJSON { response in
if let jsonValue = response.result.value {
let json = JSON(jsonValue)
if let quote = json["contents"]["quotes"][0]["quote"].string{
print(quote)
}
}
}
}
If the syntax of the json isn't correct, since it is fully printed anyway you should notice what's wrong.
func getAPI() {
Alamofire.request(.GET, "http://quotes.rest/qod.json", parameters: ["contents": "quotes"])
// JSON response
.responseJSON { response in switch response.result {
case .Failure(let error):
// got an error in getting the data, need to handle it
print("error calling GET, json response type :")
// print alamofire error code
let statusCode = error.code
print("error code json : \(statusCode)")
// print json response from server
if let data = response.data {
print("Response data: \(NSString(data: data, encoding: NSUTF8StringEncoding)!)")
}
// print http status code plus error string
print(NSHTTPURLResponse.localizedStringForStatusCode(statusCode))
if let httpResponse : NSHTTPURLResponse = response.response {
print("HTTP Response statusCode: \(httpResponse.statusCode)")
}
case .Success( _):
let statusCode = (response.response?.statusCode)!
print("status code json : \(statusCode)")
print("there is a response json")
//print(value)
// parse the result as JSON, since that's what the API provides and save datas as new user in coreData
guard let data = response.data else {
print("Error parsing response data")
return
}
let json = JSON(data: data)
// access first element of the array
if let postContent = json["contents"]["quotes"][0]["quote"].string{
// deal with json
}
}
}