Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
signalapp
GitHub Repository: signalapp/Signal-iOS
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)
        }
    }
}