Retrieving data from JSON API with “X-Auth-Token” header

Im working on project using the football-data.org api and have received an API key for it that instructed me to modify my client to use a HTTP header named “X-Auth-Token” with the underneath personal token as value. I asked a question about retrieving data from a json api recently but that one did not have an API Key needed.

check past question here

I updated the fetch function to incorporate my API key but no data is being retrieved. I have attached the updated fetch func and where it gets called as well as the object structs incase it is an issue with how I created my array of teams.

ContentView:

struct ContentView: View {
    @State var teams: [Team] = []
    let apiKey = "API_KEY"
    // for procesing fetch request from json URL
    @State private var processing: Bool = false
    
    var body: some View {
        VStack {
            if processing {
                ProgressView()
            }
            else {
                ForEach(teams, id: .id) { team in
                    Text(team.name ?? "Team Not Found")
                }
            }
        }
        .task {
            processing = true
            let response: TeamApiResponse? = await fetchTeam(urlString: "https://api.football-data.org/v4/competitions/PL/teams")
            if let teamResponse = response?.team {
                teams = teamResponse
            }
            processing = false
        }
        .padding()
    }
    
    // curl -X GET "https://api.football-data.org/v4/competitions/PL/teams/66" -H "X-Auth-Token: API_KEY"
    // Man United = 66
    
    func fetchTeam<T: Decodable>(urlString: String) async -> T? {
        // Define your API key
        let apiKey = "your_api_key_here"
        
        // Create the URL from the provided urlString
        guard let url = URL(string: urlString) else {
            print("Invalid URL string")
            return nil
        }
        
        // Create a URLRequest object
        var request = URLRequest(url: url)
        
        // Add the API key to the request header
        request.setValue(apiKey, forHTTPHeaderField: "X-Auth-Token")
        
        do {
            // Perform the network request
            let (data, response) = try await URLSession.shared.data(for: request)
            
            // Check if the response status code is 200 (OK)
            guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
                print(URLError(.badServerResponse))
                return nil
            }
            
            // Decode the data into the specified type
            return try JSONDecoder().decode(T.self, from: data)
        } catch {
            // Handle errors during the request or decoding
            print("----> error: (error)")
            return nil
        }
    }
}

structs:

import Foundation
import UIKit

struct TeamApiResponse: Decodable {
    var team: [Team]?
}

struct Team: Decodable, Identifiable {
    var id: String?
    var name: String?
    var shortName: String?
    var abbreviation: String?
    var crest: UIImage?
    var address: String?
    var website: URL?
    var founded: String?
    var clubColors: String? // Idk do something with this later in relation to UI
    var venue: String?
    var marketValue: Int? // add formatting to this
    var lastUpdated: String?
    
    var runningCompetitions: [Competition]
    var coach: Coach
    var squad: [Player]
    
    enum CodingKeys: String, CodingKey {
        // omitting area for now
        case id
        case name
        case shortName
        case abbreviation = "tla"
        case crestURL = "crest"
        case address
        case website
        case founded
        case clubColors
        case venue
        case marketValue
        // omitting staff for now
        case lastUpdated
        case runningCompetitions
        case coach
        case squad
    }
    
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        self.id = try values.decode(String.self, forKey: .id)
        self.name = try values.decodeIfPresent(String.self, forKey: .name)
        self.shortName = try values.decodeIfPresent(String.self, forKey: .shortName)
        self.abbreviation = try values.decodeIfPresent(String.self, forKey: .abbreviation)
        
        // convert crestURL to UIImage
        let crestURL = try values.decodeIfPresent(URL.self, forKey: .crestURL)
        let imageData =  try Data(contentsOf: crestURL!) // may need to provide default value in instance this doesn't work
        self.crest = UIImage(data: imageData)
        
        self.address = try values.decodeIfPresent(String.self, forKey: .address)
        self.website = try values.decodeIfPresent(URL.self, forKey: .website)
        self.founded = try values.decodeIfPresent(String.self, forKey: .founded)
        self.clubColors = try values.decodeIfPresent(String.self, forKey: .clubColors)
        self.venue = try values.decodeIfPresent(String.self, forKey: .venue)
        self.marketValue = try values.decodeIfPresent(Int.self, forKey: .marketValue)
        self.lastUpdated = try values.decodeIfPresent(String.self, forKey: .lastUpdated)
        
        // fetch from competitions block
        self.runningCompetitions = try values.decodeIfPresent([Competition].self, forKey: .runningCompetitions) ?? []
        
        // fetch from coach block
        self.coach = try values.decodeIfPresent(Coach.self, forKey: .coach) ?? Coach()
        
        // fetch from squad block
        self.squad = try values.decodeIfPresent([Player].self, forKey: .squad) ?? []
    }
}

/**
 {
 "id": 11656,
 "firstName": "Agustín",
 "lastName": "Rossi",
 "name": "Agustín Rossi",
 "position": "Goalkeeper",
 "dateOfBirth": "1995-08-21",
 "nationality": "Argentina",
 "shirtNumber": 1,
 "marketValue": 3200000,
 "contract": {
 "start": "2017-02",
 "until": "2023-12"
 }
 }
 */
struct Player: Identifiable, Hashable, Decodable {
    var id: Int
    var firstName: String
    var lastName: String
    var name: String
    var position: String
    var dateOfBirth: String
    var nationality: String
    var shirtNumber: Int
    var marketValue: Int // add formatting to this
    //omitt contract dates for now
    
    enum CodingKeys: String, CodingKey {
        case id
        case firstName
        case lastName
        case name
        case position
        case dateOfBirth
        case nationality
        case shirtNumber
        case marketValue
    }
    
    init(from decoder: any Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.id = try container.decode(Int.self, forKey: .id)
        self.firstName = try container.decode(String.self, forKey: .firstName)
        self.lastName = try container.decode(String.self, forKey: .lastName)
        self.name = try container.decode(String.self, forKey: .name)
        self.position = try container.decode(String.self, forKey: .position)
        self.dateOfBirth = try container.decode(String.self, forKey: .dateOfBirth)
        self.nationality = try container.decode(String.self, forKey: .nationality)
        self.shirtNumber = try container.decode(Int.self, forKey: .shirtNumber)
        self.marketValue = try container.decode(Int.self, forKey: .marketValue)
    }
}



/**
 "id": 60123,
 "firstName": "Sebastián",
 "lastName": "Battaglia",
 "name": "Sebastián Battaglia",
 "dateOfBirth": "1980-11-08",
 "nationality": "Argentina",
 "contract": {
 "start": "2021-08",
 "until": "2022-12"
 }
 */
struct Coach: Identifiable, Hashable, Decodable {
    var id: Int
    var firstName: String
    var lastName: String
    var name: String
    var dateOfBirth: String
    var nationality: String
    //omitt contract dates for now
    
    enum CodingKeys: String, CodingKey {
        case id
        case firstName
        case lastName
        case name
        case dateOfBirth
        case nationality
    }
    
    init(from decoder: any Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.id = try container.decode(Int.self, forKey: .id)
        self.firstName = try container.decode(String.self, forKey: .firstName)
        self.lastName = try container.decode(String.self, forKey: .lastName)
        self.name = try container.decode(String.self, forKey: .name)
        self.dateOfBirth = try container.decode(String.self, forKey: .dateOfBirth)
        self.nationality = try container.decode(String.self, forKey: .nationality)
    }
    
    init() {
        self.id = 0
        self.firstName = ""
        self.lastName = ""
        self.name = ""
        self.dateOfBirth = ""
        self.nationality = ""
    }
}

/**
 {
 "id": 2152,
 "name": "Copa Libertadores",
 "code": "CLI",
 "type": "CUP",
 "emblem": "https://crests.football-data.org/CLI.svg"
 }
 */
struct Competition: Identifiable, Hashable, Decodable {
    var id: Int
    var name: String
    var code: String
    var type: String
    var emblem: UIImage
    
    enum CodingKeys: String, CodingKey {
        case id
        case name
        case code
        case type
        case emblemURL = "emblem"
    }
    
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        self.id = try values.decode(Int.self, forKey: .id)
        self.name = try values.decode(String.self, forKey: .name)
        self.code = try values.decode(String.self, forKey: .code)
        self.type = try values.decode(String.self, forKey: .type)
        
        // convert emblemURL to UIImage
        let emblemURL = try values.decode(URL.self, forKey: .emblemURL)
        let imageData = try Data(contentsOf: emblemURL)
        self.emblem = UIImage(data: imageData)!
    }
}

1

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật