// The Swift Programming Language // https://docs.swift.org/swift-book import Foundation public final class USDA_FDC_Client { var version = 1 var baseURL: URL { URL(string: "https://api.nal.usda.gov/fdc/v\(version)")! } public init() {} public var apiKey: String = "" public func getFood(_ foodCriteria: FoodCriteria) async throws -> AbridgedFoodItem { var endpoint = baseURL.appendingPathComponent("/food/\(foodCriteria.fdcId)") endpoint.append(queryItems: [.init(name: "api_key", value: apiKey)]) // if criteria != nil { // for (key, value) in Mirror(reflecting: criteria!).children { // if value as Any? != nil { // if let l = value as? [String] { // endpoint.append(queryItems: [.init(name: key!, value: String(describing: l.joined(separator: ",")))]) // } // endpoint.append(queryItems: [.init(name: key!, value: String(describing: value))]) // } // } // } print(endpoint) var request = URLRequest(url: endpoint) request.setValue("application/json", forHTTPHeaderField: "accept") let (data, response) = try await URLSession.shared.data(for: request) guard let response = response as? HTTPURLResponse, response.statusCode == 200 else { throw FDCError.invalidResponse } do { return try JSONDecoder().decode(AbridgedFoodItem.self, from: data) } catch { throw error } } // TODO: public func getFoods(_ foodsCriteria: FoodsCriteria) async throws -> [AbridgedFoodItem] { var endpoint = baseURL.appendingPathComponent("/food") endpoint.append(queryItems: [.init(name: "api_key", value: apiKey)]) // if criteria != nil { // for (key, value) in Mirror(reflecting: criteria!).children { // if value as Any? != nil { // if let l = value as? [String] { // endpoint.append(queryItems: [.init(name: key!, value: String(describing: l.joined(separator: ",")))]) // } // endpoint.append(queryItems: [.init(name: key!, value: String(describing: value))]) // } // } // } print(endpoint) var request = URLRequest(url: endpoint) request.setValue("application/json", forHTTPHeaderField: "accept") let (data, response) = try await URLSession.shared.data(for: request) guard let response = response as? HTTPURLResponse, response.statusCode == 200 else { throw FDCError.invalidResponse } do { return try JSONDecoder().decode([AbridgedFoodItem].self, from: data) } catch { throw error } } public func getFoodsSearch(_ search: FoodSearchCriteria) async throws -> SearchResult { var endpoint = baseURL.appendingPathComponent("/foods/search") endpoint.append(queryItems: [.init(name: "api_key", value: apiKey)]) endpoint.append(queryItems: [.init(name: "query", value: search.query)]) // if criteria != nil { // for (key, value) in Mirror(reflecting: criteria!).children { // if value as Any? != nil { // if let l = value as? [String] { // endpoint.append(queryItems: [.init(name: key!, value: String(describing: l.joined(separator: ",")))]) // } // endpoint.append(queryItems: [.init(name: key!, value: String(describing: value))]) // } // } // } print(endpoint) var request = URLRequest(url: endpoint) request.setValue("application/json", forHTTPHeaderField: "accept") let (data, response) = try await URLSession.shared.data(for: request) guard let response = response as? HTTPURLResponse, response.statusCode == 200 else { throw FDCError.invalidResponse } do { return try JSONDecoder().decode(SearchResult.self, from: data) } catch { throw error } } public func getFoodList(_: FoodListCriteria? = nil) async throws -> [AbridgedFoodItem] { var endpoint = baseURL.appendingPathComponent("/foods/list") endpoint.append(queryItems: [.init(name: "api_key", value: apiKey)]) // if criteria != nil { // for (key, value) in Mirror(reflecting: criteria!).children { // if value as Any? != nil { // if let l = value as? [String] { // endpoint.append(queryItems: [.init(name: key!, value: String(describing: l.joined(separator: ",")))]) // } // endpoint.append(queryItems: [.init(name: key!, value: String(describing: value))]) // } // } // } print(endpoint) var request = URLRequest(url: endpoint) request.setValue("application/json", forHTTPHeaderField: "accept") let (data, response) = try await URLSession.shared.data(for: request) guard let response = response as? HTTPURLResponse, response.statusCode == 200 else { throw FDCError.invalidResponse } do { return try JSONDecoder().decode([AbridgedFoodItem].self, from: data) } catch { throw error } } } public enum FDCError: Error { case invalidResponse }