SwiftJSON parsing { Key: {Key: Value} } case? - json

Here is my json data :
{
"whois": {
"queryType": "IPv4",
"orgID": "ORG572"
}
}
and I want to get "orgID".
I try like this :
switch response.result {
case .success(let value):
let responseJson: JSON = JSON(value)
let orgID = responseJson["whois"]["orgID"].stringValue
print(orgID)
case .failure(let error):
print(error)
}
and that 'orgID' in log console is empty.
What I have to do?

Try using Codable to parse the data instead of using a 3rd party like SwiftyJSON.
Models:
struct Response: Codable {
let whois: Whois
}
struct Whois: Codable {
let queryType, orgID: String
}
Parse the JSON data like so,
do {
let response = try JSONDecoder().decode(Response.self, from: data)
print(response.whois.orgID)
} catch {
print(error)
}

Related

How do I display my searchable data from console to a list in SwiftUI?

I have the following structs:
struct Search: Codable {
struct Data: Codable {
struct Item: Codable {
let symbol: String
let description: String
}
let items: [Item]
}
let data: Data
}
Search function:
func getSearchkData(for search: String) {
let url = URL(string: "https://api.tastyworks.com/symbols/search/\(search)")!
URLSession.shared
.dataTaskPublisher(for: url)
.tryMap { element -> JSONDecoder.Input in
guard let httpResponse = element.response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return element.data
}
.decode(type: Search.self, decoder: JSONDecoder())
.sink { completion in
switch completion {
case .failure(let error):
print(error)
return
case .finished:
return
}
} receiveValue: { [unowned self] searchAPI in
DispatchQueue.main.async {
self.searchAPI.append(searchAPI)
}
print(searchAPI)
}
.store(in: &cancellables)
}
Im able to get the search working in the console but how can I display that exact info into my list?
results of search when I type 'A' into the searchable in swift
Hi #88Camino and welcome to SO! Your example difficile to recreate read this article to race you chance get an right answer https://stackoverflow.com/help/minimal-reproducible-example
Seem the problem is your reSearchData there is no adding receiving values to the array that will be use for the list. You can do it directly in here
receiveValue: { [unowned self] searchAPI in
DispatchQueue.main.async {
self.searchAPI.append(searchAPI) // need to change array here
}
Or if you use this searchAPI array need to .map elements in right format for feed for the list

How to decode JSON data from Alamofire request

I'm trying to decode the json data after fetching json with alamofire. I have created the model class but i don't understand how to decode the data.
Alamofire.request("http://somerandomlink.xyz").responseJSON { (response) in
switch response.result {
case .failure(let error):
print(error)
case .success(let data):
do {
//print(response)
print("data: \(data)")
} catch let error {
print(error)
}
}
}
Model
struct LoremIpsum: Codable {
let var1: String
let var2: String
let var3: String
}
Alamofire has been updated to use Codable objects natively.
Use:
.responseDecodable(of: LoremIpsum.self) {
Instead of:
.responseJSON {
You can also use .responseData instead of responseJSON and then in the success case you can try decoding using JSONDecoder as follows:
let decoder = JSONDecoder()
do {
let users = try decoder.decode(LoremIpsum.self, from:data)
print("Users list :", users)
} catch {
print(error)
}
guard let users = try? JSONDecoder().decode(LoremIpsum.self, from: response) else {
return
}

Check if JSON object null in JWT Authentication for WP REST API

I am using the "JWT Authentication for WP REST API" plug-in to login in my wordpress in iOS.
When the access credentials are correct I get the response from the server:
{
"token": "eyJ0eXAiOiJKV1QiLCJhbG...",
"user_email": "test#myhost.com",
"user_id": 1
}
If the data is incorrect, I get the answer from the server:
{
"code": "[jwt_auth] incorrect_password",
"message": "<strong>ERROR</strong>: Incorrect password",
"data": {
"status": 403
}
}
As I do to check, for example when the data is correct there is no 'code' and if the data is correct there is no 'token'
I tried like, but it does not work
let jsonObject = try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary
if jsonObject["token"] == nil {
print("error password")
} else {
}
First of all use Decodable.
Create Response as enum with cases success and failure and associated types TokenData and ErrorData
enum Response : Decodable {
case success(TokenData)
case failure(ErrorData)
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
do {
self = try .success(container.decode(TokenData.self))
} catch DecodingError.keyNotFound {
self = try .failure(container.decode(ErrorData.self))
}
}
}
struct TokenData : Decodable {
let token, userEmail : String
let userId : Int
}
struct ErrorData : Decodable {
let code, message : String
}
let jsonSuccessString = """
{
"token": "eyJ0eXAiOiJKV1QiLCJhbG...",
"user_email": "test#myhost.com",
"user_id": 1
}
"""
let jsonFailureString = """
{
"code": "[jwt_auth] incorrect_password",
"message": "<strong>ERROR</strong>: Incorrect password",
"data": {
"status": 403
}
}
"""
Decode the JSON and switch on the result, the example decodes both strings for demonstration
let successdata = Data(jsonSuccessString.utf8)
let failuredata = Data(jsonFailureString.utf8)
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let result1 = try decoder.decode(Response.self, from: successdata)
switch result1 {
case .success(let tokenData) : print(tokenData) // TokenData(token: "eyJ0eXAiOiJKV1QiLCJhbG...", userEmail: "test#myhost.com", userId: 1)
case .failure(let errorData) : print(errorData)
}
let result2 = try decoder.decode(Response.self, from: failuredata)
switch result2 {
case .success(let tokenData) : print(tokenData)
case .failure(let errorData) : print(errorData) // ErrorData(code: "[jwt_auth] incorrect_password", message: "<strong>ERROR</strong>: Incorrect password")
}
} catch {
print(error)
}

Converting Firebase Datasnapshot to codable JSON data

I'm using Firebase Database and I'm attempting to retrieve and use data with NSObject. I'm receiving an NSUnknownKeyException error when running the app, causing it to crash.
NSObject:
class WatchList: NSObject {
var filmid: Int?
}
Firebase Code:
ref.child("users").child(uid!).child("watchlist").observe(DataEventType.childAdded, with: { (info) in
print(info)
if let dict = info.value as? [String: AnyObject] {
let list = WatchList()
list.setValuesForKeys(dict)
print(list)
}
}, withCancel: nil)
I'm not sure of what could cause this.
Also, to enhance this solution is their a way to take this data and, instead of using NSObject, use Codable and JSONDecoder with the Firebase data?
You can simply use JSONSerialization to convert the snapshot value property from Any to Data:
let data = try? JSONSerialization.data(withJSONObject: snapshot.value)
You can also extend Firebase DataSnapshot type and add a data and json string properties to it:
import Firebase
extension DataSnapshot {
var data: Data? {
guard let value = value, !(value is NSNull) else { return nil }
return try? JSONSerialization.data(withJSONObject: value)
}
var json: String? { data?.string }
}
extension Data {
var string: String? { String(data: self, encoding: .utf8) }
}
usage:
guard let data = snapshot.data else { return }
It's 2021 now.
Firebase finally added support for decoding Firestore documents. Just let your objects conform to Codable and decode like this:
let result = Result {
try document?.data(as: City.self)
}
switch result {
case .success(let city):
if let city = city {
print("City: \(city)")
} else {
print("Document does not exist")
}
case .failure(let error):
// A `City` value could not be initialized from the DocumentSnapshot.
print("Error decoding city: \(error)")
}
Just don't forget to add the 'FirebaseFirestoreSwift' pod and then import it into your file.
Read more:
https://firebase.google.com/docs/firestore/query-data/get-data#custom_objects
Original answer
A really nice library to use here is Codable Firebase which I am also using in my project. Just make your class / struct conform to Codable protocol and use FirebaseDecoder to decode your Firebase data into a Swift object.
Example:
Database.database().reference().child("model").observeSingleEvent(of: .value, with: { snapshot in
guard let value = snapshot.value else { return }
do {
let model = try FirebaseDecoder().decode(Model.self, from: value)
print(model)
} catch let error {
print(error)
}
})

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")