Hello,
I am learning to use Swift and am trying to request data from the USDA Food Data Central REST API. The problem I am having is that when I try to parse the response, the 'data' object can't be read. It's not nil (tested for that) and using .count, it seems like there is data there (27531 bytes). I just can't get it to pass through the "let data = data" command.
I format the request and send it off to the API without problems, and I can read the 'response' object (there is not an 'error' object). And if I print the URLRequest.description and copy and paste it into Safari, I get a page of JSON content back (so I know the request is formatted correctly and works with the API.) I also know form the response code (200) that the API says it is successfully sending.
I also found that the response says the data is encoded in gzip. I set the "Accept-Encoding" to "identity", but that didn't solve the problem.
Any idea why this might be happening? I have been working on this for 3 days now and am hoping someone can help me figure it out.
The code is shown below (sorry for the ugly listing, I have never posted here before and can't figure out how to paste in a well-formatted code sample from Xcode...):
let API_Key: String = "48oWHEcKXeCZuuh9SGqHfhn8ttL3HcWjTDZn4gmo"
let fdcFoodItemSearchKeywords: String = "apple%20fuji"
let fdcResourceString = "https://api.nal.usda.gov/fdc/v1/foods/search?api_key=\(API_Key)&query=\(fdcFoodItemSearchKeywords)&dataType=Foundation"
guard let fdcResourceURL = URL(string: fdcResourceString) else {
print("Invalid URL")
return
}
var request = URLRequest(url: fdcResourceURL)
request.addValue("application/json", forHTTPHeaderField: "Accept")
// request.addValue("identity", forHTTPHeaderField: "Accept-Encoding")
request.httpMethod = "GET"
print("The request variable = \(request.description)")
print("The request variable http Header is: \(String(describing: request.allHTTPHeaderFields))")
URLSession.shared.dataTask(with: request) { data, response, error in
print("The data has \(String(describing: data?.count)) bytes and is: \n")
debugPrint(data ?? "Can't print data")
print("The response is: \n")
debugPrint(response ?? "Can't print response")
if let data = data {
if let decodedResponse = try? JSONDecoder().decode(FDCResponse.self, from: data) {
DispatchQueue.main.async {
self.FDCResults = decodedResponse.FDCResults
}
return
}
}
print("FDC Data Fetch Failed: \(error?.localizedDescription ?? "Unknown error")")
print(fdcResourceURL.description)
}.resume()
Post
Replies
Boosts
Views
Activity
I am using a Combine URLSession to pull data from the Food Data Central API and the Data I am receiving is not being decoded with the JSON decoder. I know the Data is being received because I use the String(data:encoding: .utf8) as a debug print and I can see the downloaded data correctly in the console. I get an error message after the .decode completion failure that says "The data couldn't be read because it isn't in the correct format."
I am guessing I have to add something like the "encoder: utf8" statement in the .decode function. Or maybe transform the data in the .tryMap closure before returning. But I have searched the documentation and other sources and have not found anywhere that discusses this.
I am a fairly new to Swift (my first real app), I am hoping someone more-experienced can point me in the right direction. My code is as follows:
private func fdcSearch(searchFor searchText: String) {
let query = "https://api.nal.usda.gov/fdc/v1/foods/search?api_key=***&query=+Apple%20+Fuji"
let searchURL = "https://api.nal.usda.gov/fdc/v1/foods/search?"
let searchQuery = "&query="+searchString
print(searchURL+devData.apiKey+searchQuery)
// guard let url = URL(string: "https://api.nal.usda.gov/fdc/v1/foods/search?api_key=***&query=AppleFuji") else {
guard let url = URL(string: searchURL+devData.apiKey+searchQuery) else {
print("Guard error on url assignment") // debug statement
return
}
print("In fdcSearch") // debug statement
fdcSearchSubscription = URLSession.shared.dataTaskPublisher(for: url)
.subscribe(on: DispatchQueue.global(qos: .default))
.tryMap { (output) -> Data in
guard let response = output.response as? HTTPURLResponse, response.statusCode >= 200 && response.statusCode < 300 else {
print("bad server response") // debug statement
throw URLError(.badServerResponse)
}
print("got output") // debug statement
if let dataString = String(data: output.data, encoding: .utf8) { // debug statement
print("got dataString: \n\(dataString)") // debug statement
} // debug statement
return output.data
}
.receive(on: DispatchQueue.main)
.decode(type: [FDCFoodItem].self, decoder: JSONDecoder())
.sink { (completion) in
switch completion {
case .finished:
print("Completion finished") // debug statement
break
case .failure(let error):
print("Completion failed") // debug statement
print(error.localizedDescription)
}
} receiveValue: { [weak self] (returnedFoods) in
self?.foods = returnedFoods
print("returnedFoods: \(returnedFoods)") // debug statement
print("self?.foods: \(String(describing: self?.foods))") // debug statement
}
}
Any suggestions on how to handle this?
Is there something I need to do to enable the use of color literals in a SwiftUI View? When I type “.fill(Color(Color Literal”…, it does not recognize it. I can get to the literal picker through the assets catalog, but not from any other method. I have tried copying code from the online demos and it doesn’t work, says it isn’t recognized. I am using XCode 5.5 and targeting ios14.