Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
RxSwiftで作るAPIラッパーのパターン
Search
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
まだ間に合う!今年の夏こそSchemeのマクロ展開器を完全理解!
omasanori
0
650
ハーネス設計入門 〜プロンプト、コンテキストの次〜
kinopeee
55
37k
初心者DevRelとして参加者だった私が、DevRel Talks!#2に登壇するまでにしてきたこと
sokohirai
0
360
AWS DevOps Agentで インシデント対応をAIに任せたい
honmarkhunt
7
2.7k
App Storeの外へ──日本のiOSサイドローディング入門 for iOSDC Japan 2026
yuukiw00w
0
140
thread_parallel_with_free-threaded_Python_and_NumPy.pdf
riku_sakamoto
0
260
Family mrubyの進捗
kishima
1
110
Laravelのアプリケーションをどこにデプロイするか #ツナギメオフライン.9
akase244
0
120
20260828_品質と開発生産性を両立させる、AI時代のE2Eテストの考え方
magicpod
0
180
{ Android | Kotlin } Gradle Plugin in 2026
ryunen344
1
300
フロントエンドUIフレームワークのこれまでとこれから
ssssota
4
2.1k
個人開発基盤をまるごとCloudflareに引っ越して爆速で総合的体験を向上させた話
tinykitten
0
140
Featured
See All Featured
Rails Girls Zürich Keynote
gr2m
96
14k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
270
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.6k
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
660
First, design no harm
axbom
PRO
2
1.3k
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1.1k
Discover your Explorer Soul
emna__ayadi
2
1.3k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2.1k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.3k
Designing for Performance
lara
611
70k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.6k
Making the Leap to Tech Lead
cromwellryan
135
10k
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ʹ͍ͭͯ
࠷ޙʹ ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ