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
RxSwiftで作るAPIラッパーのパターン
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Yusuke Murata
August 19, 2016
Programming
1.9k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
RxSwiftで作るAPIラッパーのパターン
第2回RxSwift勉強会 @ Sansan
http://connpass.com/event/35014/
Yusuke Murata
August 19, 2016
More Decks by Yusuke Murata
See All by Yusuke Murata
reduxを使わずにreact+railsする
muratayusuke
3
4.1k
Other Decks in Programming
See All in Programming
メールのエイリアス機能を履き違えない
isshinfunada
0
250
まだ間に合う!今年の夏こそSchemeのマクロ展開器を完全理解!
omasanori
0
430
Jindong: Introducing Declarative Haptics in Compose Multiplatform
l2hyunwoo
0
130
今さら聞けない .NET CLI
htkym
0
210
レビュー履歴をAIに食わせて、 Compose移行を加速するs
shihochan
0
200
使いながら育てる Claude Code — 開発フローの1コマンド化 × 繰り返し指摘の自動仕組み化
shiki_kakaku
0
1.9k
片田舎のおっさん、 Swift Buildのダイアモンド問題解決の不具合修正PRを出すが、解決方法がキャッシュをしないようにすることであり、ビルド時間が伸びると言われてマージされないので高速化もする/swiftbuild
yimajo
0
270
思考垂れ流し開発 ~音声入力 × AIエージェント × 開発ハーネスによる試行錯誤~
npostring
0
110
freeeにおけるEvalsの実践例の紹介
freee
PRO
0
140
jsmini JavaScript Engine を作ってみた話
yosuke_furukawa
PRO
0
350
いまどきの Codex で開発する visionOS アプリの開発スタイルについて
karad
0
160
freee が目指す データ マネジメント戦略 AI-Ready 時代を支える 攻めのガバナンスとは
freee
PRO
0
460
Featured
See All Featured
How To Speak Unicorn (iThemes Webinar)
marktimemedia
1
550
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
210
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
500
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
710
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.3k
We Are The Robots
honzajavorek
0
310
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.4k
A Soul's Torment
seathinner
6
3.5k
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
430
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
480
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.7k
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
57k
Transcript
3Y4XJGUͰ࡞Δ"1*ϥούʔͷύλʔϯ ݄ଜా༎հ
ࣗݾհ #&45*OD$50ଜా༎հ !NVSBUBZVTVLF IUUQNVSBUBZVTVLFDPN ɹژେֶܦࡁֶ෦ଔۀ ʙָఱͷਓࣄʢ৽ଔ࠾༻ʣ ʙָఱͷΤϯδχΞ ʙ#&45גࣜձࣾ$50 ˞3Y4XJGUྺϲ݄
ɹ 3YܥϥΠϒϥϦॳ ུྺ
࡞͍ͬͯΔαʔϏεʢձࣾʣ IUUQTUSBWFMFSTBJ
࡞͍ͬͯΔαʔϏεʢݸਓʣ IUUQTCJUMZNVMUJUFBN
5SBWFMFSTͷߏʢ8&#ʣ ϒϥβ 3BJMT "1* ɾඳը3FBDU ɾ"KBYͰ3BJMTͷ"1*Λୟ͘ ɾ1SPNJTFͰෳͷ"1*ίʔϧΛνΣʔϯ͢Δ
5SBWFMFSTͷߏʢΞϓϦʣ ΞϓϦ 3BJMT "1* ɾඳը4UPSZCPBSE ίʔυ ɾ"MBNPGJSFͰ3BJMTͷ"1*Λୟ͘ ɾ3Y4XJGU 3Y"MBNPGJSF
Ͱෳͷ"1*ίʔϧΛ νΣʔϯ͢Δ
"1*ͷύλʔϯ ޭPSࣦഊ͚ͩΘ͔Ε͍͍ ޭ͚͕ͨ࣌ͩ͠ཉ͍͠ ࣦഊ͚ͨ࣌ͩ͠Τϥʔ༰͕ཉ͍͠ ޭͨ͠Β͕ɺࣦഊͨ͠ΒΤϥʔ༰͕ཉ͍͠
"1*ͷύλʔϯ ޭPSࣦഊ͚ͩΘ͔Ε͍͍ ޭ͚͕ͨ࣌ͩ͠ཉ͍͠ ࣦഊ͚ͨ࣌ͩ͠Τϥʔ༰͕ཉ͍͠ ޭͨ͠Β͕ɺࣦഊͨ͠ΒΤϥʔ༰͕ཉ͍͠
ޭPSࣦഊ͚ͩΘ͔Ε͍͍ ྫɿϩάΠϯ"1* ɾϩάΠϯ͕ඞཁͳॲཧͷલʹϩάΠϯը໘Λදࣔ ɾϝʔϧΞυϨεͱύεϫʔυΛ1045͢Δ ɾޭͨ͠ΒϩάΠϯը໘Λดͯ͡ଓ͖ͷॲཧΛ͢Δ ɾࣦഊͨ͠ΒݻఆͷจݴΛදࣔ ɹʢϝʔϧΞυϨεͱύεϫʔυΛ֬͝ೝ͍ͩ͘͞తͳʣ
ޭPSࣦഊ͚ͩΘ͔Ε͍͍ func signIn(email: String, password: String) -> Driver<Bool> {
let params = ["user[email]": email, "user[password]": password] return rx_responseJSON(.POST, endPoint: .SignIn, parameters: params) .map { success, _ in success } .asDriver(onErrorJustReturn: false) } ྫɿϩάΠϯ"1*
ޭ͚͕ͨ࣌ͩ͠ཉ͍͠ private func rx_responseJSON(method: Alamofire.Method, url: String, parameters: [String:
AnyObject]? = nil, encoding: ParameterEncoding = .URL, headers: [String: String]? = nil) -> Observable<(Bool, AnyObject?)> { return manager .rx_responseJSON(method, url, parameters: parameters, ɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹencoding: encoding, headers: headers) .map { response, json in if 200 ..< 300 ~= response.statusCode { return (true, json) } else { return (false, json) } } } SY@SFTQPOTF+40/ͷத
ޭPSࣦഊ͚ͩΘ͔Ε͍͍ func signIn(email: String, password: String) -> Driver<Bool> {
let params = ["user[email]": email, "user[password]": password] return rx_responseJSON(.POST, endPoint: .SignIn, parameters: params) .map { success, _ in success } .asDriver(onErrorJustReturn: false) } ྫɿϩάΠϯ"1* ɾجຊ%SJWFSΛฦ͢ ɹˠඇಉظͷ6*ૢ࡞ʹ͍ͬͯ͜ ɹɹ$BO`UFSSPSPVU ɹɹ0CTFSWFPONBJOTDIFEVMFS ɹɹ4IBSJOHTJEFFGGFDUT ɹɹIUUQTHJUIVCDPN3FBDUJWF93Y4XJGUCMPCNBTUFS%PDVNFOUBUJPO6OJUTNEESJWFSVOJU
ޭPSࣦഊ͚ͩΘ͔Ε͍͍ func signIn(email: String, password: String) -> Driver<Bool> {
let params = ["user[email]": email, "user[password]": password] return rx_responseJSON(.POST, endPoint: .SignIn, parameters: params) .map { success, _ in success } .asDriver(onErrorJustReturn: false) } ྫɿϩάΠϯ"1* ɾܕ#PPMʹ͢Δ ɹˠޭ͔ࣦഊ͔ͷ ɹˠ0QUJPOBMͰ͋Δඞཁͳ͍
ޭPSࣦഊ͚ͩΘ͔Ε͍͍ func signIn(email: String, password: String) -> Driver<Bool> {
let params = ["user[email]": email, "user[password]": password] return rx_responseJSON(.POST, endPoint: .SignIn, parameters: params) .map { success, _ in success } .asDriver(onErrorJustReturn: false) } ྫɿϩάΠϯ"1* ɾͳͷͰࣦഊͨ͠ΒGBMTFฦ͠ͱ͚͍͍
ޭPSࣦഊ͚ͩΘ͔Ε͍͍ let input = Driver.combineLatest(email, password) { ($0, $1)
} loginButton.rx_tap.asDriver() .withLatestFrom(input) .flatMapLatest { mail, password in api.signIn(mail, password: password) } .driveNext { [unowned self] success in if success { self.dismissViewControllerAnimated(true, completion: nil) } else { // show error message } } .addDisposableTo(disposeBag) ྫɿϩάΠϯ"1* ɾ͏ଆʢ6*7JFXªPOUSPMMFSʣ͜Μͳײ͡
"1*ͷύλʔϯ ޭPSࣦഊ͚ͩΘ͔Ε͍͍ ޭ͚͕ͨ࣌ͩ͠ཉ͍͠ ࣦഊ͚ͨ࣌ͩ͠Τϥʔ༰͕ཉ͍͠ ޭͨ͠Β͕ɺࣦഊͨ͠ΒΤϥʔ༰͕ཉ͍͠
ޭ͚͕ͨ࣌ͩ͠ཉ͍͠ ྫɿϢʔβʔใ ɾઃఆը໘ͰϩάΠϯதͷϢʔβʔͷใΛද͍ࣔͨ͠ ɾ"1*͕ޭͨ͠ΒϨεϙϯε༰Λදࣔ ɾࣦഊͨ͠ΒϩάΠϯϘλϯΛදࣔʢະϩάΠϯѻ͍ʣ
ޭ͚͕ͨ࣌ͩ͠ཉ͍͠ func fetchUserInfo() -> Driver<User?> { return rx_responseJSON(.GET, endPoint:
.Users) .map { success, json in if success { guard let json = json as? [String: AnyObject] else { throw apiError("User parse error") } return try User(json: json) } else { return nil } } .asDriver(onErrorJustReturn: nil) } ྫɿϢʔβʔใ
ޭ͚͕ͨ࣌ͩ͠ཉ͍͠ func fetchUserInfo() -> Driver<User?> { return rx_responseJSON(.GET, endPoint:
.Users) .map { success, json in if success { guard let json = json as? [String: AnyObject] else { throw apiError("User parse error") } return try User(json: json) } else { return nil } } .asDriver(onErrorJustReturn: nil) } ྫɿϢʔβʔใ ɾཉ͍͠σʔλͷܕΛࢦఆ
ޭ͚͕ͨ࣌ͩ͠ཉ͍͠ func fetchUserInfo() -> Driver<User?> { return rx_responseJSON(.GET, endPoint:
.Users) .map { success, json in if success { guard let json = json as? [String: AnyObject] else { throw apiError("User parse error") } return try User(json: json) } else { return nil } } .asDriver(onErrorJustReturn: nil) } ྫɿϢʔβʔใ ɾޭ࣌ཉ͍͠ܕͷσʔλΛฦ͢
ޭ͚͕ͨ࣌ͩ͠ཉ͍͠ func fetchUserInfo() -> Driver<User?> { return rx_responseJSON(.GET, endPoint:
.Users) .map { success, json in if success { guard let json = json as? [String: AnyObject] else { throw apiError("User parse error") } return try User(json: json) } else { return nil } } .asDriver(onErrorJustReturn: nil) } ྫɿϢʔβʔใ ɾ0QUJPOBMʹͯ͠ɺࣦഊͳΒOJMΛฦ͢
ޭ͚͕ͨ࣌ͩ͠ཉ͍͠ api.fetchUserInfo() .driveNext { [unowned self] (user: User?) in
self.user = user } .addDisposableTo(disposeBag) ྫɿϢʔβʔใ ɾ͏ଆʢ6*7JFXªPOUSPMMFSʣ͜Μͳײ͡
"1*ͷύλʔϯ ޭPSࣦഊ͚ͩΘ͔Ε͍͍ ޭ͚͕ͨ࣌ͩ͠ཉ͍͠ ࣦഊ͚ͨ࣌ͩ͠Τϥʔ༰͕ཉ͍͠ ޭͨ͠Β͕ɺࣦഊͨ͠ΒΤϥʔ༰͕ཉ͍͠
ࣦഊ͚ͨ࣌ͩ͠Τϥʔ༰͕ཉ͍͠ ྫɿϢʔβʔొ ɾϩάΠϯը໘ͱಉ͡γνϡΤʔγϣϯ ɾϩάΠϯ͢Δ͔৽نొ͢Δ͔ΛλϒͰΓସ͑Δ ɾޭͨ͠ΒϩάΠϯը໘Λดͯ͡ଓ͖ͷॲཧ ɾࣦഊͨ͠ΒԿ͕͔͋Μ͔ͷΤϥʔ༰Λදࣔ
ࣦഊ͚ͨ࣌ͩ͠Τϥʔ༰͕ཉ͍͠ func signUp(email: String, password: String, passwordConfirm: String, firstName:
String, lastName: String) -> Driver<(Bool, [String])> { let params = [ "user[email]": email, "user[password]": password, "user[password_confirmation]": passwordConfirm, "user[first_name]": firstName, "user[last_name]": lastName ] return rx_responseJSON(.POST, endPoint: .Users, parameters: params) .map { success, json in return (success, parseJSON(json)) } .asDriver(onErrorJustReturn: (false, [])) } ྫɿϢʔβʔొ
ࣦഊ͚ͨ࣌ͩ͠Τϥʔ༰͕ཉ͍͠ func signUp(email: String, password: String, passwordConfirm: String, firstName:
String, lastName: String) -> Driver<(Bool, [String])> { let params = [ "user[email]": email, "user[password]": password, "user[password_confirmation]": passwordConfirm, "user[first_name]": firstName, "user[last_name]": lastName ] return rx_responseJSON(.POST, endPoint: .Users, parameters: params) .map { success, json in return (success, parseJSON(json)) } .asDriver(onErrorJustReturn: (false, [])) } ྫɿϢʔβʔొ ɾޭͨ͠ΒUSVF͚ͩฦͬͯ͘Ε͍͍
ࣦഊ͚ͨ࣌ͩ͠Τϥʔ༰͕ཉ͍͠ func signUp(email: String, password: String, passwordConfirm: String, firstName:
String, lastName: String) -> Driver<(Bool, [String])> { let params = [ "user[email]": email, "user[password]": password, "user[password_confirmation]": passwordConfirm, "user[first_name]": firstName, "user[last_name]": lastName ] return rx_responseJSON(.POST, endPoint: .Users, parameters: params) .map { success, json in return (success, parseJSON(json)) } .asDriver(onErrorJustReturn: (false, [])) } ྫɿϢʔβʔొ ɾࣦഊͷ༰จࣈྻͷྻͰฦ͢ ɹˠϝʔϧΞυϨεΛೖྗ͍ͯͩ͘͠͞ ɹɹύεϫʔυΛೖྗ͍ͯͩ͘͠͞FUD
ࣦഊ͚ͨ࣌ͩ͠Τϥʔ༰͕ཉ͍͠ signupButton.rx_tap.asDriver() .withLatestFrom(input) .flatMapLatest { api.signUp($0.0, password: $0.1, passwordConfirm:
$0.2, firstName: $0.3, lastName: $0.4) } .driveNext { [unowned self] success, errors in self.signupErrorLabel.hidden = success self.signupErrorLabel.text = errors.joinWithSeparator("\n") } .addDisposableTo(disposeBag) ྫɿϢʔβʔొ ɾ͏ଆʢ6*7JFXªPOUSPMMFSʣ͜Μͳײ͡
"1*ͷύλʔϯ ޭPSࣦഊ͚ͩΘ͔Ε͍͍ ޭ͚͕ͨ࣌ͩ͠ཉ͍͠ ࣦഊ͚ͨ࣌ͩ͠Τϥʔ༰͕ཉ͍͠ ޭͨ͠Β͕ɺࣦഊͨ͠ΒΤϥʔ༰͕ཉ͍͠
ޭͨ͠Β͕ɺࣦഊͨ͠ΒΤϥʔ༰͕ཉ͍͠ func hoge(fuga: String) -> Driver<(Piyo?, [String])> { let
params = ["fuga": fuga] return rx_responseJSON(.POST, endPoint: .Hoge, parameters: params) .map { success, json in if success { return (Piyo.parseJSON(json), []) } else { return (nil, parseJSON(json)) } } .asDriver(onErrorJustReturn: (nil, [])) } ྫɿʁʁʁ
ޭͨ͠Β͕ɺࣦഊͨ͠ΒΤϥʔ༰͕ཉ͍͠ func hoge(fuga: String) -> Driver<(Piyo?, [String])> { let
params = ["fuga": fuga] return rx_responseJSON(.POST, endPoint: .Hoge, parameters: params) .map { success, json in if success { return (Piyo.parseJSON(json), []) } else { return (nil, parseJSON(json)) } } .asDriver(onErrorJustReturn: (nil, [])) } ྫɿʁʁʁ ɾͱͷΈ߹Θͤ
ޭͨ͠Β͕ɺࣦഊͨ͠ΒΤϥʔ༰͕ཉ͍͠ func hoge(fuga: String) -> Driver<(Piyo?, [String])> { let
params = ["fuga": fuga] return rx_responseJSON(.POST, endPoint: .Hoge, parameters: params) .map { success, json in if success { return (Piyo.parseJSON(json), []) } else { return (nil, parseJSON(json)) } } .asDriver(onErrorJustReturn: (nil, [])) } ྫɿʁʁʁ ɾCPEZͷKTPOɺޭͯͨ͠Βཉ͔ͬͨ͠
ޭͨ͠Β͕ɺࣦഊͨ͠ΒΤϥʔ༰͕ཉ͍͠ func hoge(fuga: String) -> Driver<(Piyo?, [String])> { let
params = ["fuga": fuga] return rx_responseJSON(.POST, endPoint: .Hoge, parameters: params) .map { success, json in if success { return (Piyo.parseJSON(json), []) } else { return (nil, parseJSON(json)) } } .asDriver(onErrorJustReturn: (nil, [])) } ྫɿʁʁʁ ɾCPEZͷKTPOɺࣦഊͯͨ͠ΒΤϥʔ༰
"1*ͷύλʔϯ ޭPSࣦഊ͚ͩΘ͔Ε͍͍ ޭ͚͕ͨ࣌ͩ͠ཉ͍͠ ࣦഊ͚ͨ࣌ͩ͠Τϥʔ༰͕ཉ͍͠ ޭͨ͠Β͕ɺࣦഊͨ͠ΒΤϥʔ༰͕ཉ͍͠
ΈͲ͜Ζ ɾશ෦ʹ౷Ұͨ͠ํ͕͍͍ʁ ɹˠ౷Ұͨ͠ํ͕Θ͔Γ͍͢ʁ ɹɹ౷Ұͨ͠ΒδΣωϦΫεͰ៉ྷʹॻ͚Δ͔ʁ ɹɹͰඞཁ࠷ݶͷใ͚ͩฦͨ͠ํ͕͍͍͢ʁ
·ͱΊ ɾ͋͘·Ͱ͜ͷΞϓϦͰ༗ޮͳͭͷཧͷํ ɾ͜ͷͭͷྨͰશ͕ͯ͏·͍͘͘Θ͚Ͱͳ͍͔ ɾ͑ͦ͏ͳ࣌ͬͯΈͯͶ
ࢀߟʹͳͬͨϖʔδ ɾʲ༁ʳ͋ͳ͕ͨٻΊ͍ͯͨϦΞΫςΟϒϓϩάϥϛϯάೖ ɾຊՈͷ(FUUJOH4UBSUFE ɾຊՈͷ6OJUTϖʔδ ɾຊՈͷ3Y&YBNQMF ɾ3Yͷ)PUͱ$PMEʹ͍ͭͯ
࠷ޙʹ ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ