Path: blob/main/SignalServiceKit/Network/API/Giphy/GiphyAPI.swift
1 views
//
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
public enum GiphyAPI {
// MARK: - Properties
private static let kGiphyBaseURL = URL(string: "https://api.giphy.com/")!
private static func buildURLSession() -> OWSURLSessionProtocol {
let configuration = ContentProxy.sessionConfiguration()
// Don't use any caching to protect privacy of these requests.
configuration.urlCache = nil
configuration.requestCachePolicy = .reloadIgnoringCacheData
return OWSURLSession(
baseUrl: kGiphyBaseURL,
securityPolicy: OWSURLSession.defaultSecurityPolicy,
configuration: configuration,
)
}
// MARK: Search
// This is the Signal iOS API key.
private static let kGiphyApiKey = "ZsUpUm2L6cVbvei347EQNp7HrROjbOdc"
private static let kGiphyPageSize = 100
public static func trending() async throws -> [GiphyImageInfo] {
try await fetch(urlPath: "/v1/gifs/trending", queryItems: [])
}
public static func search(query: String) async throws -> [GiphyImageInfo] {
try await fetch(urlPath: "/v1/gifs/search", queryItems: [
URLQueryItem(name: "q", value: query),
URLQueryItem(name: "offset", value: "0"),
])
}
private static func fetch(urlPath: String, queryItems: [URLQueryItem]) async throws -> [GiphyImageInfo] {
var urlComponents = URLComponents()
urlComponents.path = urlPath
let baseQueryItems: [URLQueryItem] = [
URLQueryItem(name: "api_key", value: kGiphyApiKey),
URLQueryItem(name: "limit", value: "\(kGiphyPageSize)"),
]
urlComponents.queryItems = baseQueryItems + queryItems
guard let urlString = urlComponents.string else {
throw OWSAssertionError("Could not encode query.")
}
let urlSession = buildURLSession()
do {
var request = try urlSession.endpoint.buildRequest(urlString, method: .get)
guard ContentProxy.configureProxiedRequest(request: &request) else {
throw OWSAssertionError("Invalid URL")
}
let response = try await urlSession.performRequest(request: request, ignoreAppExpiry: false)
guard let responseDict = response.responseBodyDict else {
throw OWSAssertionError("Missing or invalid JSON")
}
Logger.info("Request succeeded.")
guard let imageInfos = self.parseGiphyImages(responseDict: responseDict) else {
throw OWSAssertionError("unable to parse trending images")
}
return imageInfos
} catch {
Logger.warn("Request failed: \(error.shortDescription)")
throw error
}
}
// MARK: Parse API Responses
private static func parseGiphyImages(responseDict: [String: Any]) -> [GiphyImageInfo]? {
guard let imageDicts = responseDict["data"] as? [[String: Any]] else {
Logger.error("Invalid response data.")
return nil
}
return imageDicts.compactMap { imageDict in
GiphyImageInfo(parsing: imageDict)
}
}
}