to decode your json data you must first get the correct swift data model that match the data.
A quick way to do this, is to copy and paste your json data into "https://quicktype.io/".
This site will give you the swift structs you need. Then you need to make a request call
to the server. Here is the code that does this, given the swift data structs.
import SwiftUI
@main
struct TestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
@State var results = [Result]()
var body: some View {
List {
ForEach(results) { news in
VStack {
Text(news.title)
Text(news.link).foregroundColor(.blue)
}
}
}
.onAppear {
loadNews()
}
}
func loadNews() {
let jsonUrl = URL(string: "https://newsdata.io/api/1/news?apikey=YOURAPIKEY&q=travelling&language=en")
guard let url = jsonUrl else { return }
let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data else { return }
do {
let response = try JSONDecoder().decode(Response.self, from: data)
results = response.results
}
catch {
print("---> error: \(error)")
}
}
task.resume()
}
}
struct Response: Codable {
let status: String
let totalResults: Int
let results: [Result]
let nextPage: Int
}
struct Result: Identifiable, Codable {
let id = UUID()
let title: String
let link: String
let keywords: [String]?
let creator: [String]?
let videoURL: JSONNull?
let resultDescription, content: String?
let pubDate: String
let fullDescription: String?
let imageURL: String?
let sourceID: String
enum CodingKeys: String, CodingKey {
case title, link, keywords, creator
case videoURL = "video_url"
case resultDescription = "description"
case content, pubDate
case fullDescription = "full_description"
case imageURL = "image_url"
case sourceID = "source_id"
}
}
class JSONNull: Codable, Hashable {
public static func == (lhs: JSONNull, rhs: JSONNull) -> Bool {
return true
}
public var hashValue: Int {
return 0
}
public init() {}
public required init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if !container.decodeNil() {
throw DecodingError.typeMismatch(JSONNull.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for JSONNull"))
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encodeNil()
}
}
PS: do not post your secret API key. Remove it from your question, now.
EDIT-1:
if you really need for some reason, not to decode status
and totalResults
make the properties let
and give them an initial value, as shown below. Xcode will tell you these will not be decoded.
struct Response: Codable {
let results: [Result]
let status: String = "" // <-- here give the let a value
let totalResults: Int = 0 // <-- here give the let a value
let nextPage: Int = 0 // <-- here give the let a value
}
or remove those fields if you never want to use them:
struct Response: Codable {
let results: [Result]
}