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

942bb606679caf4c57b38927f83178e1?s=47 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

942bb606679caf4c57b38927f83178e1?s=128

qsona

August 05, 2017
Tweet

Transcript

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

    @ΈΜͳͷ΢ΣσΟϯά ৿ ٱଠ࿠ (@qsona) גࣜձࣾFiNC 2017/8/5 ͗Μ͟Rubyձٞ01 @ΈΜͳͷ΢ΣσΟϯά
  2. whoami • ৿ ٱଠ࿠ (΋Γ ͖Ύ͏ͨΖ͏) • Twitter: qsona (͖Ύ͏ͦͳ)

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

  4. whoami • 2013- Node.js ͰͷήʔϜ։ൃ(αʔόαΠυ) • 2016/2- גࣜձࣾFiNCॴଐ • Ruby

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

    on Rails, Microservices Architecture • ࣾྺ=Railsྺ=1೥൒ ͓ͯ΍ΘΒ͔ʹʂʂ
  6. whoami • Microservices Meetup Λ
 ӡӦ͍ͯ͠·͢ • @ FiNC •

    ෆఆظ։࠵
  7. ࠓ೔ͷτϐοΫ • ϚΠΫϩαʔϏε • Ruby on Rails • Web API

    ͲΕ΋FiNCͰͷ։ൃͰ
 େࣄʹ͍ͯ͠Δ΋ͷɻ
  8. גࣜձࣾFiNC ͱ͸ • ͗Μ͟ʹ͋ΔձࣾͰ͢ • ݱࡏ͸ @ ༗ָொ • ͦͷલ͸

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

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

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

    ΠϯϑϥΛࢧ͑Δ
  13. ࠓ೔ͷΞδΣϯμ 1. Ұ؏ੑͷ͋ΔWeb APIઃܭ
 ϚΠΫϩαʔϏεࢦ޲։ൃͷࢹ఺Λަ͑ɺWeb APIઃܭΛٞ࿦͠·͢ɻ 2. Rails API։ൃͷϓϥΫςΟε
 ্هͷWeb

    APIઃܭʹର͠ɺRailsͰͷ࣮૷දݱΛ༩͍͖͑ͯ·͢ɻ 3. ੍໿͔Β֎ΕͨAPIΛ࡞Δ࣌
 ͜͜·ͰͰ࿩ͨ͜͠ͱͷྫ֎ʹͳΔΑ͏ͳέʔεΛߟ͑ͯΈ·͢ɻ
  14. 1. Ұ؏ੑͷ͋ΔWeb APIઃܭ

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

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

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

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

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

  20. Ϧιʔεͷྫ // GET /v1/users/1 { // User Ϧιʔε "id": 123,

    "name": "qsona", "age": 17, "jobs": [ // Job Ϧιʔεͷ഑ྻ { "id": 2, "name": "ձࣾһ" }, { "id": 7, "name": "ࣗ୐ܯඋһ" } ] }
  21. Ϧιʔεͱ͸? • αʔόɾΫϥΠΞϯτؒͰ߹ҙͰ͖͍ͯΔɺϞϊͷ୯Ґ • ΫϥΠΞϯτ͸ɺϦιʔεͷ୯ҐͰΫϥεΛੜ੒͢Δ • (Ͱ͖Ε͹) اըαΠυ΋ͦͷ୯ҐΛཧղ͍ͯ͠Δ • Domain-Driven

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

    Design Ͱ͍͏ͱ͜ΖͷυϝΠϯϞσϧͱ
 ରԠ͢Δ => APIઃܭΛߟ͑ΔͨΊʹ͸
 ϏδωευϝΠϯͷߟ࡯͕ඞਢ
  23. ͜ͷ੍໿ʹΑΔϝϦοτ • ϏδωευϝΠϯʹ͍ͭͯΑ͘ߟ࡯͠ɺUIʹ΂ͬͨΓͳAPI͕࡞ΒΕΔͷΛ๷͙ • APIͷ໾ׂ͕1ͭʹఆ·ΓɺສೳͳAPI͸࡞ΒΕʹ͘͘ͳΔɻ • ฦ͢΋ͷ͸ඞͣϦιʔεͰ͋ΓɺͦͷϦιʔεΛෳ਺ͷAPIͰ࠶ར༻͢ΔͷͰɺ
 ࢓༷͕҆ఆ͢Δ (API͝ͱʹඍົʹҧ͏Ωʔ͕ฦ͞ΕΔɺΈ͍ͨͷ͕ͳ͘ͳΔ) •

    ΫϥΠΞϯτؒ (ྫ͑͹iOS/Android) Ͱͷڞ௨ೝ͕ࣝͰ͖ɺ
 Ϩεϙϯεͷଊ͑ํ (Ϋϥε΁ͷϚοϐϯάͷ࢓ํ) ͕҆ఆ͢Δɻ
  24. Q.ΫϥΠΞϯτͷෛ୲͕૿͑ΔͷͰ͸? • ͳΜͰ΋ϦιʔεΛฦ͢ͱɺΫϥΠΞϯτ͔Βෳ਺ͷ APIΛୟ͘͜ͱ͕૿͑ΔͷͰ͸? • ࠷ѱɺN+1ͳϦΫΤετ͕ඈͿΈ͍ͨͳ͜ͱ͕ى͜Δͷ Ͱ͸?

  25. APIઃܭͰେମղܾͰ͖Δ • Ϧιʔεͷཻ౓Λɺࡉ͔͗͘͢͠ͳ͍͜ͱ • ΞϓϦέʔγϣϯ্ͷυϝΠϯϞσϧͷཻ౓ • ςʔϒϧͷ୯ҐͰ͸ͳ͍ • ϦΫΤετͷ N+1

    ໰୊͕ى͜Δͷ͸ɺϦιʔεͷཻ౓ͷϛε=APIઃܭϛ εͰ͋Δ͜ͱ͕΄ͱΜͲ • ͱ͸͍͑ɺຊདྷؔ܎ͷͳ͍ϦιʔεΛ1ը໘Ͱෳ਺ར༻ͨ͠Γɺ
 αʔϏεʹ·͕ͨͬͯσʔλΛऔಘ͍ͨ࣌͠΋͋Δ
  26. BFF (Backends For Frontends) • ϑϩϯτΤϯυͷͨΊͷαʔόʔ • ΫϥΠΞϯτͱɺόοΫΤϯυαʔϏεͷதؒʹҐஔ ͢Δ •

    ෳ਺ͷϚΠΫϩαʔϏεͷAPIΛɺฒྻ/௚ྻͰୟ͖ɺ ϦιʔεΛ·ͱΊΔ໾໨Λ࣋ͭ (API Aggregation)
  27. step-by-step BFF - Yosuke Furukawa (Microservices Meetup vol.5)

  28. ׬શୈ2ܗଶRESTful

  29. RESTfulͷܗଶ Richardson Maturity Model - Martin Fowler • Ϩϕϧ1: ϦιʔεͱURIͰ

    ͷදݱ • Ϩϕϧ2: HTTPͷಈࢺΛਖ਼ ͘͠࢖͍෼͚Δ • Ϩϕϧ3: ϋΠύʔϝσΟΞ ίϯτϩʔϧ (HATEOAS)
  30. RESTful ୈ1ܗଶ • path ͰϦιʔεΛදݱ͢Δ • ex) GET /v1/users/:user_id •

    User Ϧιʔε • ex) GET /v1/users/:user_id/jobs • User Ϧιʔεʹैଐ͢Δ Job Ϧιʔεͷ഑ྻ • Ϧιʔεͷैଐؔ܎͕Θ͔Γ΍͍͢
  31. RESTful ୈ2ܗଶ • HTTPͷಈࢺ (GET, POST, ...) Λར༻͢Δ • ex)

    POST /v1/users ... Ϣʔβ࡞੒ • HTTPඪ४ʹଇΔϝϦοτ͕͋Δ • pathʹಈࢺΛؚΊͳ͍ͱ͍͏੍໿͕ɺϦιʔ εΛߟ࡯͢Δ͜ͱΛଅ͢
  32. ୈ2ܗଶͷRESTfulΛ΍Γ͖Δ • جຊతʹɺϨϕϧ2·Ͱ͸΍Γ͖Δʹӽͨ͜͠ͱ͸ͳ͍ • APIʹҰ؏ੑΛ࣋ͨͤΔͨΊͷɺྑ੍͍໿ʹͳΔ • Ϩϕϧ3 (ڀۃܗଶ) ʹ͢Δʹ͸ɺ
 Ϧλʔϯ΋͋Δ͕ίετ΋͋Δ

    • ࠓͷͱ͜Ζίετͷ͕େ͖͍ͱ൑அ • ߟ͑ํ͸෦෼తʹར༻͍ͯ͠Δ
  33. ࣮ྫ ʙ FiNC Appͷ ʮϥϯΩϯάʯ ػೳͷAPI ʙ

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

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

    • ( ranking_users )
  36. RankingUser#index API • RankingUser Ϧιʔε • score, rank • user_id

    • ranking_idͱɺظؒ(today/total) Λ ύϥϝʔλͰड͚Δ
  37. UserProfile API • UserProfile Ϧιʔε • name, image • ෳ਺ͷ

    user_id ΛύϥϝʔλͰड ͚ͯɺ഑ྻͰฦ͢ • ͜ͷAPI͚ͩ͸ɺϝΠϯαʔϏε ʹଐ͍ͯ͠Δ
  38. BFFͰू໿͢Δ 1. Ranking औಘ 2. Ranking id͔ΒɺRanking UserΛ ഑ྻͰऔಘ 3.

    Ranking Userͷ user_id഑ྻ͔Βɺ UserProfile Λ഑ྻͰऔಘ
  39. ू໿͸ϑϩϯτͷࣗ༝ • ྫ͑͹͸͡Ίʹ Ranking ͚ͩΛҰ୴ औಘͯ͠ɺͦΕΛඳըͭͭ͠ɺ
 ࣍ͷϦΫΤετͰ RankingUser ͱ UserProfile

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

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

    ͸΋ͬͱਏ͍ • BFF͸۪͔ʹɺόοΫΤϯυΛݡ͘͢΂͖
  42. υϝΠϯͱͯ͠ͷߟ࡯ • ʮλϒʯΛυϝΠϯͱͯ͠ଊ͑ͯΈΔ • Ranking has_many Tabs • Tab has_many

    RankingUsers • Tab͸ɺRankingUserͷू߹ͷऔΓํΛ࣋ͭ • ΫϥΠΞϯτΤϯδχΞͱ͜ͷઃܭͷٞ࿦Λ ߦ͍ɺ2࣌ؒΛඅ΍ͨ͠ (ઃܭॏཁ)
  43. υϝΠϯͰਖ਼ղͩͬͨ • ॊೈͳӡ༻͕Մೳʹͳͬͨ • ྫ͑͹ɺαʔόଆͷ࣮૷͚ͩͰ Yesterday λϒΛ௥ՃͰ͖Δ • ΞϓϦέʔγϣϯͷ࢓༷Λਖ਼͘͠൓ө ͍ͯ͠Δঢ়ଶ

    • αʔό/ΫϥΠΞϯτؒͷೝࣝ΋ڞ௨ʹ
  44. 1ষ ·ͱΊ • ڧ͍Ϧιʔεࢦ޲ͷ੍໿ʹΑΓɺWeb API͕
 ؕΓ͕ͪͳ᠘ΛճආͰ͖Δ • ը໘࠷దԽʹ͸ BFF Λར༻͢Δ

    • RESTful (ୈ2ܗଶ) Λ΍Γ͖Δ • υϝΠϯϞσϧͷߟ࡯͕伴
  45. 2. Rails API։ൃͷϓϥΫςΟε

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

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

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

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

    • ී௨͸ Model 1ͭʹ Serializer 1ͭΛରԠͤ͞Δ
  50. Ϧιʔεࢦ޲ͱͷରԠ • Serializer Ϋϥε͕ APIͷϦιʔεʹରԠ͢Δ • 1ͭͷAPIͰɺModelΛ1͚ͭͩγϦΞϥΠζ͢Δ • γϦΞϥΠβ͸Ҿ਺ΛऔΒͳ͍ •

    શͯͷ৘ใ͕1ͭͷModelʹೖ͍ͬͯΔ • instance_options (ͱ͍͏ active_model_serializersͷػೳ) ͸࢖Θͳ͍
  51. RESTful (ୈ2ܗଶ·Ͱ) ͷදݱ

  52. RESTful (ୈ2ܗଶ·Ͱ) ͷදݱ • Rails Wayʹ৐Δ • routes / ActionController

    • pathͱControllerઃܭ • ύϥϝʔλ͔ΒϞσϧΛҾ͘ίʔυΛڞ௨Խ͢Δ • DHHͷControllerઃܭ
  53. pathͱControllerઃܭ • path͕ڞ௨Ͱ͋Ε͹ɺಉ͡ϞσϧΛ࢖͏͸ͣ • ҎԼͷ3ͭͷpath͕͋Δͱ͢ΔͱɺͲΕ΋ಉ͡UserΛ࢖͏͸ͣ • /v1/users/:user_id • /v1/users/:user_id/jobs •

    /v1/users/:user_id/parent • ͦͷ෦෼Λڞ௨Ͱ࢖͏͜ͱͰɺͦͷ੍໿ΛकΕΔ
  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
  55. DHHͷControllerઃܭ • Controller ʹఆٛ͢ΔΞΫγϣϯ͸جຊ7ΞΫγϣϯͷΈ • APIͰ͸5ΞΫγϣϯ (index, show, create, update,

    destroy) • ͦΕҎ֎Λఆٛͨ͘͠ͳͬͨΒɺίϯτϩʔϥΛ෼ׂ͢Δ How DHH Organizes His Rails Controllers , Jerome Dalbert
 ೔ຊޠ༁ DHH͸ͲͷΑ͏ʹRailsͷίϯτϩʔϥΛॻ͘ͷ͔ , POSTD
  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
  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
  58. ྫ: Ranking API

  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 } ] }
  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 } ] } ͚ͩ͜͜ɺೝূϢʔβࢹ఺ͰͷϥϯΩϯά৘ใ
  61. Ranking (ActiveRecord) # == Schema Information # id :bigint #

    name :string class Ranking < ApplicationRecord has_many :ranking_users end
  62. ϦιʔεʹରԠ͢ΔϞσϧΛߟ͑Δ • ฦ͍ͨ͠ͷ͸ 
 Ranking + Ϣʔβ͔ΒΈͨRanking৘ใ • Rankingͦͷ΋ͷ͸ɺ୭͔Βݟͯ΋ಉ͡΋ͷͳ͸ͣ •

    ฦ͢ϦιʔεΛ UserRanking ͱଊ͑ͯΈΔ
  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
  64. UserRanking (non-AR Model) • Ranking + User ͔ΒͳΔϞσϧ • Ranking

    ͷϝιου͸delegate͍ͯ͠Δ • ໘౗ͩͬͨΒmethod_missingͰ... • "User͔ΒݟͨRanking" ͷϝιουΛ௥Ճ͍ͯ͠Δ • my_score / my_rank
  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
  66. V1 Users Rankings Controller • ϧʔςΟϯά͸ GET /v1/users/me/rankings/:id ͱͨ͠ •

    `me` ͸ೝূ͞ΕͨϢʔβΛද͢ɺuser_idͷΤΠϦΞε • ࢦఆͨ͠Ϣʔβࢹ఺ͰͷϥϯΩϯά͕ཉ͍͠ͱ͖͸ 
 GET /v1/users/:user_id/rankings/:id • ϚΠΫϩαʔϏεؒͰAPIΛར༻͢Δͱ͖͸ɺͪ͜Β͕࢖ΘΕΔ
  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
  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ϝιουʹ·ͱΊΔ
  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 ʹ௚઀ ϞσϧΛ౉͢
  70. ී௨ͷControllerͱͷҧ͍ • ಈతʹHTMLΛੜ੒͢ΔControllerͷ৔߹ɺ
 ඞཁͳσʔλΛΠϯελϯεม਺ʹηοτ͢Δ • ಉ͡API޲͚ͷγϦΞϥΠβͰ΋ɺ rabl ͸ͦΕͱಉ͡ࢥ૝

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

    Ͱ͸ͳ͘୯ʹ `ranking`
  72. 2ষ ·ͱΊ • ڧ͍Ϧιʔεࢦ޲ΛRailsͰकΔʹ͸ɺͦΕʹ߹ͬͨγϦΞ ϥΠβ (ྫ͑͹ active_model_serializers) ΛબͿ • ϦιʔεʹରԠ͢ΔϞσϧ

    (AR/non-AR) Λ࡞Δ • RESTfulΛकΔʹ͸ɺRails wayʹ৐͍͚ͬͯ͹͍͍ • Controller ͷ࢖͍ํΛ޻෉͠ɺpathͷղऍΛڞ௨Խ͢Δ
  73. 3. ੍໿͔Β֎ΕͨAPIΛ࡞Δ࣌

  74. ྫ) ϖʔδϯά͕͋ΔAPI • Α͘RESTfulͷจ຺Ͱٞ࿦ʹͳΔྫ • Ϧιʔεͷ഑ྻ͕͋ΓɺͦΕͱ͸ผ్ϖʔδϯάʹؔ͢Δ৘ใΛฦ ͢ͱ͖ • ͦͷ৘ใ͸Ͳ͜ʹஔ͘΂͖͔? •

    ڧ͍Ϧιʔεࢦ޲͸कΕΔͷ͔? • (τοϓϨϕϧΛ഑ྻʹ͢ΔͱɺΩʔ͸ੜ΍ͤͳ͍)
  75. 1) ϔομ೿ Best Practices for Designing a Pragmatic RESTful API

    , Vinay Sahni
 ຋༁: WebAPI ઃܭͷϕετϓϥΫςΟε , mserizawa
  76. 2) ϨεϙϯεϘσΟ೿ RESTful API ͷઃܭͷΩϗϯ , Cside

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

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

  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 ϖʔδϯά͋Γͷ
 ϢʔβҰཡɻ
  80. ڧ͍Ϧιʔεࢦ޲Λద༻ͨ͠ • ϧʔϧΛγϯϓϧͳ··อͭ͜ͱʹ੒ޭͨ͠ • ͜ΕͰࠔ͍ͬͯͳ͍͠ɺ࣮ࡍʹӡ༻Ͱ͖͍ͯΔ • index ͱ paging Ͱ͸ҧ͏ϦιʔεΛฦ͍ͯ͠ΔͷͰɺ


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

  82. ଞʹ΋৭ʑ͋Δ • ex) POSTܥͷAPIͰɺ෭࡞༻ͷ݁ՌΛฦ͍ͨ͠ͱ͖͸? • ex) ύϑΥʔϚϯεʹ೉͕͋ΓɺBFFͰ΋ղܾͰ͖ͳ͍ͱ͖͸? • ΋ͪΖΜʮۜͷ஄ؙ͸ͳ͍ʯ •

    ϧʔϧ͸γϯϓϧͳํ͕͍͍͕ɺͲ͜·Ͱ੍໿Λద༻Ͱ͖Δ͔͸ ΞϓϦέʔγϣϯͷੑ࣭࣍ୈ • ྑ੍͍໿Λϕʔεʹɺ޻෉ͯ͠࠷దղΛݟ͚͍͖ͭͯ·͠ΐ͏
  83. ࠓ೔ͷ·ͱΊ • ྑ͍Web APIઃܭ͕ɺϦονͳΫϥΠΞϯτΞϓϦͷ։ ൃ΍ϚΠΫϩαʔϏεͷڠௐಈ࡞Λࢧ͑Δ • Ұ؏ੑͷ͋ΔWeb APIઃܭͷͨΊʹ͸ɺҰఆͷ੍໿Λ࣋ ͨͤɺ·ͨϏδωευϝΠϯΛΑ͘ߟ࡯͢Δ͜ͱ͕ॏཁ •

    Rails Λ༻্͍ͨهͷઃܭͷ࣮૷දݱΛ঺հͨ͠
  84. ࠓ೔࿩ͤͳ͔ͬͨ͜ͱ • APIͷఆٛͱɺυΩϡϝϯτͷࣗಈੜ੒ • FiNCͰ͸ JSON Hyper Schema / prmd,

    committee Λར༻͍ͯ͠Δ • committee + prmd ͰJSON SchemaΛ͍͍ײ͡ʹӡ༻͢Δ - ͓͓ͨͷ෺ஔ ( @ota42y ) • ࠓ೔࿩ͨ͠Α͏ͳAPI։ൃελΠϧΛखʹೖΕΔ·ͰͷಓͷΓ • FiNCͷWeb API։ൃࣄ৘ - Fumiya Shinozuka
  85. Have a Good API Life! @qsona