How to connect http server using Swift and Alamofire - json

Hi I new at swift and I got problem with server connection. I am trying to make request using a method post to login to server using username and password. How I can connect to the server and authentificate?
error messsage:
["id": <null>, "error": {
code = "-32700";
message = "Parse error";
}, "jsonrpc": 2.0]
Code:
class ViewController: UIViewController {
override func viewDidLoad() {
var userName = "root"
var password = "admin01"
// http://192.168.1.1/ubus
//var LOGIN_TOKEN = 0000000000000000
let url: String = "http://192.168.1.1/ubus"
let param: [String: Any] = ["username": "admin", "password": "admin01", "token": "0000000000000000"]
Alamofire.request(url, method: .post, parameters: param,
encoding: JSONEncoding.default)
.responseJSON { response in
guard response.result.error == nil else {
// got an error in getting the data, need to handle it
print("error calling post")
print(response.result.error!)
return
}
// make sure we got some JSON since that's what we expect
guard let json = response.result.value as? [String: Any] else {
print("didn't get todo object as JSON from API")
print("Error: \(response.result.error)")
return
}
print(json)
}
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
Json at server which I need to get:
{"jsonrpc":"2.0","id":1,"result":[0,{"ubus_rpc_session":"07e111d317f7c701dc4dfde1b0d4862d","timeout":300,"expires":300,"acls":{"access-group":{"superuser":["read","write"],"unauthenticated":["read"]},"ubus":{"*":["*"],"session":["access","login"]},"uci":{"*":["read","write"]}},"data":{"username":"root"}}]}
Request should look like:
"{ \"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"call\", \"params\": [ \"00000000000000000000000000000000\", \"session\", \"login\", { \"username\": \"root\", \"password\": \"admin01\" } ] }"

Try to use this code:
Alamofire.request(url, method: .post, parameters: parameters).responseJSON { response in
if(response.result.isFailure){
print("no data!");
}else{
print("received data!");
// make sure we got some JSON since that's what we expect
guard let json = response.result.value as? [String: Any] else {
print("didn't get todo object as JSON from API")
print("Error: \(response.result.error)")
return
}
print(json)
}
}

Related

how to pass value to empty json object in swift using Alamofire

I have a api whose body has one dictionary key that is empty value.
Eg. {
"customer_name": "name"
"request_data": {}
}
I am using alamofire for this post request.
I am not able to understand what should i pass as a value to this key when calling the api.
My code:
Network Service -
func KYCRequestWithTemplate(parameters: KYCRequest_WithTemplateModel, completionHandler: #escaping Handler) {
let authorizationValue = "Basic authorization value"
let headers: HTTPHeaders = [
"content-type": "application/json",
"authorization": "\(authorizationValue)"
]
AF.request("url", method: .post, parameters: parameters, encoder: JSONParameterEncoder.default, headers: headers).response { response in
switch response.result {
case .success(let data):
do {
let json = try JSONDecoder().decode(KYCRequest_WithTemplate.self, from: data!)
print(json)
if response.response?.statusCode == 200 || response.response?.statusCode == 201 {
completionHandler(.success(json))
}else {
completionHandler(.failure(.custom(message: "Please check your network connectivity")))
}
}catch {
print(error.localizedDescription)
completionHandler(.failure(.custom(message: "Please try again")))
}
case .failure(let error):
print(error.localizedDescription)
completionHandler(.failure(.custom(message: "Please try again")))
}
}
}
Model :
//for post method
struct KYCRequest_WithTemplateModel: Encodable {
let customer_identifier: String
let customer_name: String
let reference_id: String
let template_name: String
let notify_customer: Bool
let request_details: RequestDetails
let transaction_id: String
let generate_access_token: Bool
}
struct RequestDetails: Codable {
}
Calling API:
I am getting error here. Please help me understand what shall I pass here as a value
let kycTemplateData = KYCRequest_WithTemplateModel(customer_identifier: "\(mobileNo)", customer_name: "\(userName)", reference_id: "id", template_name: "template_name", notify_customer: true, request_details: "**I am getting error here. Please help me understand what shall I pass here as a value**", transaction_id: "id", generate_access_token: true)

-- function-call with completion URLRequest - JSON

i did read a lot about functions with completion-handler, but now i have a problem how to call this function (downloadJSON) in the correct way. Which parameters do i have to give in the function and handle the result-data (json) in my own class, where the function was called.
This is the code from David Tran. Hi makes wonderful tutorials, but in the code there is no call of this function.
let request: URLRequest
lazy var configuration: URLSessionConfiguration = URLSessionConfiguration.default
lazy var session: URLSession = URLSession(configuration: self.configuration)
typealias JSONHandler = (JSON?, HTTPURLResponse?, Error?) -> Void
func downloadJSON(completion: #escaping JSONHandler)
{
let dataTask = session.dataTask(with: self.request) { (data, response, error) in
// OFF THE MAIN THREAD
// Error: missing http response
guard let httpResponse = response as? HTTPURLResponse else {
let userInfo = [NSLocalizedDescriptionKey : NSLocalizedString("Missing HTTP Response", comment: "")]
let error = NSError(domain: DANetworkingErrorDomain, code: MissingHTTPResponseError, userInfo: userInfo)
completion(nil, nil, error as Error)
return
}
if data == nil {
if let error = error {
completion(nil, httpResponse, error)
}
} else {
switch httpResponse.statusCode {
case 200:
// OK parse JSON into Foundation objects (array, dictionary..)
do {
let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [String : Any]
completion(json, httpResponse, nil)
} catch let error as NSError {
completion(nil, httpResponse, error)
}
default:
print("Received HTTP response code: \(httpResponse.statusCode) - was not handled in NetworkProcessing.swift")
}
}
}
dataTask.resume()
}
Let Xcode help you. Type downlo and press return. Xcode completes the function
Press return again and you get the parameters
You have to replace the placeholders with parameter names for example
downloadJSON { (json, response, error) in
if let error = error {
print(error)
} else if let json = json {
print(json)
}
}
Note:
There is a fatal type mismatch error in your code: The result of the JSONSerialization line is [String:Any] but the first parameter of the completion handler is JSON

How should I go about parsing a JSON response from an API with Alamofire and SwiftyJSON?

I am trying to parse a JSON from an API using Alamofire and SwiftyJSON, but am having trouble trying to access the information in the JSON. I need to simply parse the JSON for an item called "ask_price": and also "time_coinapi" but I am not sure how I manage the response, or if I have to use a different method. here is what I have at the moment:
class CoinAPIManager {
var prices: [String] = []
var times: [String] = []
static let shared = CoinAPIManager()
func getReq() {
let headers: HTTPHeaders = [
"X-CoinAPI-Key": "Key"
]
Alamofire.request("https://rest.coinapi.io/v1/quotes/BITSTAMP_SPOT_BTC_USD/history?time_start=2018-08-21T00:00:00&time_end=2018-08-22T00:00:00&limit=100", headers: headers).responseJSON { response in
debugPrint(response)
if let data = try? String(contentsOf: response) {
let json = JSON(parseJSON: data)
parse(json: json)
}
}
func parse(json: JSON) {
for result in json[].arrayValue {
let price = result["ask_price"].stringValue
}
}
}
}
and I have also tried this:
func getReq() {
let headers: HTTPHeaders = [
"X-CoinAPI-Key": "Key"
]
Alamofire.request("https://rest.coinapi.io/v1/quotes/BITSTAMP_SPOT_BTC_USD/history?time_start=2018-08-21T00:00:00&time_end=2018-08-22T00:00:00&limit=100", headers: headers).responseJSON { response in
debugPrint(response)
switch response.result {
case .failure(let error):
// Do whatever here
return
case .success(let data):
// First make sure you got back a dictionary if that's what you expect
guard let json = data as? [String : AnyObject] else {
print("Failed to get expected response from webserver.")
return
}
// Then make sure you get the actual key/value types you expect
guard var price = json["ask_price"] as? Double else {
print("Failed to get data from webserver")
return
}
}
What am I doing wrong? this is how the JSON looks:
[
{
"symbol_id": "BITSTAMP_SPOT_BTC_USD",
"time_exchange": "2013-09-28T22:40:50.0000000Z",
"time_coinapi": "2017-03-18T22:42:21.3763342Z",
"ask_price": 770.000000000,
"ask_size": 3252,
"bid_price": 760,
"bid_size": 124
},
{
"symbol_id": "BITSTAMP_SPOT_BTC_USD",
"time_exchange": "2013-09-28T22:40:50.0000000",
"time_coinapi": "2017-03-18T22:42:21.3763342",
"ask_price": 770.000000000,
"ask_size": 3252,
"bid_price": 760,
"bid_size": 124
}
]
previous question deleted and reposted due to large mistake
you need to change your response to SwiftyJSON object like this
Alamofire.request("https://rest.coinapi.io/v1/quotes/BITSTAMP_SPOT_BTC_USD/history?time_start=2018-08-21T00:00:00&time_end=2018-08-22T00:00:00&limit=100", headers: headers).responseJSON { response in
debugPrint(response)
switch response.result {
case .failure(let error):
// Do whatever here
return
case .success:
// First make sure you got back a dictionary if that's what you expect
let responseJSON = JSON(response.result.value!)
if responseJSON.count != 0 {
print(responseJSON)
//do whatever you want with your object json
}
}
}
i suggest in your ApiManager you can use completion blocks to manage asyncronous request, check the next code.
class func getRequestWithoutParams(didSuccess:#escaping (_ message: JSON) -> Void, didFail: #escaping (_ alert:UIAlertController)->Void){
Alamofire.request("http://foo.bar"),method: .post,parameters: parameters,encoding: JSONEncoding.default,headers:nil).responseJSON { response in
switch response.result{
case .success:
let res = JSON(response.result.value!)
didSuccess(res)
break
case .failure(let error):
let alert = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .alert)
let done = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(done)
didFail(alert)
}
}
}
From Swift 4, you should be able to use codable to solve it:
struct YourStructure: Codable {
let symbol_id: String?
let time_exchange: String?
let ask_price: String?
private enum CodingKeys: String, CodingKey {
case symbol_id = "symbol_id"
case time_exchange = "time_exchange"
case ask_price = "ask_price"
}
}
And then parse it with JSONDecoder
let decoder = JSONDecoder()
let parsedData = decoder.decode(YourStructure.self, from: "YourJsonData")

JSON "Invalid value around character 0" though the url works flawless and the JSON is valid

I have this json error that just randomly seems to pop up.
I load json from a domain and parse it to a dictionary. If the error doesn't occur it works flawless. Here is the code:
func retrieveCoinPairData() {
guard !checkIfBaseAndTargetAreEqual() else { return }
if let base = self.currentBase, let target = self.currentTarget {
if let url = URL(string: "https://api.cryptonator.com/api/full/\(base.code)-\(target.code)") {
URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
if let error = error {
print(error.localizedDescription)
}
if let response = response {
print("reponse /api/full", response)
}
do {
if let data = data {
let jsonData = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String: Any]
self.createCoinPairData(with: jsonData)
} else {
self.delegate?.updateInfoLabelContent(content: .noInternetConnection)
}
} catch {
self.delegate?.updateInfoLabelContent(content: .error)
print("catch error", error, data?.description as Any)
self.retrieveCoinPairData()
}
}).resume()
} else {
self.delegate?.updateInfoLabelContent(content: .error)
}
}
}
The server response is the following throwing an 403 error:
reponse /api/full <NSHTTPURLResponse: 0x608000232400> {
URL: https://api.cryptonator.com/api/full/BTC-ETH } {
status code: 403, headers {
Connection = "keep-alive";
"Content-Encoding" = gzip;
"Content-Type" = "text/html";
Date = "Tue, 05 Jun 2018 04:23:37 GMT";
"Keep-Alive" = "timeout=15";
Server = nginx;
"Transfer-Encoding" = Identit
and the URLSession catch error is the following:
catch error Error Domain=NSCocoaErrorDomain Code=3840
"Invalid value around character 0."
UserInfo={NSDebugDescription=Invalid value around character 0.}
Optional("162 bytes")
The error occurs in the try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String: Any] line.
Now anytime this error occurs (and it is completely random), when I check the url in the browser it works perfect.
I checked the json with jsonlint.com and it is valid, there is no top level object that makes the json need fragmentation, though that option seemed to reduce the error in the past.
I know the code 403 error tells me the website blocks access and the code 3840 error tells me there is no content to be parsed. Still I wonder where and why the error occurs.
This is the site used in this example: https://api.cryptonator.com/api/full/btc-eth
Change your lines of code to do this:
if let error = error {
print(error.localizedDescription)
return
}
if let httpResponse = response as HTTPURLResponse {
if httpResponse.statusCode == 200 {
// do your json deserialization after you verify you
// got a 200 / OK from the server
do {
if let data = data {
let jsonData = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String: Any]
self.createCoinPairData(with: jsonData)
} else {
self.delegate?.updateInfoLabelContent(content: .noInternetConnection)
}
} catch {
self.delegate?.updateInfoLabelContent(content: .error)
print("catch error", error, data?.description as Any)
self.retrieveCoinPairData()
}
} else {
print("reponse /api/full", response)
}
}
And what you see there is that you should only attempt JSON deserialization if you know the server sent you a 200/OK response.
There is a redirection on the url which occure sometime. You can see redirecting something like ohio.something sometime you request the url.
When the redirection happen, urlsession get the error code 403.
And also invalide value around 0 occure when json serialisation get html or other code than vald json object.
Try to remove the redirection from the webservice.
Your request should be like this, this is just demo version you have to modify it accordingly as per your requirement,
if let url = URL(string: "https://api.cryptonator.com/api/full/BTC-ETH") {
var urlRequest = URLRequest(url: url)
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.setValue("application/json", forHTTPHeaderField: "accept")
urlRequest.httpMethod = "get"
URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
guard let data = data, error == nil else {
print(error ?? "")
return
}
do {
let response = try JSONDecoder().decode(ResultResponse.self, from: data)
print(response)
} catch {
print("catch error", error.localizedDescription)
}
}.resume()
} else {
//Your else code
}
Below are two Codable classes,
struct Ticker: Codable {
let base, target, price, volume: String
let change: String
let markets: [String]
}
struct ResultResponse: Codable {
let ticker: Ticker
let timestamp: Int
let success: Bool
let error: String
}
Once you call this, you will get following output,
ResultResponse(ticker: Demo.Ticker(base: "BTC", target: "ETH", price: "12.67485919", volume: "", change: "-0.04568160", markets: []), timestamp: 1528180081, success: true, error: "")

Type any has no subscript members swift 3

My code is this
import UIKit
import Alamofire
class ViewController: UIViewController {
var young = "https://jsonplaceholder.typicode.com/posts"
override func viewDidLoad() {
super.viewDidLoad()
callAlamo(url: young)
}
func callAlamo(url: String){
Alamofire.request(url).responseJSON { (response) in
let responseJSON = response.data
if responseJSON == nil{
print("response is empty")
}else{
print("Jon is \(responseJSON)")
self.parseJson(JSONData: responseJSON!)
}
}
}
func parseJson(JSONData: Data){
do{
let readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers)
for i in 0..<(readableJSON as AnyObject).count{
print(readableJSON[i] as String)
}
}catch{
print(error)
}
}
}
I need each array element inside this Json.
Try to use below code:
Alamofire.request(url).responseJSON { (response) in
switch response.result {
case .success(let value) :
print(response.request) // original URL request
print(response.response) // HTTP URL response
print(response.data) // server data
print(response.result) // result of response serialization
if let JSON = response.result.value as! [String:AnyObject]!{
print("JSON: ",JSON)
}
case .failure(let encodingError):
completionHandler(APIResponse.init(status: "failure", response: nil, result:nil))
}
}
When using the responseJSON handler, the JSON data has already been parsed internally by JSONSerialization. You do NOT want to try to parse it again, otherwise you're parsing the server's response data twice which is really bad for performance. All you need to do is the following:
Alamofire.request(url).responseJSON { response in
if let json = response.result.value {
print("Parsed JSON: \(json)")
// Now you can cast `json` to a Dictionary or Array
}
}