😑 using search-a-licious API now...

This commit is contained in:
cdricms
2025-12-06 18:43:14 +01:00
parent 44420002c7
commit dd191b585d
7 changed files with 35 additions and 23 deletions

View File

@@ -9,7 +9,7 @@ extension KeyedDecodingContainer {
return nil
}
public func decodeStringOrInt(forKey key: Key) throws -> Int? {
public func decodeIntOrString(forKey key: Key) throws -> Int? {
if let intVal = try? decode(Int.self, forKey: key) {
return intVal
}
@@ -19,4 +19,14 @@ extension KeyedDecodingContainer {
return nil
}
public func decodeStringOrArray(forKey key: Key) throws -> String? {
if let arrayVal = try? decode([String].self, forKey: key) {
return arrayVal.joined(separator: ",")
}
if let stringVal = try? decode(String.self, forKey: key) {
return stringVal
}
return nil
}
}

View File

@@ -57,7 +57,7 @@ public actor OpenFoodFactsClient {
) async throws -> SearchResponseEnvelope {
guard
var components = URLComponents(
url: config.apiURL.appendingPathComponent("/search"),
url: config.searchURL,
resolvingAgainstBaseURL: true)
else {
throw OFFError.invalidURL
@@ -76,19 +76,19 @@ public actor OpenFoodFactsClient {
for param in parameters {
switch param {
case .query(let q):
queryItems.append(URLQueryItem(name: "search_terms", value: q))
case .tag(let tag, let value):
// V2 allows dynamic tags like `brands_tags=coca`
queryItems.append(
URLQueryItem(name: "\(tag.rawValue)_tags", value: value))
queryItems.append(URLQueryItem(name: "q", value: q))
// case .tag(let tag, let value):
// // V2 allows dynamic tags like `brands_tags=coca`
// queryItems.append(
// URLQueryItem(name: "\(tag.rawValue)_tags", value: value))
case .page(let p):
queryItems.append(URLQueryItem(name: "page", value: String(p)))
case .pageSize(let s):
queryItems.append(
URLQueryItem(name: "page_size", value: String(s)))
case .sort(let s):
queryItems.append(
URLQueryItem(name: "sort_by", value: s.rawValue))
// case .sort(let s):
// queryItems.append(
// URLQueryItem(name: "sort_by", value: s.rawValue))
}
}
@@ -140,11 +140,11 @@ public struct SearchResponseEnvelope: Sendable, Decodable {
public let count: Int
public let page: Int
public let pageSize: Int
public let products: [Product]
public let hits: [Product]
public let pageCount: Int
private enum CodingKeys: String, CodingKey {
case count, page, products
case count, page, hits
case pageSize = "page_size"
case pageCount = "page_count"
}

View File

@@ -4,6 +4,7 @@ public struct OpenFoodFactsConfig: Sendable {
public let baseURL: URL
public let userAgent: UserAgent
public let apiURL: URL
public let searchURL: URL
public struct UserAgent: CustomStringConvertible, Sendable {
public let appName: String
@@ -62,5 +63,6 @@ public struct OpenFoodFactsConfig: Sendable {
self.baseURL = environment.url
self.userAgent = userAgent
self.apiURL = self.baseURL.appendingPathComponent("/api/v2")
self.searchURL = URL(string: "https://search.openfoodfacts.org/search")!
}
}

View File

@@ -35,10 +35,10 @@ public struct NutriscoreData: Sendable, Codable {
isBeverage = try container.decodeIfPresent(
Int.self, forKey: .isBeverage)
isCheese = try container.decodeStringOrInt(forKey: .isCheese)
isWater = try container.decodeStringOrInt(forKey: .isWater)
isFat = try container.decodeStringOrInt(forKey: .isFat)
energy = try container.decodeStringOrInt(forKey: .energy)
isCheese = try container.decodeIntOrString(forKey: .isCheese)
isWater = try container.decodeIntOrString(forKey: .isWater)
isFat = try container.decodeIntOrString(forKey: .isFat)
energy = try container.decodeIntOrString(forKey: .energy)
}

View File

@@ -147,7 +147,7 @@ public struct Product: Codable, Sendable, Identifiable {
String.self, forKey: .productName)
genericName = try container.decodeIfPresent(
String.self, forKey: .genericName)
brands = try container.decodeIfPresent(String.self, forKey: .brands)
brands = try container.decodeStringOrArray(forKey: .brands)
brandsTags = try container.decodeIfPresent(
[String].self, forKey: .brandsTags)
quantity = try container.decodeIfPresent(String.self, forKey: .quantity)

View File

@@ -2,10 +2,10 @@ import Foundation
public enum SearchParameter: Sendable, Hashable {
case query(String)
case tag(tag: SearchTagType, value: String)
// case tag(tag: SearchTagType, value: String)
case page(Int)
case pageSize(Int)
case sort(SearchSort)
// case sort(SearchSort)
}
public enum SearchTagType: String, Sendable {

View File

@@ -35,15 +35,15 @@ final class OpenFoodFactsTests: XCTestCase {
func testSearch() async throws {
let response = try await client.search(
.query("chocolate"),
.tag(tag: .brands, value: "milka"),
// .tag(tag: .brands, value: "milka"),
.pageSize(5),
.sort(.popularity),
// .sort(.popularity),
)
let results = response.products
let results = response.hits
let jsonResults = try JSONEncoder().encode(results)
_ = jsonResults
try jsonResults.write(to: .init(filePath: "./jsonResults.json"))
XCTAssertFalse(results.isEmpty)
XCTAssertEqual(results.count, 5)