GiphyApiManager.swift 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. //
  2. // GiphyApiManager.swift
  3. // LiveLikeGiphyChallenge
  4. //
  5. // Created by Ljupco Nastevski on 30.1.22.
  6. //
  7. import Foundation
  8. enum GiphyApiError: Error {
  9. case canceledByUser
  10. case requestFailed
  11. case decodingFailed
  12. }
  13. fileprivate struct RequestParamKeys {
  14. static let ApiKey = "api_key"
  15. static let QueryKey = "q"
  16. static let OffsetKey = "offset"
  17. static let LimitKey = "limit"
  18. }
  19. fileprivate struct Versions {
  20. static let v1 = "/v1"
  21. }
  22. fileprivate struct Endpoints {
  23. static let Gifs = Versions.v1 + "/gifs"
  24. static let Trending = Gifs + "/trending"
  25. static let Search = Gifs + "/search"
  26. }
  27. class GiphyApiManager {
  28. static let shared = GiphyApiManager()
  29. private var baseUrl = URLComponents(string: Constants.GiphyBaseUrl)!
  30. private let session = URLSession(configuration: .ephemeral, delegate: nil, delegateQueue: nil)
  31. // Last searchable task
  32. private var lastSearchableTask: URLSessionDataTask?
  33. init() {
  34. // Default query items
  35. baseUrl.queryItems = [
  36. URLQueryItem(name: RequestParamKeys.ApiKey, value: Constants.GiphyApiKey),
  37. URLQueryItem(name: RequestParamKeys.LimitKey, value: String(Constants.GiphyPaginationLimit))
  38. ]
  39. }
  40. func cancelLastSearchableTask() {
  41. lastSearchableTask?.cancel()
  42. lastSearchableTask = nil
  43. }
  44. func cancelDataTaskForUrl(url: URL) {
  45. session.getAllTasks { tasks in
  46. tasks.filter { $0.state == .running }.filter { $0.originalRequest?.url == url}.first?.cancel()
  47. }
  48. }
  49. func getTrendingGifs(offset: Int, completion: @escaping (Result<GiphyListResponse, Error>) -> Void) {
  50. let offset = URLQueryItem(name: RequestParamKeys.OffsetKey, value: String(offset))
  51. self.lastSearchableTask = self.getCodable(endpoint: Endpoints.Trending, queries: [offset], completion: completion)
  52. }
  53. func getSearchGifs(offset: Int, query: String, completion: @escaping (Result<GiphyListResponse, Error>) -> Void) {
  54. let offset = URLQueryItem(name: RequestParamKeys.OffsetKey, value: String(offset))
  55. let query = URLQueryItem(name: RequestParamKeys.QueryKey, value: query)
  56. self.lastSearchableTask = self.getCodable(endpoint: Endpoints.Search, queries: [offset, query], completion: completion)
  57. }
  58. func getData(url: URL, completion: @escaping (Data?) -> Void) -> URLSessionDataTask {
  59. let task = session.dataTask(with: url) { data, _ , _ in
  60. completion(data)
  61. }
  62. task.resume()
  63. return task
  64. }
  65. private func getCodable<U:Codable>(endpoint: String, queries: [URLQueryItem]? = nil, completion: @escaping (Result<U, Error>) -> Void) -> URLSessionDataTask {
  66. var fullUrlComponent = self.baseUrl
  67. if let queries = queries {
  68. fullUrlComponent.queryItems?.append(contentsOf: queries)
  69. }
  70. fullUrlComponent.path = endpoint
  71. let task = session.dataTask(with: fullUrlComponent.url!) { d, _, e in
  72. guard let data = d else { completion(.failure(e!)); return }
  73. do {
  74. let decoded = try JSONDecoder().decode(U.self, from: data)
  75. completion(.success(decoded))
  76. } catch {
  77. completion(.failure(GiphyApiError.decodingFailed))
  78. }
  79. }
  80. task.resume()
  81. return task
  82. }
  83. }