How do I decode this json in Swift 4, with decoder?
I want to be able to get the "token" by itself, so I can store it in the Keychain.
{
"success":true,
"token":"***"
,
"user": {
"id": "59f0ec6d5479390345980cc8",
"username": "john",
"email": "john#gmail.com"
}
}
I have tried this, but it doesn't print anything.
let session = URLSession.shared
let task = session.dataTask(with: request) { (data, _, _) in
guard let data = data else { return }
do {
let jsonwt = try JSONDecoder().decode(JWT.self, from: data)
print(jsonwt.token)
} catch {}
}
task.resume()
}
I can put this after the catch, but that gets the whole json, and I don't want that.
print(String(data: data, encoding: .utf8)!)
Here are the structures. I think this is where the problem lies.
struct User: Decodable {
let id: String
let username: String
let email: String
}
struct JWT: Decodable {
let success: String
let token: String
let user: User
}
Works like this:
struct User : Codable
{ var id : String
}
struct JWT : Codable
{ var success : Bool
var token : String
var user :User
}
let json = """
{ \"success\" : true,
\"token\" : \"***\",
\"user\":
{ \"id\": \"59f0ec6d5479390345980cc8\",
\"username\": \"john\",
\"email\": \"john#gmail.com\"
}
}
"""
let decoder = JSONDecoder()
let jwt = try decoder.decode(JWT.self, from: json.data(using: .utf8)!)
print ("token: \(jwt.token)")
Here's some playground code that demonstrates the code for parsing JSON in Swift:
//: Playground - noun: a place where people can play
import UIKit
import XCTest
import PlaygroundSupport
let json = """
{
"success":true,
"token":"***"
,
"user": {
"id": "59f0ec6d5479390345980cc8",
"username": "john",
"email": "john#gmail.com"
}
}
""".data(using: .utf8)!
do {
if let data = try JSONSerialization.jsonObject(with: json, options: .allowFragments) as? [String:Any], let token = data["token"] {
print("token is \(token)")
}
} catch _ {
print("Failed to decode JSON")
}
Related
How to parse following json which I want to parse only few part.
```
{
"head": {
"StatusValue": 200,
"StatusText": "Success"
},
"body": {
"Data": [
{
"payer_type_id": 1,
"payer_type": "Self Pay"
},
{
"payer_type_id": 2,
"payer_type": "Corporate"
},
{
"payer_type_id": 6,
"payer_type": "Insurance"
}
],
"RecordCount": 3,
"TotalRecords": null
}
}
How to parse only data inside Data key.
Expected result should be in following format
Date = [["payer_type_id": 1,"payer_type": "Self Pay"],["payer_type_id": 2,"payer_type": "Corporate"],["payer_type_id": 6,"payer_type": "Insurance"]]
You can use Codable protocol for your parsing .
Create Your Model
struct APIRootModel : Codable {
let head : HeaderModel
let body : BodyModel
}
struct HeaderModel :Codable{
let StatusValue : Int
let StatusText : String
}
struct BodyModel : Codable{
let Data : [DataModel]
}
struct DataModel : Codable{
let payer_type_id : Int
let payer_type : String
}
Decode your json using JSONDecoder()
let decoder = JSONDecoder()
do {
let rootModel = try decoder.decode(APIRootModel.self, from: jsonData)
print(rootModel.body.data)
} catch {
print(error)
}
Use [DataModel] for your tableview datasource.
Try this:
let jsonString = "your json string here"
let dictObject = getDictionaryFromJsonString(dictString: jsonString)
let bodyDict = dictObject["body"]
let dataArray = bodyDict["Data"]
func getDictionaryFromJsonString(dictString:String)->
[String: Any] {
do {
return try JSONSerialization.jsonObject(with:
dictString.data(using: String.Encoding.utf8,
allowLossyConversion: true)!, options:
JSONSerialization.ReadingOptions.allowFragments) as!
Dictionary
} catch {
return [:]
}
}
In browser my url gives results in perfect JSON format as follows
"articles": [
{
"source": {
"id": "the-times-of-india",
"name": "The Times of India"
},
"author": "Times Of India",
But Where as in Xcode output the response I am getting is as follows. How to convert this response into perfect json format
{
articles = (
{
author = "Times Of India";
content = "Hyderabad: Senior Police officials arrive at the site of the encounter. All four accused in the rape
description = "India News: All four accused in the rape and murder of woman veterinarian in Telangana have been killed in an encounter with the police. Cops claimed they tried t";
publishedAt = "2019-12-06T04:15:00Z";
source = {
name = "The Times of India";
};
},
I am using the following code to decode the json data
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let dataResponse = data, error == nil else {
print(error?.localizedDescription ?? "Response Error")
return
}
do{
//here dataResponse received from a network request
let jsonResponse = try JSONSerialization.jsonObject(with: dataResponse, options: [])
print(jsonResponse) //Response result
} catch let parsingError {
print("Error", parsingError)
}
}
task.resume()
Please help me with this issue.
first you must create a Decodable struct and put it before viewController class:
struct YourArrray: Decodable {
let author: String?
let content: String?
let location: String?
let description : String?
let publishedAt : String?
let name: String?
}
declare your Url:
let jsonUrlString = "https://yourUrljson"
after that create your struct array var:
var myVar = [YourArrray]()
now you can procede to decode json:
fileprivate func fetchJsonObject() {
guard let url = URL(string: jsonUrlString) else { return }
URLSession.shared.dataTask(with: url) { (data, respons, err) in
guard let data = data else { return }
do {
let jsonResponse = try JSONDecoder().decode([myVar].self, from: data)
print(jsonResponse)
} catch let jsonErr {
print("Error serializing:", jsonErr)
}
}.resume()
}
Now you can simply call the function fetchJsonObject() and you're done
Hope this help :)
I am trying to parse this JSON using Codable:
{
"users": [
{
"id": 1,
"name": "Allen Carslake",
"userName": "acarslake0",
"profileImage": "https://source.unsplash.com/random/400x400",
"createdDate": "2019-07-08T00:00:00.000+0000"
},
{
"id": 2,
"name": "Revkah Antuk",
"userName": "rantuk1",
"profileImage": "https://source.unsplash.com/random/400x400",
"createdDate": "2019-07-05T00:00:00.000+0000"
},
{
"id": 3,
"name": "Mirna Saffrin",
"userName": "msaffrin2",
"profileImage": "https://source.unsplash.com/random/400x400",
"createdDate": "2019-05-19T00:00:00.000+0000"
},
{
"id": 4,
"name": "Haily Eilers",
"userName": "heilers3",
"profileImage": "https://source.unsplash.com/random/400x400",
"createdDate": "2019-06-28T00:00:00.000+0000"
},
{
"id": 5,
"name": "Oralie Polkinhorn",
"userName": "opolkinhorn4",
"profileImage": "https://source.unsplash.com/random/400x400",
"createdDate": "2019-06-04T00:00:00.000+0000"
}
]
}
I am keeping the URL private on here but it is returning JSON above. So far this is my code:
import UIKit
struct User: Codable {
let id: Int
let name: String
let userName: String
let profileImage: String
let createdDate: String
}
struct Users: Codable {
let users: String
}
let url = URL(string: "")!
URLSession.shared.dataTask(with: url) { data, _, _ in
if let data = data {
let users = try? JSONDecoder().decode([User].self, from: data)
print(users)
}
}.resume()
I need to be able to access the User properties but I think the nesting is making it difficult for me. Any help is awesome!! Thank you!!
First of all: Catch always the DecodingError and print it. It tells you exactly what's wrong.
The error occurs because you are ignoring the root object Users. Your code works if you decode(Users.self.
My suggestions:
Decode createdDate as Date adding a appropriate date decoding strategy.
Decode profileImage as URL (for free).
Handle all errors.
struct Root : Decodable { // `Users` and `User` is too confusing
let users: [User]
}
struct User : Decodable {
let id: Int
let name: String
let userName: String
let profileImage: URL
let createdDate: Date
}
URLSession.shared.dataTask(with: url) { data, _, error in
if let error = error { print(error); return }
do {
let decoder = JSONDecoder()
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
decoder.dateDecodingStrategy = .formatted(dateFormatter)
let result = try decoder.decode(Root.self, from: data!)
for user in result.users {
print(user.userName, user.id, user.createdDate)
}
} catch {
print(error)
}
}.resume()
The root of the json is a dictionary not an array you can write a root class but it will be useless , so you need
URLSession.shared.dataTask(with: url) { data, _, _ in
do {
if let data = data {
let res = try JSONSerialization.jsonObject(with: data) as! [String:Any]
let usersData = try JSONSerialization.data(withJSONObject: res["users"])
let users = try JSONDecoder().decode([User].self, from: usersData)
print(users)
}
}
catch {
print(error)
}
}.resume()
Your Users struct (I renamed it to UsersResponse) should contain a users property of type [User]. Then you can do the following:
struct UsersResponse: Codable {
let users: [User]
}
URLSession.shared.dataTask(with: url) { data, _, _ in
guard let data = data else { return }
if let users = try? JSONDecoder().decode(Users.self, from: data).users {
users.forEach { user in
print("A user called \(user.name) with an id of \(user.id).")
}
}
}.resume()
Please try the below code. This is working for me.
Model Class:
struct UsersResponse: Codable {
let users: [User]
}
struct User: Codable {
let id: Int
let name: String
let userName: String
let profileImage: String?
let createdDate: String
}
Network class:
public enum EndPoints: String {
case prod = "ProdURL"
case test = "testURL"
}
public enum Result<T> {
case success(T)
case failure(Error)
}
final public class Networking: NSObject {
// MARK: - Private functions
private static func getData(url: URL,
completion: #escaping (Data?, URLResponse?, Error?) -> ()) {
URLSession.shared.dataTask(with: url, completionHandler: completion).resume()
}
/// fetchUsersResponse function will fetch the User Response and returns
/// Result<UsersResponse> as completion handler
public static func fetchUsersResponse(shouldFail: Bool = false, completion: #escaping (Result<UsersResponse>) -> Void) {
var urlString: String?
if shouldFail {
urlString = EndPoints.test.rawValue
} else {
urlString = EndPoints.prod.rawValue
}
guard let mainUrlString = urlString, let url = URL(string: mainUrlString) else { return }
Networking.getData(url: url) { (data, response, error) in
if let error = error {
completion(.failure(error))
return
}
guard let data = data, error == nil else { return }
do {
let decoder = JSONDecoder()
//decoder.dateDecodingStrategy = .millisecondsSince1970
decoder.dateDecodingStrategy = .formatted(setDateFormat())
let json = try decoder.decode(UsersResponse.self, from: data)
completion(.success(json))
} catch let error {
completion(.failure(error))
}
}
}
func setDateFormat() -> DateFormatter {
let dateFormat = DateFormatter()
dateFormat.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
return dateFormat
}
I'm trying to load local JSON file and parse using model which conforms to Decodable protocol.
JSON file:
[
{
"body": {},
"header": {
"returnCode": "200",
"returnMessage": "Successfully Received",
}
}
]
Response Message model:
struct ResponseMessage: Decodable {
struct header: Decodable {
let returnCode: String
let returnMessage: String
}
}
Mock API implementation:
let url = Bundle.main.url(forResource: "MockJSONData", withExtension: "json")!
do {
let data = try Data(contentsOf: url)
let teams = try JSONDecoder().decode(ResponseMessage.self, from: data)
print(teams)
} catch {
print(error)
}
But Response Message returns empty data for that.
Appreciate your help and suggestions!
Thanks
Update ResponseMessage and Header types as below,
struct ResponseMessage: Decodable {
var header: Header
}
struct Header: Decodable {
let returnCode: String
let returnMessage: String
}
and decode like this,
do {
let data = try Data(contentsOf: url)
let teams = try JSONDecoder().decode([ResponseMessage].self, from: data)
print(teams.first!.header.returnMessage)
} catch {
print(error)
}
I am trying to parse JSON using codable. I am able to decode it but it is in a root array and i am unable to print each value on by it self. the compiler is complaining saying Value of type '[Root]' has no member 'commit'. How can i change this to print the values. Below is the JSON
[
{
"sha": "3f4227ec2894bb354b145deff9dbc1adc6b6d6f2",
"node_id": "MDY6Q29tbWl0NDQ4Mzg5NDk6M2Y0MjI3ZWMyODk0YmIzNTRiMTQ1ZGVmZjlkYmMxYWRjNmI2ZDZmMg==",
"commit": {
"author": {
"name": "Slava Pestov",
"email": "sviatoslav.pestov#gmail.com",
"date": "2018-08-12T08:09:22Z"
}
}
},
{
"sha": "3f4227ec2894bb354b145deff9dbc1adc6b6d6f2",
"node_id": "MDY6Q29tbWl0NDQ4Mzg5NDk6M2Y0MjI3ZWMyODk0YmIzNTRiMTQ1ZGVmZjlkYmMxYWRjNmI2ZDZmMg==",
"commit": {
"author": {
"name": "Slava Pestov",
"email": "sviatoslav.pestov#gmail.com",
"date": "2018-08-12T08:09:22Z"
}
}
}
]
I decode it here
struct Root: Decodable {
let commit: Author
}
struct Author: Decodable {
let author: People
}
struct People: Decodable {
let name: String?
let date: String?
let email: String?
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
getCommits()
}
func getCommits() {
let urlString = "https://api.github.com/repos/apple/swift/commits"
guard let url = URL(string: urlString) else {
print("Couldn't fetch JSON")
return
}
let session = URLSession.shared
let dataTask = session.dataTask(with: url) { (data, response, error) in
guard data != nil && error == nil else {
print(data ?? "")
return
}
do {
let decoder = JSONDecoder()
let result = try decoder.decode([Root].self, from: data!)
print(result.commit)
print(result.commit.author.name)
} catch let decodeError {
print("Failed to decode json:", decodeError)
}
}
dataTask.resume()
}
}
And here is my output in the console. I would like to be able to print only the name, date and email.
[Gihhub.Commits(commit: Gihhub.Author(author: Gihhub.People(name: Optional("Slava Pestov"), date: Optional("2018-08-12T08:09:22Z"), email: Optional("sviatoslav.pestov#gmail.com")))), Gihhub.Commits(commit: Gihhub.Author(author: Gihhub.People(name: Optional("Slava Pestov"), date: Optional("2018-08-12T03:47:22Z"), email: Optional("spestov#apple.com")))), Gihhub.Commits(commit: Gihhub.Author(author: Gihhub.People(name: Optional("Slava Pestov"), date: Optional("2018-08-12T03:47:08Z"), email: Optional("spestov#apple.com"))))]
result is an array you need
result.forEach {
print($0.commit.author.name)
print($0.commit.author.date)
print($0.commit.author.email)
}