i am trying to create a CRM app, for this i created a database on my raspberry Pi, and used PHP to create JSON results on a url.
Now i have created the following Network manager in swift, but the invalidData error at the end in the catch keeps getting thrown. What am i doing wrong ?
import Foundation
final class NetworkManager {
static let shared = NetworkManager()
static let baseURL = ""
private let buyersURL = baseURL + ""
private init(){}
func getBuyers(completed: @escaping (Result<[Buyer], CRMError>) -> Void) {
guard let url = URL(string: buyersURL) else {
completed(.failure(.invalidURL))
return
}
let task = URLSession.shared.dataTask(with: URLRequest(url: url)) { data, response, error in
if let _ = error {
completed(.failure(.unableToComplete))
return
}
guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
completed(.failure(.invalidResponse))
return
}
guard let data = data else {
completed(.failure(.invalidData))
return
}
do {
let decoder = JSONDecoder()
let decodedResponse = try decoder.decode(BuyerResponse.self, from: data)
completed(.success(decodedResponse.request))
} catch {
completed(.failure(.invalidData))
}
}
task.resume()
}
}
The following is the result of the JSON on the URL
and the following is my Buyer struct:
import Foundation
struct Buyer: Codable, Identifiable, Hashable{
let id: Int
let user_id: Int
let name: String
let email: String
let country: String
let phone: String
let second_phone: String
let whishes: String
let budget: String
let timing: String
let fase: String
let media: String
let plans: String
let extra: String
let hot: Int
}
struct BuyerResponse : Codable {
let request: [Buyer]
}
And this is the view in which i call get the buyers:
struct BuyersView: View {
@StateObject var viewModel = BuyersViewModel()
@State var path = NavigationPath()
@State private var buyers: [Buyer] = []
var body: some View {
NavigationStack(path: $path) {
VStack{
CategoryView(categories: viewModel.fases, currentSelection: $viewModel.currentFase)
HStack{
Spacer()
NavigationLink("Add buyer", value: 0)
.padding()
}
List(buyers){ buyer in
BuyerCellView(buyer: buyer)
}
}
// .navigationDestination(for: Int.self) { _ in
// AddBuyerView(path: $path, fases: viewModel.fases, medias: $viewModel.media)
// }.navigationDestination(for: Buyer.self) { buyer in
// BuyerDetailView(buyer: buyer)
// }
}.onAppear{
getBuyers()
}
}
func getBuyers() {
NetworkManager.shared.getBuyers { result in
DispatchQueue.main.async {
switch result {
case .success(let buyers):
self.buyers = buyers
case .failure(let error):
print(error.localizedDescription)
}
}
}
}
}
I checked that the variables on the JSON and the struct of Buyer are the same, but the error keeps happening, i just expect that the variable buyers returns a list of Buyers from the JSON.
I folowed the tutorial of https://www.youtube.com/watch?v=b1oC7sLIgpI&t=22362s at around 6 hours into the video
Thank you for helping in advance
The inside of BuyerResponse
you say that the JSON should look like this:
{ request: [{buyer 1 properties}, {buyer 2 properties}] }
But judging from your screenshot, the response looks like this:
[{buyer 1 properties}, {buyer 2 properties}]
Inside of your PHP script you should adjust the response so that you get that request:
before the list starts. That should do the trick.
Another way would be to change that line here
let decodedResponse = try decoder.decode(BuyerResponse.self, from: data)
to
let decodedResponse = try decoder.decode([Buyer].self, from: data)
That way you tell the decoder that it's getting a list of Buyer
s without anything around it.
Generally if you get an error at that position, it means that the data that you receive does not match the data structure that you specify.
A good way to approach this is to just create a model struct with only one property and check whether that works. Then add another property, etc. If it doesn't work: print the error you receive and that will tell you at what line of the JSON there is something unexpected.