Skip to content

Instantly share code, notes, and snippets.

@minsOne
Last active December 30, 2022 00:14
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save minsOne/4d60f94224010d701f6d8d9e49c684b4 to your computer and use it in GitHub Desktop.
Save minsOne/4d60f94224010d701f6d8d9e49c684b4 to your computer and use it in GitHub Desktop.
Network Abstract Layer
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
internal func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
GitHubAPI.Users(userName: "minsone").request(completion: { result in
print(result)
})
}
}
public struct EmptyParameter: NetworkAPIParameterable {}
public struct EmptyResponse: Codable {}
public extension GitHubAPI {
struct Users: NetworkAPIDefinition {
public let urlInfo: URLInfo
public let requestInfo: RequestInfo<EmptyParameter> = .init(method: .get)
public init(userName: String) {
self.urlInfo = .GitHubAPI(path: "/users/\(userName)")
}
public struct Response: Decodable {
let login: String
let id: Int
let node_id: String
let avatar_url: String
}
}
}
public enum GitHubAPI {}
public extension NetworkAPI {
enum Method: String {
case get = "GET"
case post = "POST"
}
}
public extension NetworkAPI {
struct RequestInfo<T: NetworkAPIParameterable> {
var method: Method
var headers: [String: String]?
var parameters: T?
public init(method: NetworkAPI.Method,
headers: [String : String]? = nil,
parameters: T? = nil) {
self.method = method
self.headers = headers
self.parameters = parameters
}
}
}
extension NetworkAPI.RequestInfo {
func requests(url: URL) -> URLRequest {
var request = URLRequest(url: url)
request.httpMethod = method.rawValue
request.httpBody = parameters?
.dictionary
.flatMap { try? JSONSerialization.data(withJSONObject: $0) }
headers.map {
request.allHTTPHeaderFields?.merge($0) { lhs, rhs in lhs }
}
return request
}
}
import Foundation
public extension NetworkAPI {
struct URLInfo {
let scheme: String
let host: String
let port: Int?
let path: String
let query: [String:String]?
public init(scheme: String = "https",
host: String,
port: Int? = nil,
path: String,
query: [String : String]? = nil) {
self.scheme = scheme
self.host = host
self.port = port
self.path = path
self.query = query
}
}
}
extension NetworkAPI.URLInfo {
var url: URL {
var components = URLComponents()
components.scheme = scheme
components.host = host
components.port = port
components.path = path
components.queryItems = query?.compactMap { URLQueryItem(name: $0.key, value: $0.value) }
guard let url = components.url else {
assertionFailure("URL 정보를 확인해주세요.")
return .init(string: "https://\(host)")!
}
return url
}
}
public enum NetworkAPI {}
public extension NetworkAPIDefinition {
func request(completion: @escaping ((Result<Response, Error>) -> Void)) {
let url = urlInfo.url
let request = requestInfo.requests(url: url)
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let dataTask = session.dataTask(with: request) { data, response, error in
guard let data = data else { return }
do {
let response = try JSONDecoder().decode(Response.self, from: data)
completion(.success(response))
} catch {
completion(.failure(error))
}
}
dataTask.resume()
}
}
public protocol NetworkAPIDefinition {
typealias URLInfo = NetworkAPI.URLInfo
typealias RequestInfo = NetworkAPI.RequestInfo
associatedtype Parameter: NetworkAPIParameterable
associatedtype Response: Decodable
var urlInfo: URLInfo { get }
var requestInfo: RequestInfo<Parameter> { get }
}
public protocol NetworkAPIParameterable: Encodable {
var dictionary: [String: Any]? { get }
}
public extension NetworkAPIParameterable {
var dictionary: [String: Any]? {
return (try? JSONEncoder().encode(self))
.flatMap { try? JSONSerialization.jsonObject(with: $0) as? [String: Any] }
}
}
public extension NetworkAPI.URLInfo {
static func GitHubAPI(path: String) -> Self {
Self.init(host: "api.github.com", path: path)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment