Upgrade to Pro — share decks privately, control downloads, hide ads and more …

マイクロサービス指向 Rails API 開発ガイド/building rails api on microservices

qsona
August 05, 2017

マイクロサービス指向 Rails API 開発ガイド/building rails api on microservices

2017/8/5 ぎんざRuby会議01 @みんなのウェディング

引用のリンク先などはこちらを参照ください
https://medium.com/finc-engineering/ginzaruby01-rails-api-guide-168fe9cf5b4d

qsona

August 05, 2017
Tweet

More Decks by qsona

Other Decks in Technology

Transcript

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

    View Slide

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

    View Slide

  3. whoami
    ϚΠΫϩαʔϏε࣌୅ʹ๋͙ɺRailsͰͷதن໛APIαʔό։ൃͷͨΊͷٕज़ߏ੒

    Ruby on Rails Advent Calendar 2016, qsona

    View Slide

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

    View Slide

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

    View Slide

  6. whoami
    • Microservices Meetup Λ

    ӡӦ͍ͯ͠·͢
    • @ FiNC
    • ෆఆظ։࠵

    View Slide

  7. ࠓ೔ͷτϐοΫ
    • ϚΠΫϩαʔϏε
    • Ruby on Rails
    • Web API
    ͲΕ΋FiNCͰͷ։ൃͰ

    େࣄʹ͍ͯ͠Δ΋ͷɻ

    View Slide

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

    View Slide

  9. View Slide

  10. ϚΠΫϩαʔϏεͱ͸?
    • ϏδωευϝΠϯʹج͍ͮͯϞσϧԽ͞Εͨɺ

    ཻ౓ͷࡉ͔͍αʔϏε
    • ਫฏ(ٕज़)෼ׂͰ͸ͳ͘ɺਨ௚(Ϗδωε)෼ׂ
    • APIΛ௨ͯ͡ɺ࿈ܞͯ͠ಈ࡞͢Δ

    View Slide

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

    View Slide

  12. Web API ͕ͱͯ΋ॏཁ
    • ϦονͰେن໛ͳωΠςΟϒΞϓϦ։ൃʹ

    ରԠ͢ΔͨΊ
    • ଟ͘ͷϚΠΫϩαʔϏεΛڠௐಈ࡞ͤ͞ΔͨΊ
    • ྑ͘ఆٛ͞ΕͨAPI͸ɺϚΠΫϩαʔϏεͷ
    ΠϯϑϥΛࢧ͑Δ

    View Slide

  13. ࠓ೔ͷΞδΣϯμ
    1. Ұ؏ੑͷ͋ΔWeb APIઃܭ

    ϚΠΫϩαʔϏεࢦ޲։ൃͷࢹ఺Λަ͑ɺWeb APIઃܭΛٞ࿦͠·͢ɻ
    2. Rails API։ൃͷϓϥΫςΟε

    ্هͷWeb APIઃܭʹର͠ɺRailsͰͷ࣮૷දݱΛ༩͍͖͑ͯ·͢ɻ
    3. ੍໿͔Β֎ΕͨAPIΛ࡞Δ࣌

    ͜͜·ͰͰ࿩ͨ͜͠ͱͷྫ֎ʹͳΔΑ͏ͳέʔεΛߟ͑ͯΈ·͢ɻ

    View Slide

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

    View Slide

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

    View Slide

  16. Web APIࣦഊ͋Δ͋Δ
    • UIʹ΂ͬͨΓͳAPIͰɺ࠶ར༻ੑ͕௿͍
    • ສೳͳAPI͕֤ॴͰ࢖͍·Θ͞ΕɺύϑΥʔϚϯε͕ѱ͍
    • ͋Δ2ͭͷAPIΛൺ΂ͯΈΔͱɺ

    ಉ͡Α͏Ͱಉ͡͡Όͳ͍গ͠ಉ͡σʔλ͕ฦͬͯ͘Δ

    View Slide

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

    View Slide

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

    View Slide

  19. ڧ͍Ϧιʔεࢦ޲
    • શͯͷAPI͸ɺඞͣ "Ϧιʔε" ·ͨ͸

    "Ϧιʔεͷ഑ྻ" Λฦ͢
    • σʔλߏ଄(JSON)͕ωετ͞ΕͨΒɺ

    ֊૚͕Լ͕ͬͨ෦෼͸ඞͣϦιʔεͱΈͳ͢

    View Slide

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

    View Slide

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

    ରԠ͢Δ

    View Slide

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

    ରԠ͢Δ
    => APIઃܭΛߟ͑ΔͨΊʹ͸

    ϏδωευϝΠϯͷߟ࡯͕ඞਢ

    View Slide

  23. ͜ͷ੍໿ʹΑΔϝϦοτ
    • ϏδωευϝΠϯʹ͍ͭͯΑ͘ߟ࡯͠ɺUIʹ΂ͬͨΓͳAPI͕࡞ΒΕΔͷΛ๷͙
    • APIͷ໾ׂ͕1ͭʹఆ·ΓɺສೳͳAPI͸࡞ΒΕʹ͘͘ͳΔɻ
    • ฦ͢΋ͷ͸ඞͣϦιʔεͰ͋ΓɺͦͷϦιʔεΛෳ਺ͷAPIͰ࠶ར༻͢ΔͷͰɺ

    ࢓༷͕҆ఆ͢Δ (API͝ͱʹඍົʹҧ͏Ωʔ͕ฦ͞ΕΔɺΈ͍ͨͷ͕ͳ͘ͳΔ)
    • ΫϥΠΞϯτؒ (ྫ͑͹iOS/Android) Ͱͷڞ௨ೝ͕ࣝͰ͖ɺ

    Ϩεϙϯεͷଊ͑ํ (Ϋϥε΁ͷϚοϐϯάͷ࢓ํ) ͕҆ఆ͢Δɻ

    View Slide

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

    View Slide

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

    αʔϏεʹ·͕ͨͬͯσʔλΛऔಘ͍ͨ࣌͠΋͋Δ

    View Slide

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

    View Slide

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

    View Slide

  28. ׬શୈ2ܗଶRESTful

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  32. ୈ2ܗଶͷRESTfulΛ΍Γ͖Δ
    • جຊతʹɺϨϕϧ2·Ͱ͸΍Γ͖Δʹӽͨ͜͠ͱ͸ͳ͍
    • APIʹҰ؏ੑΛ࣋ͨͤΔͨΊͷɺྑ੍͍໿ʹͳΔ
    • Ϩϕϧ3 (ڀۃܗଶ) ʹ͢Δʹ͸ɺ

    Ϧλʔϯ΋͋Δ͕ίετ΋͋Δ
    • ࠓͷͱ͜Ζίετͷ͕େ͖͍ͱ൑அ
    • ߟ͑ํ͸෦෼తʹར༻͍ͯ͠Δ

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  39. ू໿͸ϑϩϯτͷࣗ༝
    • ྫ͑͹͸͡Ίʹ Ranking ͚ͩΛҰ୴
    औಘͯ͠ɺͦΕΛඳըͭͭ͠ɺ

    ࣍ͷϦΫΤετͰ RankingUser ͱ
    UserProfile ΛऔΓʹߦͬͯ΋͍͍

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  44. 1ষ ·ͱΊ
    • ڧ͍Ϧιʔεࢦ޲ͷ੍໿ʹΑΓɺWeb API͕

    ؕΓ͕ͪͳ᠘ΛճආͰ͖Δ
    • ը໘࠷దԽʹ͸ BFF Λར༻͢Δ
    • RESTful (ୈ2ܗଶ) Λ΍Γ͖Δ
    • υϝΠϯϞσϧͷߟ࡯͕伴

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  54. 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

    View Slide

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

    ೔ຊޠ༁ DHH͸ͲͷΑ͏ʹRailsͷίϯτϩʔϥΛॻ͘ͷ͔ , POSTD

    View Slide

  56. 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

    View Slide

  57. 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

    View Slide

  58. ྫ: Ranking API

    View Slide

  59. // ͋ΔϥϯΩϯάΛऔಘ͢Δ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 }
    ]
    }

    View Slide

  60. // ͋ΔϥϯΩϯάΛऔಘ͢Δ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 }
    ]
    }
    ͚ͩ͜͜ɺೝূϢʔβࢹ఺ͰͷϥϯΩϯά৘ใ

    View Slide

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

    View Slide

  62. ϦιʔεʹରԠ͢ΔϞσϧΛߟ͑Δ
    • ฦ͍ͨ͠ͷ͸ 

    Ranking + Ϣʔβ͔ΒΈͨRanking৘ใ
    • Rankingͦͷ΋ͷ͸ɺ୭͔Βݟͯ΋ಉ͡΋ͷͳ͸ͣ
    • ฦ͢ϦιʔεΛ UserRanking ͱଊ͑ͯΈΔ

    View Slide

  63. 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

    View Slide

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

    View Slide

  65. 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

    View Slide

  66. V1 Users Rankings Controller
    • ϧʔςΟϯά͸ GET /v1/users/me/rankings/:id ͱͨ͠
    • `me` ͸ೝূ͞ΕͨϢʔβΛද͢ɺuser_idͷΤΠϦΞε
    • ࢦఆͨ͠Ϣʔβࢹ఺ͰͷϥϯΩϯά͕ཉ͍͠ͱ͖͸ 

    GET /v1/users/:user_id/rankings/:id
    • ϚΠΫϩαʔϏεؒͰAPIΛར༻͢Δͱ͖͸ɺͪ͜Β͕࢖ΘΕΔ

    View Slide

  67. # 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

    View Slide

  68. # 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ϝιουʹ·ͱΊΔ

    View Slide

  69. # 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 ʹ௚઀
    ϞσϧΛ౉͢

    View Slide

  70. ී௨ͷControllerͱͷҧ͍
    • ಈతʹHTMLΛੜ੒͢ΔControllerͷ৔߹ɺ

    ඞཁͳσʔλΛΠϯελϯεม਺ʹηοτ͢Δ
    • ಉ͡API޲͚ͷγϦΞϥΠβͰ΋ɺ rabl ͸ͦΕͱಉ͡ࢥ૝

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  75. 1) ϔομ೿
    Best Practices for Designing a Pragmatic RESTful API , Vinay Sahni

    ຋༁: WebAPI ઃܭͷϕετϓϥΫςΟε , mserizawa

    View Slide

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

    View Slide

  77. ๻ݸਓͷߟ͑
    • ϔομ͸ͿͬͪΌ͚࢖͍ͮΒ͍ɺʹಉҙ
    • ͨͱ͑͹BFFͷϨΠϠͰAPIΛ·ͱΊ͍ͨέʔε

    1ϦΫΤετʹରͯ͠HTTPϔομ͸౰વ1ͭ
    • "ڧ͍Ϧιʔεࢦ޲"͸ɺग़དྷΔݶΓकΓ͍ͨ
    • ʮϖʔδϯάʯ΋ҰͭͷϦιʔεͱͯ͠ଊ͑ͯΈͨΒ?

    View Slide

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

    View Slide

  79. // 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
    ϖʔδϯά͋Γͷ

    ϢʔβҰཡɻ

    View Slide

  80. ڧ͍Ϧιʔεࢦ޲Λద༻ͨ͠
    • ϧʔϧΛγϯϓϧͳ··อͭ͜ͱʹ੒ޭͨ͠
    • ͜ΕͰࠔ͍ͬͯͳ͍͠ɺ࣮ࡍʹӡ༻Ͱ͖͍ͯΔ
    • index ͱ paging Ͱ͸ҧ͏ϦιʔεΛฦ͍ͯ͠ΔͷͰɺ

    index Ͱ͸τοϓϨϕϧͷ഑ྻɺ

    paging Ͱ͸ dataҎԼʹ഑ྻɺͱ֊૚͕มΘͬͯΔͷ͸ҧ࿨ײͳ͍
    • ޙ͔Βϖʔδϯά͕ඞཁʹͳͬͨΒɺͦΕ͸΋͏ޙํޓ׵ੑ͕ͳ͘
    ͳΔมߋͱଊ͑ͯɺURIม͑ͨ΄͏͕͍͍ͱׂΓ੾͍ͬͯΔ

    View Slide

  81. ద༻੒ޭ

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  85. Have a Good API Life!
    @qsona

    View Slide