Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
実際書くと今まで聞いてきたものはだいたいこんな感じにかける。普段書くものでSwift3を書いていけば良いと思う #CodePiece #iphonekyoto
struct ProfileResponse: APIResponse {
let name: String
let age: Int
init(json: JSONObject) throws {
name = try json.get("name")
age = try json.get("age")
}
}
protocol APIEndpoint {
var url: URL { get }
var method: HTTPMethod { get }
var queryParameters: APIParameters? { get }
var headers: APIHeaders? { get }
associatedtype Response: APIResponse
}
protocol JSONDecodable {
init(json: JSONObject) throws
}
protocol APIResponse: JSONDecodable {
}
struct JSONObject {
private let dictionary: [String: Any]
init(dictionary: [String: Any]) {
self.dictionary = dictionary
}
}
enum JSONDecodeError: Error {
case missingRequiredKey(String)
case unexpectedType(key: String, expected: Any.Type, actual: Any.Type)
}
func get<T: JSONPrimitive>(_ key: String) throws -> T {
guard let value = dictionary[key] else {
throw JSONDecodeError.missingRequiredKey(key)
}
guard let typed = value as? T else {
throw JSONDecodeError.unexpectedType(
key: key,
expected: T.self,
actual: type(of: value))
}
return typed
}
enum HTTPMethod: String {
case GET
case HEAD
case POST
case PUT
case DELETE
}
typealias APIParameters = Dictionary<String, String?>
typealias APIHeaders = Dictionary<String, String>
fileprivate extension Dictionary {
var parameters: Dictionary {
return self
}
}
fileprivate extension APIEndpoint {
var request: URLRequest {
var urlComponents = URLComponents(
url: url,
resolvingAgainstBaseURL: true)!
urlComponents.queryItems = queryParameters?
.parameters.map(URLQueryItem.init)
var request = URLRequest(url: urlComponents.url!)
request.httpMethod = method.rawValue
request.allHTTPHeaderFields = headers
return request
}
}
struct APIClient {
let session: URLSession
}
enum APIResult<Response> {
case success(Response)
case failure(Error)
}
@discardableResult // 返り値不要なものは明示的に宣言する必要がある
func request<T: APIEndpoint>(
endpoint: T,
callback: @escaping ((APIResult<T.Response>) -> Void)) -> URLSessionTask { // 非同期実行するのでエスケーピングが必要
let task = session.dataTask(with: endpoint.request) { (data, response, error) in
if let error = error {
callback(.failure(error))
return
}
guard let data = data else {
callback(.failure(APIError.emptyBody))
return
}
do {
guard let dictionary = try JSONSerialization.jsonObject(with: data) as? [String: Any] else {
throw APIError.unexpectedResponse
}
let response = try T.Response(json: JSONObject(dictionary: dictionary))
callback(.success(response))
} catch {
callback(.failure(error))
}
}
task.resume()
return task
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment