Slide 1

Slide 1 text

ϚΠΫϩαʔϏεࢦ޲ Rails API ։ൃΨΠυ ৿ ٱଠ࿠ (@qsona), גࣜձࣾFiNC 2017/8/5 ͗Μ͟Rubyձٞ01 @ΈΜͳͷ΢ΣσΟϯά ৿ ٱଠ࿠ (@qsona) גࣜձࣾFiNC 2017/8/5 ͗Μ͟Rubyձٞ01 @ΈΜͳͷ΢ΣσΟϯά

Slide 2

Slide 2 text

whoami • ৿ ٱଠ࿠ (΋Γ ͖Ύ͏ͨΖ͏) • Twitter: qsona (͖Ύ͏ͦͳ) • 2ࣇͷ෕Ͱ͢

Slide 3

Slide 3 text

whoami ϚΠΫϩαʔϏε࣌୅ʹ๋͙ɺRailsͰͷதن໛APIαʔό։ൃͷͨΊͷٕज़ߏ੒
 Ruby on Rails Advent Calendar 2016, qsona

Slide 4

Slide 4 text

whoami • 2013- Node.js ͰͷήʔϜ։ൃ(αʔόαΠυ) • 2016/2- גࣜձࣾFiNCॴଐ • Ruby on Rails, Microservices Architecture • ࣾྺ=Railsྺ=1೥൒

Slide 5

Slide 5 text

whoami • 2013- Node.js ͰͷήʔϜ։ൃ(αʔόαΠυ) • 2016/2- גࣜձࣾFiNCॴଐ • Ruby on Rails, Microservices Architecture • ࣾྺ=Railsྺ=1೥൒ ͓ͯ΍ΘΒ͔ʹʂʂ

Slide 6

Slide 6 text

whoami • Microservices Meetup Λ
 ӡӦ͍ͯ͠·͢ • @ FiNC • ෆఆظ։࠵

Slide 7

Slide 7 text

ࠓ೔ͷτϐοΫ • ϚΠΫϩαʔϏε • Ruby on Rails • Web API ͲΕ΋FiNCͰͷ։ൃͰ
 େࣄʹ͍ͯ͠Δ΋ͷɻ

Slide 8

Slide 8 text

גࣜձࣾFiNC ͱ͸ • ͗Μ͟ʹ͋ΔձࣾͰ͢ • ݱࡏ͸ @ ༗ָொ • ͦͷલ͸ @ ౦ۜ࠲ • (ӈ: FiNC Fit ۜ࠲ళ)

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

ϚΠΫϩαʔϏεͱ͸? • ϏδωευϝΠϯʹج͍ͮͯϞσϧԽ͞Εͨɺ
 ཻ౓ͷࡉ͔͍αʔϏε • ਫฏ(ٕज़)෼ׂͰ͸ͳ͘ɺਨ௚(Ϗδωε)෼ׂ • APIΛ௨ͯ͡ɺ࿈ܞͯ͠ಈ࡞͢Δ

Slide 11

Slide 11 text

FiNCͷϚΠΫϩαʔϏε • RailsͰͷϚΠΫϩαʔϏε ໿25ݸ • Web APIͱඇಉظΠϕϯτΛར༻ͯ͠ڠௐಈ࡞

Slide 12

Slide 12 text

Web API ͕ͱͯ΋ॏཁ • ϦονͰେن໛ͳωΠςΟϒΞϓϦ։ൃʹ
 ରԠ͢ΔͨΊ • ଟ͘ͷϚΠΫϩαʔϏεΛڠௐಈ࡞ͤ͞ΔͨΊ • ྑ͘ఆٛ͞ΕͨAPI͸ɺϚΠΫϩαʔϏεͷ ΠϯϑϥΛࢧ͑Δ

Slide 13

Slide 13 text

ࠓ೔ͷΞδΣϯμ 1. Ұ؏ੑͷ͋ΔWeb APIઃܭ
 ϚΠΫϩαʔϏεࢦ޲։ൃͷࢹ఺Λަ͑ɺWeb APIઃܭΛٞ࿦͠·͢ɻ 2. Rails API։ൃͷϓϥΫςΟε
 ্هͷWeb APIઃܭʹର͠ɺRailsͰͷ࣮૷දݱΛ༩͍͖͑ͯ·͢ɻ 3. ੍໿͔Β֎ΕͨAPIΛ࡞Δ࣌
 ͜͜·ͰͰ࿩ͨ͜͠ͱͷྫ֎ʹͳΔΑ͏ͳέʔεΛߟ͑ͯΈ·͢ɻ

Slide 14

Slide 14 text

1. Ұ؏ੑͷ͋ΔWeb APIઃܭ

Slide 15

Slide 15 text

1ষͷαϚϦ • ڧ͍Ϧιʔεࢦ޲ • ׬શୈ2ܗଶRESTful • ͦͷ࣮ྫ

Slide 16

Slide 16 text

Web APIࣦഊ͋Δ͋Δ • UIʹ΂ͬͨΓͳAPIͰɺ࠶ར༻ੑ͕௿͍ • ສೳͳAPI͕֤ॴͰ࢖͍·Θ͞ΕɺύϑΥʔϚϯε͕ѱ͍ • ͋Δ2ͭͷAPIΛൺ΂ͯΈΔͱɺ
 ಉ͡Α͏Ͱಉ͡͡Όͳ͍গ͠ಉ͡σʔλ͕ฦͬͯ͘Δ

Slide 17

Slide 17 text

Web APIͰࣦഊΛආ͚Δʹ͸ • UIʹ΂ͬͨΓͳAPIΛ࡞Βͳ͍ • ສೳͳAPIΛ࡞Βͳ͍ • ಉ͡Α͏Ͱಉ͡͡Όͳ͍গ͠ಉ͡σʔλΛฦ͞ͳ͍ • ্هΛकΕΔΑ͏ʹɺઃܭࢦ਑΍੍໿Λઃ͚͍ͯ͘

Slide 18

Slide 18 text

ҰͭͷܾΊࣄ : "ڧ͍Ϧιʔεࢦ޲"

Slide 19

Slide 19 text

ڧ͍Ϧιʔεࢦ޲ • શͯͷAPI͸ɺඞͣ "Ϧιʔε" ·ͨ͸
 "Ϧιʔεͷ഑ྻ" Λฦ͢ • σʔλߏ଄(JSON)͕ωετ͞ΕͨΒɺ
 ֊૚͕Լ͕ͬͨ෦෼͸ඞͣϦιʔεͱΈͳ͢

Slide 20

Slide 20 text

Ϧιʔεͷྫ // GET /v1/users/1 { // User Ϧιʔε "id": 123, "name": "qsona", "age": 17, "jobs": [ // Job Ϧιʔεͷ഑ྻ { "id": 2, "name": "ձࣾһ" }, { "id": 7, "name": "ࣗ୐ܯඋһ" } ] }

Slide 21

Slide 21 text

Ϧιʔεͱ͸? • αʔόɾΫϥΠΞϯτؒͰ߹ҙͰ͖͍ͯΔɺϞϊͷ୯Ґ • ΫϥΠΞϯτ͸ɺϦιʔεͷ୯ҐͰΫϥεΛੜ੒͢Δ • (Ͱ͖Ε͹) اըαΠυ΋ͦͷ୯ҐΛཧղ͍ͯ͠Δ • Domain-Driven Design Ͱ͍͏ͱ͜ΖͷυϝΠϯϞσϧͱ
 ରԠ͢Δ

Slide 22

Slide 22 text

Ϧιʔεͱ͸? • αʔόɾΫϥΠΞϯτؒͰ߹ҙͰ͖͍ͯΔɺϞϊͷ୯Ґ • ΫϥΠΞϯτ͸ɺϦιʔεͷ୯ҐͰΫϥεΛੜ੒͢Δ • (Ͱ͖Ε͹) اըαΠυ΋ͦͷ୯ҐΛཧղ͍ͯ͠Δ • Domain-Driven Design Ͱ͍͏ͱ͜ΖͷυϝΠϯϞσϧͱ
 ରԠ͢Δ => APIઃܭΛߟ͑ΔͨΊʹ͸
 ϏδωευϝΠϯͷߟ࡯͕ඞਢ

Slide 23

Slide 23 text

͜ͷ੍໿ʹΑΔϝϦοτ • ϏδωευϝΠϯʹ͍ͭͯΑ͘ߟ࡯͠ɺUIʹ΂ͬͨΓͳAPI͕࡞ΒΕΔͷΛ๷͙ • APIͷ໾ׂ͕1ͭʹఆ·ΓɺສೳͳAPI͸࡞ΒΕʹ͘͘ͳΔɻ • ฦ͢΋ͷ͸ඞͣϦιʔεͰ͋ΓɺͦͷϦιʔεΛෳ਺ͷAPIͰ࠶ར༻͢ΔͷͰɺ
 ࢓༷͕҆ఆ͢Δ (API͝ͱʹඍົʹҧ͏Ωʔ͕ฦ͞ΕΔɺΈ͍ͨͷ͕ͳ͘ͳΔ) • ΫϥΠΞϯτؒ (ྫ͑͹iOS/Android) Ͱͷڞ௨ೝ͕ࣝͰ͖ɺ
 Ϩεϙϯεͷଊ͑ํ (Ϋϥε΁ͷϚοϐϯάͷ࢓ํ) ͕҆ఆ͢Δɻ

Slide 24

Slide 24 text

Q.ΫϥΠΞϯτͷෛ୲͕૿͑ΔͷͰ͸? • ͳΜͰ΋ϦιʔεΛฦ͢ͱɺΫϥΠΞϯτ͔Βෳ਺ͷ APIΛୟ͘͜ͱ͕૿͑ΔͷͰ͸? • ࠷ѱɺN+1ͳϦΫΤετ͕ඈͿΈ͍ͨͳ͜ͱ͕ى͜Δͷ Ͱ͸?

Slide 25

Slide 25 text

APIઃܭͰେମղܾͰ͖Δ • Ϧιʔεͷཻ౓Λɺࡉ͔͗͘͢͠ͳ͍͜ͱ • ΞϓϦέʔγϣϯ্ͷυϝΠϯϞσϧͷཻ౓ • ςʔϒϧͷ୯ҐͰ͸ͳ͍ • ϦΫΤετͷ N+1 ໰୊͕ى͜Δͷ͸ɺϦιʔεͷཻ౓ͷϛε=APIઃܭϛ εͰ͋Δ͜ͱ͕΄ͱΜͲ • ͱ͸͍͑ɺຊདྷؔ܎ͷͳ͍ϦιʔεΛ1ը໘Ͱෳ਺ར༻ͨ͠Γɺ
 αʔϏεʹ·͕ͨͬͯσʔλΛऔಘ͍ͨ࣌͠΋͋Δ

Slide 26

Slide 26 text

BFF (Backends For Frontends) • ϑϩϯτΤϯυͷͨΊͷαʔόʔ • ΫϥΠΞϯτͱɺόοΫΤϯυαʔϏεͷதؒʹҐஔ ͢Δ • ෳ਺ͷϚΠΫϩαʔϏεͷAPIΛɺฒྻ/௚ྻͰୟ͖ɺ ϦιʔεΛ·ͱΊΔ໾໨Λ࣋ͭ (API Aggregation)

Slide 27

Slide 27 text

step-by-step BFF - Yosuke Furukawa (Microservices Meetup vol.5)

Slide 28

Slide 28 text

׬શୈ2ܗଶRESTful

Slide 29

Slide 29 text

RESTfulͷܗଶ Richardson Maturity Model - Martin Fowler • Ϩϕϧ1: ϦιʔεͱURIͰ ͷදݱ • Ϩϕϧ2: HTTPͷಈࢺΛਖ਼ ͘͠࢖͍෼͚Δ • Ϩϕϧ3: ϋΠύʔϝσΟΞ ίϯτϩʔϧ (HATEOAS)

Slide 30

Slide 30 text

RESTful ୈ1ܗଶ • path ͰϦιʔεΛදݱ͢Δ • ex) GET /v1/users/:user_id • User Ϧιʔε • ex) GET /v1/users/:user_id/jobs • User Ϧιʔεʹैଐ͢Δ Job Ϧιʔεͷ഑ྻ • Ϧιʔεͷैଐؔ܎͕Θ͔Γ΍͍͢

Slide 31

Slide 31 text

RESTful ୈ2ܗଶ • HTTPͷಈࢺ (GET, POST, ...) Λར༻͢Δ • ex) POST /v1/users ... Ϣʔβ࡞੒ • HTTPඪ४ʹଇΔϝϦοτ͕͋Δ • pathʹಈࢺΛؚΊͳ͍ͱ͍͏੍໿͕ɺϦιʔ εΛߟ࡯͢Δ͜ͱΛଅ͢

Slide 32

Slide 32 text

ୈ2ܗଶͷRESTfulΛ΍Γ͖Δ • جຊతʹɺϨϕϧ2·Ͱ͸΍Γ͖Δʹӽͨ͜͠ͱ͸ͳ͍ • APIʹҰ؏ੑΛ࣋ͨͤΔͨΊͷɺྑ੍͍໿ʹͳΔ • Ϩϕϧ3 (ڀۃܗଶ) ʹ͢Δʹ͸ɺ
 Ϧλʔϯ΋͋Δ͕ίετ΋͋Δ • ࠓͷͱ͜Ζίετͷ͕େ͖͍ͱ൑அ • ߟ͑ํ͸෦෼తʹར༻͍ͯ͠Δ

Slide 33

Slide 33 text

࣮ྫ ʙ FiNC Appͷ ʮϥϯΩϯάʯ ػೳͷAPI ʙ

Slide 34

Slide 34 text

ϥϯΩϯάػೳ(v1) • ظؒ಺ͷา਺Λڝ͏ • ͜ͷϖʔδʹ͸ɺ͍͔ͭ͘ͷ Ϧιʔε͕ଘࡏ͢Δ • ϥϯΩϯάͷαʔϏεͱɺϢʔ β৘ใΛѻ͏ϝΠϯαʔϏε ͷ2छྨ͕ଘࡏ͍ͯ͠Δ

Slide 35

Slide 35 text

Ranking#show API • Ranking Ϧιʔε • name • start_at, end_at • ( ranking_users )

Slide 36

Slide 36 text

RankingUser#index API • RankingUser Ϧιʔε • score, rank • user_id • ranking_idͱɺظؒ(today/total) Λ ύϥϝʔλͰड͚Δ

Slide 37

Slide 37 text

UserProfile API • UserProfile Ϧιʔε • name, image • ෳ਺ͷ user_id ΛύϥϝʔλͰड ͚ͯɺ഑ྻͰฦ͢ • ͜ͷAPI͚ͩ͸ɺϝΠϯαʔϏε ʹଐ͍ͯ͠Δ

Slide 38

Slide 38 text

BFFͰू໿͢Δ 1. Ranking औಘ 2. Ranking id͔ΒɺRanking UserΛ ഑ྻͰऔಘ 3. Ranking Userͷ user_id഑ྻ͔Βɺ UserProfile Λ഑ྻͰऔಘ

Slide 39

Slide 39 text

ू໿͸ϑϩϯτͷࣗ༝ • ྫ͑͹͸͡Ίʹ Ranking ͚ͩΛҰ୴ औಘͯ͠ɺͦΕΛඳըͭͭ͠ɺ
 ࣍ͷϦΫΤετͰ RankingUser ͱ UserProfile ΛऔΓʹߦͬͯ΋͍͍

Slide 40

Slide 40 text

ಥવͷཁ๬(v2) • ʮ੺࿮ͷλϒͷจݴ΍ॱ൪Λɺαʔ όαΠυͰม͑ΒΕΔΑ͏ʹ͍ͨ͠ʯ • iOS/AndroidΞϓϦ͸ਃ੥͕ඞཁ ͳͷͰɺUIΛؾܰʹม͑ΒΕͳ͍ ͱ͍͏ࣄ৘͕

Slide 41

Slide 41 text

UI or Domain? • ͸͡Ί͸ɺUIͷͨΊͷϩδοΫͩͱߟ͑ɺBFF ʹ࣮૷͠Α͏ͱߟ͑ͨ • UIϩδοΫΛόοΫΤϯυʹ࣋ͨͤͨ͘ͳ͍ • ͔͠͠ɺBFFʹυϝΠϯϩδοΫ͕ྲྀग़͢Δͷ ͸΋ͬͱਏ͍ • BFF͸۪͔ʹɺόοΫΤϯυΛݡ͘͢΂͖

Slide 42

Slide 42 text

υϝΠϯͱͯ͠ͷߟ࡯ • ʮλϒʯΛυϝΠϯͱͯ͠ଊ͑ͯΈΔ • Ranking has_many Tabs • Tab has_many RankingUsers • Tab͸ɺRankingUserͷू߹ͷऔΓํΛ࣋ͭ • ΫϥΠΞϯτΤϯδχΞͱ͜ͷઃܭͷٞ࿦Λ ߦ͍ɺ2࣌ؒΛඅ΍ͨ͠ (ઃܭॏཁ)

Slide 43

Slide 43 text

υϝΠϯͰਖ਼ղͩͬͨ • ॊೈͳӡ༻͕Մೳʹͳͬͨ • ྫ͑͹ɺαʔόଆͷ࣮૷͚ͩͰ Yesterday λϒΛ௥ՃͰ͖Δ • ΞϓϦέʔγϣϯͷ࢓༷Λਖ਼͘͠൓ө ͍ͯ͠Δঢ়ଶ • αʔό/ΫϥΠΞϯτؒͷೝࣝ΋ڞ௨ʹ

Slide 44

Slide 44 text

1ষ ·ͱΊ • ڧ͍Ϧιʔεࢦ޲ͷ੍໿ʹΑΓɺWeb API͕
 ؕΓ͕ͪͳ᠘ΛճආͰ͖Δ • ը໘࠷దԽʹ͸ BFF Λར༻͢Δ • RESTful (ୈ2ܗଶ) Λ΍Γ͖Δ • υϝΠϯϞσϧͷߟ࡯͕伴

Slide 45

Slide 45 text

2. Rails API։ൃͷϓϥΫςΟε

Slide 46

Slide 46 text

੍໿ͷදݱ • લষͰ࿩ͨ͠Α͏ʹɺAPIͷ࡞Γํʹ੍໿Λ༩ ͑Δ͜ͱͰɺAPIʹҰ؏ੑΛ࣋ͨͤɺΑ͘ఆٛ ͢Δ͜ͱ͕Ͱ͖Δ • ͦͷঢ়ଶΛɺRailsͰදݱ͍͖͍ͯͨ͠

Slide 47

Slide 47 text

"ڧ͍Ϧιʔεࢦ޲" ͷදݱ

Slide 48

Slide 48 text

"ڧ͍Ϧιʔεࢦ޲"ͷදݱ • Ұྫͱͯ͠ɺactive_model_serializers ͱ͍͏ gemΛར༻ͨ͠ϓϥΫςΟεΛ঺հ͢Δ

Slide 49

Slide 49 text

active_model_serializers • ϨεϙϯεϘσΟ΁ͷγϦΞϥΠζ෦෼Λ୲౰͢Δgem • Modelʹରͯ͠ɺSerializerΛରԠͤͯ͞࡞Δ • ͜͜ͷModel͸ɺActiveRecord Ͱ΋ͦ͏Ͱͳͯ͘΋͍͍ • ʮෳ਺ͷModelΛ·ͱΊͯγϦΞϥΠζʯ͸ͳ͍ • ී௨͸ Model 1ͭʹ Serializer 1ͭΛରԠͤ͞Δ

Slide 50

Slide 50 text

Ϧιʔεࢦ޲ͱͷରԠ • Serializer Ϋϥε͕ APIͷϦιʔεʹରԠ͢Δ • 1ͭͷAPIͰɺModelΛ1͚ͭͩγϦΞϥΠζ͢Δ • γϦΞϥΠβ͸Ҿ਺ΛऔΒͳ͍ • શͯͷ৘ใ͕1ͭͷModelʹೖ͍ͬͯΔ • instance_options (ͱ͍͏ active_model_serializersͷػೳ) ͸࢖Θͳ͍

Slide 51

Slide 51 text

RESTful (ୈ2ܗଶ·Ͱ) ͷදݱ

Slide 52

Slide 52 text

RESTful (ୈ2ܗଶ·Ͱ) ͷදݱ • Rails Wayʹ৐Δ • routes / ActionController • pathͱControllerઃܭ • ύϥϝʔλ͔ΒϞσϧΛҾ͘ίʔυΛڞ௨Խ͢Δ • DHHͷControllerઃܭ

Slide 53

Slide 53 text

pathͱControllerઃܭ • path͕ڞ௨Ͱ͋Ε͹ɺಉ͡ϞσϧΛ࢖͏͸ͣ • ҎԼͷ3ͭͷpath͕͋Δͱ͢ΔͱɺͲΕ΋ಉ͡UserΛ࢖͏͸ͣ • /v1/users/:user_id • /v1/users/:user_id/jobs • /v1/users/:user_id/parent • ͦͷ෦෼Λڞ௨Ͱ࢖͏͜ͱͰɺͦͷ੍໿ΛकΕΔ

Slide 54

Slide 54 text

class V1::UsersController < ApplicationController def show render json: user, serializer: V1::UserSerializer end 
 def jobs render json: user.jobs, each_serializer: V1::JobSerializer end def parent render json: user.parent, serializer: V1::UserSerializer end private def user @user ||= User.find(params[:user_id]) end end

Slide 55

Slide 55 text

DHHͷControllerઃܭ • Controller ʹఆٛ͢ΔΞΫγϣϯ͸جຊ7ΞΫγϣϯͷΈ • APIͰ͸5ΞΫγϣϯ (index, show, create, update, destroy) • ͦΕҎ֎Λఆٛͨ͘͠ͳͬͨΒɺίϯτϩʔϥΛ෼ׂ͢Δ How DHH Organizes His Rails Controllers , Jerome Dalbert
 ೔ຊޠ༁ DHH͸ͲͷΑ͏ʹRailsͷίϯτϩʔϥΛॻ͘ͷ͔ , POSTD

Slide 56

Slide 56 text

class V1::UsersController < ApplicationController include V1::Users::ControllerConcern def show render json: user, serializer: V1::UserSerializer end end class V1::Users::JobsController < ApplicationController
 include V1::Users::ControllerConcern def index render json: user.jobs, each_serializer: V1::JobSerializer end end class V1::Users::ParentsController < ApplicationController include V1::Users::ControllerConcern def show render json: user.parent, serializer: V1::UserSerializer end end /v1/users/:user_id /v1/users/:user_id/jobs /v1/users/:user_id/parent

Slide 57

Slide 57 text

module V1::Users::ControllerConcern def user(includes: nil) @user ||= if includes User.includes(includes).find(params[:user_id]) else User.find(params[:user_id]) end end end path ͔ΒϞσϧΛ औಘ͢Δ෦෼Λڞ ௨Խ͢ΔͨΊͷ Controller Concern

Slide 58

Slide 58 text

ྫ: Ranking API

Slide 59

Slide 59 text

// ͋ΔϥϯΩϯάΛऔಘ͢ΔAPIͷϨεϙϯεϘσΟ { "id": 123, "name": "Rails Contributors from Japan", "my_score": 0, "my_rank": null, "ranking_users": [ { "name": "kamipo", "rank": 1, "score": 811 }, { "name": "a_matsuda", "rank": 2, "score": 700 }, { "name": "y-yagi", "rank": 3, "score": 532 } ] }

Slide 60

Slide 60 text

// ͋ΔϥϯΩϯάΛऔಘ͢ΔAPIͷϨεϙϯεϘσΟ { "id": 123, "name": "Rails Contributors from Japan", "my_score": 0, "my_rank": null, "ranking_users": [ { "name": "kamipo", "rank": 1, "score": 811 }, { "name": "a_matsuda", "rank": 2, "score": 700 }, { "name": "y-yagi", "rank": 3, "score": 532 } ] } ͚ͩ͜͜ɺೝূϢʔβࢹ఺ͰͷϥϯΩϯά৘ใ

Slide 61

Slide 61 text

Ranking (ActiveRecord) # == Schema Information # id :bigint # name :string class Ranking < ApplicationRecord has_many :ranking_users end

Slide 62

Slide 62 text

ϦιʔεʹରԠ͢ΔϞσϧΛߟ͑Δ • ฦ͍ͨ͠ͷ͸ 
 Ranking + Ϣʔβ͔ΒΈͨRanking৘ใ • Rankingͦͷ΋ͷ͸ɺ୭͔Βݟͯ΋ಉ͡΋ͷͳ͸ͣ • ฦ͢ϦιʔεΛ UserRanking ͱଊ͑ͯΈΔ

Slide 63

Slide 63 text

UserRanking (non-AR Model) class UserRanking include ActiveModel::Model include ActiveModel::Serialization attr_accessor :user, :ranking delegate :id, to: :ranking delegate :name, to: :ranking delegate :ranking_users, to: :ranking def my_score ranking_users.find_by(user_id: user.id)&.score end end

Slide 64

Slide 64 text

UserRanking (non-AR Model) • Ranking + User ͔ΒͳΔϞσϧ • Ranking ͷϝιου͸delegate͍ͯ͠Δ • ໘౗ͩͬͨΒmethod_missingͰ... • "User͔ΒݟͨRanking" ͷϝιουΛ௥Ճ͍ͯ͠Δ • my_score / my_rank

Slide 65

Slide 65 text

V1 UserRanking Serializer • UserRankingͷΠϯελϯεΛγϦΞϥΠζ͢Δ • APIʹఆٛ͢ΔϦιʔε͸ɺ͜ΕͱରԠ͍ͯ͠Δ class V1::UserRankingSerializer < ActiveModel::Serializer attributes :id, :name, :my_score, :my_rank has_many :ranking_users, serializer: V1::RankingUserSerializer end

Slide 66

Slide 66 text

V1 Users Rankings Controller • ϧʔςΟϯά͸ GET /v1/users/me/rankings/:id ͱͨ͠ • `me` ͸ೝূ͞ΕͨϢʔβΛද͢ɺuser_idͷΤΠϦΞε • ࢦఆͨ͠Ϣʔβࢹ఺ͰͷϥϯΩϯά͕ཉ͍͠ͱ͖͸ 
 GET /v1/users/:user_id/rankings/:id • ϚΠΫϩαʔϏεؒͰAPIΛར༻͢Δͱ͖͸ɺͪ͜Β͕࢖ΘΕΔ

Slide 67

Slide 67 text

# app/controllers/v1/users/rankings_controller.rb class V1::Users::RankingsController < ApplicationController def show user_ranking = UserRanking.new(ranking: ranking, user: user) render json: user_ranking, serializer: V1::UserRankingSerializer end private def ranking @ranking ||= Ranking.find(params[:id]) end def user @user ||= if params[:user_id] == 'me' current_user! else User.find(params[:user_id]) end end end

Slide 68

Slide 68 text

# app/controllers/v1/users/rankings_controller.rb class V1::Users::RankingsController < ApplicationController def show user_ranking = UserRanking.new(ranking: ranking, user: user) render json: user_ranking, serializer: V1::UserRankingSerializer end private def ranking @ranking ||= Ranking.find(params[:id]) end def user @user ||= if params[:user_id] == 'me' current_user! else User.find(params[:user_id]) end end end params ͔ΒऔΕΔσʔλ͸
 privateϝιουʹ·ͱΊΔ

Slide 69

Slide 69 text

# app/controllers/v1/users/rankings_controller.rb class V1::Users::RankingsController < ApplicationController def show user_ranking = UserRanking.new(ranking: ranking, user: user) render json: user_ranking, serializer: V1::UserRankingSerializer end private def ranking @ranking ||= Ranking.find(params[:id]) end def user @user ||= if params[:user_id] == 'me' current_user! else User.find(params[:user_id]) end end end params ͔ΒऔΕΔσʔλ͸
 privateϝιουʹ·ͱΊΔ render ʹ௚઀ ϞσϧΛ౉͢

Slide 70

Slide 70 text

ී௨ͷControllerͱͷҧ͍ • ಈతʹHTMLΛੜ੒͢ΔControllerͷ৔߹ɺ
 ඞཁͳσʔλΛΠϯελϯεม਺ʹηοτ͢Δ • ಉ͡API޲͚ͷγϦΞϥΠβͰ΋ɺ rabl ͸ͦΕͱಉ͡ࢥ૝

Slide 71

Slide 71 text

ී௨ͷControllerͱͷҧ͍ • ڧ͍Ϧιʔεࢦ޲ͷAPI৔߹ɺฦ͢΋ͷ͸Ϧιʔε୯ମͳͷ Ͱɺ࠷ऴతʹ1ͭͷϞσϧ͚͕ͩඞཁ • Πϯελϯεม਺ʹηοτ͢Δඞཁ͸ͳ͘ɺrenderʹ౉ͤ͹Α͍ • private method΋ɺྫ͑͹ `set_ranking` Ͱ͸ͳ͘୯ʹ `ranking`

Slide 72

Slide 72 text

2ষ ·ͱΊ • ڧ͍Ϧιʔεࢦ޲ΛRailsͰकΔʹ͸ɺͦΕʹ߹ͬͨγϦΞ ϥΠβ (ྫ͑͹ active_model_serializers) ΛબͿ • ϦιʔεʹରԠ͢ΔϞσϧ (AR/non-AR) Λ࡞Δ • RESTfulΛकΔʹ͸ɺRails wayʹ৐͍͚ͬͯ͹͍͍ • Controller ͷ࢖͍ํΛ޻෉͠ɺpathͷղऍΛڞ௨Խ͢Δ

Slide 73

Slide 73 text

3. ੍໿͔Β֎ΕͨAPIΛ࡞Δ࣌

Slide 74

Slide 74 text

ྫ) ϖʔδϯά͕͋ΔAPI • Α͘RESTfulͷจ຺Ͱٞ࿦ʹͳΔྫ • Ϧιʔεͷ഑ྻ͕͋ΓɺͦΕͱ͸ผ్ϖʔδϯάʹؔ͢Δ৘ใΛฦ ͢ͱ͖ • ͦͷ৘ใ͸Ͳ͜ʹஔ͘΂͖͔? • ڧ͍Ϧιʔεࢦ޲͸कΕΔͷ͔? • (τοϓϨϕϧΛ഑ྻʹ͢ΔͱɺΩʔ͸ੜ΍ͤͳ͍)

Slide 75

Slide 75 text

1) ϔομ೿ Best Practices for Designing a Pragmatic RESTful API , Vinay Sahni
 ຋༁: WebAPI ઃܭͷϕετϓϥΫςΟε , mserizawa

Slide 76

Slide 76 text

2) ϨεϙϯεϘσΟ೿ RESTful API ͷઃܭͷΩϗϯ , Cside

Slide 77

Slide 77 text

๻ݸਓͷߟ͑ • ϔομ͸ͿͬͪΌ͚࢖͍ͮΒ͍ɺʹಉҙ • ͨͱ͑͹BFFͷϨΠϠͰAPIΛ·ͱΊ͍ͨέʔε
 1ϦΫΤετʹରͯ͠HTTPϔομ͸౰વ1ͭ • "ڧ͍Ϧιʔεࢦ޲"͸ɺग़དྷΔݶΓकΓ͍ͨ • ʮϖʔδϯάʯ΋ҰͭͷϦιʔεͱͯ͠ଊ͑ͯΈͨΒ?

Slide 78

Slide 78 text

͜ΜͳΠϝʔδ struct Paging { data: Array cursor: T2 }

Slide 79

Slide 79 text

// GET /v1/users [ { "id": 1, "name": "kamipo" }, { "id": 2, "name": "a_matsuda" }, { "id": 3, "name": "y-yagi" }, { "id": 4, "name": "willnet" }, { "id": 5, "name": "ken1flan" } ] // GET /v1/users/paging?cursor=2&limit=2 { "cursor": 4,
 "data": [ { "id": 3, "name": "y-yagi" }, { "id": 4, "name": "willnet" } ] } GET /v1/users/ ϢʔβҰཡɻ
 ϖʔδϯά͸ͳ͍ GET /v1/users/paging ϖʔδϯά͋Γͷ
 ϢʔβҰཡɻ

Slide 80

Slide 80 text

ڧ͍Ϧιʔεࢦ޲Λద༻ͨ͠ • ϧʔϧΛγϯϓϧͳ··อͭ͜ͱʹ੒ޭͨ͠ • ͜ΕͰࠔ͍ͬͯͳ͍͠ɺ࣮ࡍʹӡ༻Ͱ͖͍ͯΔ • index ͱ paging Ͱ͸ҧ͏ϦιʔεΛฦ͍ͯ͠ΔͷͰɺ
 index Ͱ͸τοϓϨϕϧͷ഑ྻɺ
 paging Ͱ͸ dataҎԼʹ഑ྻɺͱ֊૚͕มΘͬͯΔͷ͸ҧ࿨ײͳ͍ • ޙ͔Βϖʔδϯά͕ඞཁʹͳͬͨΒɺͦΕ͸΋͏ޙํޓ׵ੑ͕ͳ͘ ͳΔมߋͱଊ͑ͯɺURIม͑ͨ΄͏͕͍͍ͱׂΓ੾͍ͬͯΔ

Slide 81

Slide 81 text

ద༻੒ޭ

Slide 82

Slide 82 text

ଞʹ΋৭ʑ͋Δ • ex) POSTܥͷAPIͰɺ෭࡞༻ͷ݁ՌΛฦ͍ͨ͠ͱ͖͸? • ex) ύϑΥʔϚϯεʹ೉͕͋ΓɺBFFͰ΋ղܾͰ͖ͳ͍ͱ͖͸? • ΋ͪΖΜʮۜͷ஄ؙ͸ͳ͍ʯ • ϧʔϧ͸γϯϓϧͳํ͕͍͍͕ɺͲ͜·Ͱ੍໿Λద༻Ͱ͖Δ͔͸ ΞϓϦέʔγϣϯͷੑ࣭࣍ୈ • ྑ੍͍໿Λϕʔεʹɺ޻෉ͯ͠࠷దղΛݟ͚͍͖ͭͯ·͠ΐ͏

Slide 83

Slide 83 text

ࠓ೔ͷ·ͱΊ • ྑ͍Web APIઃܭ͕ɺϦονͳΫϥΠΞϯτΞϓϦͷ։ ൃ΍ϚΠΫϩαʔϏεͷڠௐಈ࡞Λࢧ͑Δ • Ұ؏ੑͷ͋ΔWeb APIઃܭͷͨΊʹ͸ɺҰఆͷ੍໿Λ࣋ ͨͤɺ·ͨϏδωευϝΠϯΛΑ͘ߟ࡯͢Δ͜ͱ͕ॏཁ • Rails Λ༻্͍ͨهͷઃܭͷ࣮૷දݱΛ঺հͨ͠

Slide 84

Slide 84 text

ࠓ೔࿩ͤͳ͔ͬͨ͜ͱ • APIͷఆٛͱɺυΩϡϝϯτͷࣗಈੜ੒ • FiNCͰ͸ JSON Hyper Schema / prmd, committee Λར༻͍ͯ͠Δ • committee + prmd ͰJSON SchemaΛ͍͍ײ͡ʹӡ༻͢Δ - ͓͓ͨͷ෺ஔ ( @ota42y ) • ࠓ೔࿩ͨ͠Α͏ͳAPI։ൃελΠϧΛखʹೖΕΔ·ͰͷಓͷΓ • FiNCͷWeb API։ൃࣄ৘ - Fumiya Shinozuka

Slide 85

Slide 85 text

Have a Good API Life! @qsona