Aim: To show the API data into Tab bar using SwiftUI
What i tried : I tried to implement the API using model and implemented it into tab view.
What is the issue: i have tried to change my model many time, still the data is not correctly fetched.
Getting error: The data couldn’t be read because it isn’t in the correct format.
API url: https://dev.myhss.org.uk/api/v1/events/eventlist
Optional parameter(can be used):
key : event_type
value: 1(1- upcoming events, 2- past events)
body: x-www-form-unlencoded
Ideal response:
{
"status": true,
"message": "Event Listing",
"data": {
"upcoming": [
{
"event_id": "1",
"event_title": "event tile",
"event_start_date": "2024-02-02 16:55:08",
"event_end_date": "2024-06-20 16:55:08",
"event_img": "https://dev.myhss.org.uk/assets/events/event-1.png",
"event_chargable_or_not": "0"
}
],
"past": [
{
"event_id": "2",
"event_title": "event title 2",
"event_start_date": "2023-04-15 16:55:08",
"event_end_date": "2023-05-31 16:55:08",
"event_img": "https://dev.myhss.org.uk/assets/events/event-2.png",
"event_chargable_or_not": null
}
]
}
}
Updated the suggested code from the answer , but still, the issue persist,
Error: The data couldn’t be read because it isn’t in the correct format.
SwiftUI code:
import SwiftUI
struct EventListing: Codable {
var status: Bool
var message: String
var data: Event2
}
struct Event2: Codable {
var upcoming: [Event]
var past: [Event]
}
struct Event: Codable, Identifiable {
var id: String // Add this property to conform to Identifiable
var title: String
var startDate: Date
var endDate: Date
var imageURL: URL?
var isChargeable: Bool
enum CodingKeys: String, CodingKey {
case id = "event_id"
case title = "event_title"
case startDate = "event_start_date"
case endDate = "event_end_date"
case imageURL = "event_img"
case isChargeable = "event_chargable_or_not"
}
}
import SwiftUI
struct OkView: View {
var body: some View {
TabView {
UpcomingEventsView()
.tabItem {
Image(systemName: "calendar.circle")
Text("Upcoming")
}
PastEventsView()
.tabItem {
Image(systemName: "calendar.circle.fill")
Text("Past")
}
}
}
}
struct UpcomingEventsView: View {
@State private var events: [Event] = []
var body: some View {
List(events) { event in
Text(event.title)
}
.onAppear {
ApiService.fetchEvents(type: .upcoming) { result in
switch result {
case .success(let eventListing):
self.events = eventListing.data.upcoming
case .failure(let error):
print(error.localizedDescription)
}
}
}
}
}
struct PastEventsView: View {
@State private var events: [Event] = []
var body: some View {
List(events) { event in
Text(event.title)
}
.onAppear {
ApiService.fetchEvents(type: .past) { result in
switch result {
case .success(let eventListing):
self.events = eventListing.data.past
case .failure(let error):
print(error.localizedDescription)
}
}
}
}
}
enum EventType {
case upcoming
case past
}
class ApiService {
static let baseUrl = "https://dev.myhss.org.uk/api/v1/events/eventlist"
static let dateFormatter = DateFormatter()
static func fetchEvents(type: EventType, completion: @escaping (Result<EventListing, Error>) -> Void) {
let endpoint = type == .upcoming ? "events/upcoming" : "events/past"
guard let url = URL(string: "(baseUrl)/(endpoint)") else {
completion(.failure(ApiError.invalidUrl))
return
}
URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
completion(.failure(error))
return
}
guard let data = data else {
completion(.failure(ApiError.noData))
return
}
do {
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(dateFormatter)
let eventListing = try decoder.decode(EventListing.self, from: data)
completion(.success(eventListing))
} catch let error {
completion(.failure(error))
}
}.resume()
}
enum ApiError: Error {
case invalidUrl
case noData
}
}
2
Answers
You should change your DTO as
in your codes i can not see the data part but that should be like these. After change code please check the url is correct and data is coming correctly.
Try the following code, using a
URLRequest
with aPOST
header, instead of your url, andmodified
Event
model, note especially, thevar isChargeable: String?
notBool
, works for me.In addition, you need to consult the server docs, to determine which properties are optional, and adjust the code (add
?
) accordingly.