I would like some assistance trying to find out why I can't process this curl URLRequest in Swift. I believe my issue is how I am adding my headers but I can't figure this out. I've tried multiple ways without success. All the examples I am finding here don't seem to work for this situation.
When I get to the JSONDecoder I think it's decoding something, but not what I am expecting and the debugger doesn't get to the catch error.
Any assistance would be greatly appreciated!
import Foundation
import SwiftUI
class Network: ObservableObject {
@Published var Loan: [LoanSelected] = []
func getLoan() {
guard let url = URL(string: "https://absws.com/TmoAPI/v1/LSS.svc/GetLoan/1001")
else
{
return
}
var urlRequest = URLRequest(url: url)
let headers = [
"Token": "VIC",
"Database": "World"
]
//urlRequest.httpMethod = "GET"
//urlRequest.addValue("ABS", forHTTPHeaderField: "Token")
//urlRequest.addValue("World Mortgage Company", forHTTPHeaderField: "Database")
//urlRequest.httpBody = payload
urlRequest.httpMethod = "GET"
urlRequest.allHTTPHeaderFields = headers
let dataTask = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
if let error = error {
print("Request error: ", error)
return
}
guard let response = response as? HTTPURLResponse else { return }
if response.statusCode == 200 {
guard let data = data else { return }
DispatchQueue.main.async {
do {
let decodedUsers = try JSONDecoder().decode([LoanSelected].self, from: data)
self.Loan = decodedUsers
} catch let error {
print("Error decoding: ", error)
}
}
}
}
dataTask.resume()
}
}
You are not getting an array [LoanSelected]
from the server with the url you show.
Try this approach, using model struts that match the json data you are getting from the API.
Here is my test code, works well for me.
Use https://app.quicktype.io/ to generate the correct model structs for you.
struct ContentView: View {
@StateObject var network = Network()
var body: some View {
ScrollView {
Text("Loan")
.font(.title)
.bold()
VStack(alignment: .leading) {
HStack(alignment:.top) {
Text("\(network.loan?.account ?? "no account")")
VStack(alignment: .leading) {
Text(network.loan?.bankName ?? "no bank").bold()
}
}
.frame(width: 300, alignment: .leading)
.padding()
.cornerRadius(20)
}
}
.padding(.vertical)
.onAppear {
network.getLoan()
}
}
}
class Network: ObservableObject {
@Published var loan: Loan? // <-- here
func getLoan() {
guard let url = URL(string: "https://absws.com/TmoAPI/v1/LSS.svc/GetLoan/1001"),
let payload = "".data(using: .utf8) else {
return
}
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "GET"
urlRequest.addValue("ABS", forHTTPHeaderField: "Token")
urlRequest.addValue("World Mortgage Company", forHTTPHeaderField: "Database")
urlRequest.httpBody = payload
let dataTask = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
if let error = error {
print("Request error: ", error)
return
}
guard let response = response as? HTTPURLResponse else { return }
if response.statusCode == 200 {
guard let data = data else { return }
DispatchQueue.main.async {
do {
let decoded = try JSONDecoder().decode(ApiData.self, from: data) // <-- here
self.loan = decoded.data
} catch let error {
print("Error decoding: ", error)
}
}
}
}
dataTask.resume()
}
}
struct ApiData: Codable {
let data: Loan
let errorMessage: String
let errorNumber, status: Int
enum CodingKeys: String, CodingKey {
case data = "Data"
case errorMessage = "ErrorMessage"
case errorNumber = "ErrorNumber"
case status = "Status"
}
}
struct Loan: Codable {
let type, account, accountNumber, accountType: String
let applyAs, bankAddress, bankName, borrowerRecID: String
let byLastName: String?
let cdfiReporting: String
let coBorrowers: [String]
let customFields: [CustomField]
let debitAmount, debitDueDay, emailAddress, emailFormat: String
let frequency, individualID, individualName, isTemplate: String
let losLoanRecID, nextDebitDate, notes: String
let primaryBorrower: PrimaryBorrower
let primaryProperty: String?
let recID, routingNumber, serviceStatus, sortName: String
let stopDate: String
let sysTimeStamp: String?
let terms: [String: String?]
let useDebitAmount, wpcPin, wpcPublish: String
enum CodingKeys: String, CodingKey {
case type = "__type"
case account = "Account"
case accountNumber = "AccountNumber"
case accountType = "AccountType"
case applyAs = "ApplyAs"
case bankAddress = "BankAddress"
case bankName = "BankName"
case borrowerRecID = "BorrowerRecID"
case byLastName = "ByLastName"
case cdfiReporting = "CDFIReporting"
case coBorrowers = "CoBorrowers"
case customFields = "CustomFields"
case debitAmount = "DebitAmount"
case debitDueDay = "DebitDueDay"
case emailAddress = "EmailAddress"
case emailFormat = "EmailFormat"
case frequency = "Frequency"
case individualID = "IndividualId"
case individualName = "IndividualName"
case isTemplate = "IsTemplate"
case losLoanRecID = "LOSLoanRecID"
case nextDebitDate = "NextDebitDate"
case notes = "Notes"
case primaryBorrower = "PrimaryBorrower"
case primaryProperty = "PrimaryProperty"
case recID = "RecID"
case routingNumber = "RoutingNumber"
case serviceStatus = "ServiceStatus"
case sortName = "SortName"
case stopDate = "StopDate"
case sysTimeStamp = "SysTimeStamp"
case terms = "Terms"
case useDebitAmount = "UseDebitAmount"
case wpcPin = "WPC_PIN"
case wpcPublish = "WPC_Publish"
}
}
struct CustomField: Codable {
let name: String
let tab: String
let value: String
enum CodingKeys: String, CodingKey {
case name = "Name"
case tab = "Tab"
case value = "Value"
}
}
struct PrimaryBorrower: Codable {
let account, borrowerRecID, city, deliveryOptions: String
let emailAddress, emailFormat, firstName, fullName: String
let lastName, mi, phoneCell, phoneFax: String
let phoneHome, phoneWork, placeOnHold, recID: String
let rolodexPrint, salutation, sendLateNotices, sendPaymentReceipt: String
let sendPaymentStatement, state, street, tin: String
let tinType, zipCode: String
enum CodingKeys: String, CodingKey {
case account = "Account"
case borrowerRecID = "BorrowerRecID"
case city = "City"
case deliveryOptions = "DeliveryOptions"
case emailAddress = "EmailAddress"
case emailFormat = "EmailFormat"
case firstName = "FirstName"
case fullName = "FullName"
case lastName = "LastName"
case mi = "MI"
case phoneCell = "PhoneCell"
case phoneFax = "PhoneFax"
case phoneHome = "PhoneHome"
case phoneWork = "PhoneWork"
case placeOnHold = "PlaceOnHold"
case recID = "RecID"
case rolodexPrint = "RolodexPrint"
case salutation = "Salutation"
case sendLateNotices = "SendLateNotices"
case sendPaymentReceipt = "SendPaymentReceipt"
case sendPaymentStatement = "SendPaymentStatement"
case state = "State"
case street = "Street"
case tin = "TIN"
case tinType = "TINType"
case zipCode = "ZipCode"
}
}