Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
APIKit
Search
M
October 21, 2017
Programming
0
100
APIKit
APIKitについての説明
M
October 21, 2017
Tweet
Share
More Decks by M
See All by M
Combine
mtsd
0
77
Swift 5.1 - Property Wrapper
mtsd
0
46
Swift 5.1
mtsd
0
39
Build Time Analyzer
mtsd
0
160
SafeArea
mtsd
0
58
URLProtocol
mtsd
0
70
Other Decks in Programming
See All in Programming
The Evolution of Enterprise Java with Jakarta EE 11 and Beyond
ivargrimstad
1
750
生成AIコーディングとの向き合い方、AIと共創するという考え方 / How to deal with generative AI coding and the concept of co-creating with AI
seike460
PRO
1
300
Perlで痩せる
yuukis
1
690
Elixir で IoT 開発、 Nerves なら簡単にできる!?
pojiro
1
140
セキュリティマネジャー廃止とクラウドネイティブ型サンドボックス活用
kazumura
1
180
赤裸々に公開。 TSKaigiのオフシーズン
takezoux2
0
130
Go1.25からのGOMAXPROCS
kuro_kurorrr
1
720
Enterprise Web App. Development (2): Version Control Tool Training Ver. 5.1
knakagawa
1
110
社内での開発コミュニティ活動とモジュラーモノリス標準化事例のご紹介/xPalette and Introduction of Modular monolith standardization
m4maruyama
1
120
Team topologies and the microservice architecture: a synergistic relationship
cer
PRO
0
650
Javaに鉄道指向プログラミング (Railway Oriented Pro gramming) のエッセンスを取り入れる/Bringing the Essence of Railway-Oriented Programming to Java
cocet33000
2
580
Passkeys for Java Developers
ynojima
3
860
Featured
See All Featured
Adopting Sorbet at Scale
ufuk
77
9.4k
Making Projects Easy
brettharned
116
6.2k
Designing Experiences People Love
moore
142
24k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
357
30k
How to Think Like a Performance Engineer
csswizardry
24
1.7k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
46
9.6k
Documentation Writing (for coders)
carmenintech
71
4.9k
It's Worth the Effort
3n
184
28k
Making the Leap to Tech Lead
cromwellryan
134
9.3k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
657
60k
Building a Scalable Design System with Sketch
lauravandoore
462
33k
Transcript
APIKit
これまで利用してきたネットワー クライブラリ NSURLConnection Three20(Facebook) ASIHTTPRequest AFNetworking Swift 発表 Alamo re
APIKit
Type-safe networking abstraction layer that associates request type with response
type. -- APIKit “ “
Why APIKit?
作者が日本人
これまでいくつかPR してきましたが
作者が日本人なら気軽に日本語とか で質問できそうじゃないですか...?
実際にいくつかAPIKit にissue 挙げたりやPR してま す。
本題
特徴 レスポンスはモデルオブジェクトとして受け取れ る。 個々 のエンドポイントに対する定義が1 箇所で済 む。 成功時にレスポンスを非オプショナルな値で受け 取れる。 また失敗時にエラー
を非オプショナルな 値で受け取れる。(Result(Either) 型) -- Appendix 参照
API 定義 デー タ形式(JSON, XML, …) 認証有無 ステー タスコー ド
エラー レスポンス エンドポイント HTTP メソッド リクエストパラメー タ レスポンス etc.
API 定義 デー タ形式(JSON, XML, …) 認証有無 ステー タスコー ド
エラー レスポンス エンドポイント HTTP メソッド リクエストパラメー タ レスポンス etc.
実装(v3.1.2)
API 仕様( 例) エンドポイント:https://api.example.com/users HTTP メソッド:Get リクエストパラメー タ:name - String
デー タ形式:JSON レスポンス: { "id": 1, "login": "starwars", "url": "https://example.com/starwars", }
レスポンス struct User { let id: Int let login: String
let url: String init(JSON: Any) throws { ... } }
リクエストの定義 Request プロトコルに適合させ、 最低5 つの項目を実装 する associatedtype Response var baseURL:
URL { get } var method: HTTPMethod { get } var path: String { get } func response(from object: Any, urlResponse: HTTPURLResponse) throws -> Response
struct UsersRequest: APIKit.Request { typealias Response = User var baseURL:
URL { return URL(string: "https://api.example.com")! } var method: APIKit.HTTPMethod { return .get } var path: String { return "/users" } func response(from object: Any, urlResponse: HTTPURLResponse ) throws -> User { return try User(JSON: object) } }
パラメー タの定義 struct UsersRequest: APIKit.Request { ... let name: String
var parameters: Any? { return ["name": name] } } 各パラメー タがType-safe UsersRequest(name: "starwars")
例えばAlamofire を利用した場合 /// public typealias Parameters = [String: Any] let
parameters: Parameters = ["name": "starwars"] Alamofire.request("https://api.example.com/users", parameters: parameters) [String: Any] のDictionary にパラメー タをセットする ので、 期待している型ではない値をセットできてしま う。 let parameters: Parameters = ["name": 2] ...
リクエストの呼び出し let request = UsersRequest(name: "starwars") Session.send(request) { result in
switch result { case .success(let response): print("response >>>", response) case .failure(let error): print("error >>>", error) } }
その他の機能
URL クエリー var queryParameters: [String: Any]? { get } HTTP
body パラメー タ var bodyParameters: BodyParameters? { get } HTTP ヘッダー var headerFields: [String: String] { get } Content-Type に紐づくパー サー var dataParser: DataParser { get }
リクエストのカスタマイズ func intercept(urlRequest: URLRequest) throws -> URLRequest レスポンスのカスタマイズ レスポンスヘッダー を取り出すなど
func intercept(object: Any, urlResponse: HTTPURLResponse) throws -> Any
JSON パー サと組み合わせる
APIKit + Himotoki
Himotoki.Decodable の適用 extension User: Himotoki.Decodable { static func decode(_ e:
Extractor) throws -> User { return try User( id: e <| "id", login: e <| "login", url: e <| "url" ) } }
型制約つきprotocol extensions extension APIKit.Request where Response: Himotoki.Decodable { func response(from
object: Any, urlResponse: HTTPURLResponse ) throws -> Response { return try decodeValue(object) } }
APIKit + Decodable (Codable of Swift4)
Decodable(Codable) の適用 struct User: Codable { let id: Int let
login: String let url: String } ちなみにCodable をextension で適用するとエラー にな る。 自分で public func encode(to encoder: Encoder) throws public init(from decoder: Decoder) throws を実装すれば問題ない。
APIKit 組み込みのJSON パー サの問題 APIKit に組み込みのJSON パー サJSONDataParser は内 部でJSONSerialization.jsonObject(with:options:)
を利 用しており、 戻り値はルー トオブジェクトが Dictionary やArray の値 // APIKit.JSONDataParser public func parse(data: Data) throws -> Any { ... return try JSONSerialization.jsonObject( with: data, options: readingOptions) }
上記でパー スされた値をモデルオブジェクトに変換す る際に利用される func response(from object: Any, urlResponse: HTTPURLResponse) throws
-> Response の引数object はDictionary やArray パー スされた値をモデルオブジェクトに変換する JSONDecoder#decode(_:from:) はData 型を引数にとる。 func decode<T>(_ type: T.Type, from data: Data) throws -> T where T : Decodable
Data 型を返すJSONDataParser を作成 DataParser プロトコル public protocol DataParser { var
contentType: String? { get } func parse(data: Data) throws -> Any }
Data 型の値をそのまま返すDataParser class JSONDataParser: APIKit.DataParser { var contentType: String? {
return "application/json" } func parse(data: Data) throws -> Any { return data } }
型制約つきprotocol extensions extension APIKit.Request where Response: Decodable { // 作成したJSONDataParser
をパー サとして適用する var dataParser: DataParser { return JSONDataParser() } func response(from object: Any, urlResponse: HTTPURLResponse ) throws -> Response { let decoder = JSONDecoder() return try decoder.decode(Response.self, from: object as! Data) } }
APIKit + Unbox
Unboxable の適用 extension User: Unboxable { init(unboxer: Unboxer) throws {
self.id = try unboxer.unbox(key: "id") self.login = try unboxer.unbox(key: "login") self.url = try unboxer.unbox(key: "url") } }
型制約つきprotocol extensions extension Request where Response: Unboxable { func response(from
object: Any, urlResponse: HTTPURLResponse) throws -> Response { guard let dictionary = object as? UnboxableDictionary throw ResponseError.unexpectedObject(object) } return try unbox(dictionary: dictionary) } } ※ JSON のルー トオブジェクトがオブジェクト値( ハッシュ) の 場合
APIKit + ObjectMapper
Mappable(ImmutableMappable) の適用 extension User: ImmutableMappable { init(map: Map) throws {
id = try map.value("id") login = try map.value("login") url = try map.value("url") } mutating func mapping(map: Map) { id >>> map["id"] login >>> map["login"] url >>> map["url"] } } ※ 定数プロパティの場合はMappable プロトコルは使えない ImmutableMappable はBeta
型制約つきprotocol extensions extension Request where Response: ImmutableMappable { func response(from
object: Any, urlResponse: HTTPURLResponse) throws -> Response { return try Response(JSONObject: object) } } ※ JSON のルー トオブジェクトがオブジェクト値( ハッシュ) の 場合
Demo
API 仕様( 例) エンドポイント:https://api.example.com/articles HTTP メソッド:Get リクエストパラメー タ:page - Int
デー タ形式:JSON レスポンス: { "id": 1, "title": "Star Wars", "created_at": "2000-01-01T00:00:00+00:00", }
まとめ API の仕様をRequest プロトコルに適合させていく のが、 Swift という言語に翻訳している感覚 各エンドポイントの定義が一箇所にまとまるので あとから把握しやすい 型制約付きprotocol
extensions を利用してモデル オブジェクトへのマッピングを簡潔にできる 作者が日本人だから質問への障壁が低い? 例えば日本語で質問したり
でもちゃんとがっつり英語でPR してます
Appendix 堅牢で使いやすいAPI クライアントをSwift で実装 したい APIKit でSwift らしいAPI クライアントを実装する #potatotips
でAPIKit を紹介してきた Swift 2 でのAPIKit + Himotoki APIKit: レスポンスに応じた独自のエラー を投げる