Building an API in Rails without Realizing It

2,343 views
2,293 views

Published on

Presented at Confoo (Montreal, Canada) on 3/1/2013

In this talk I’ll show you how to build your application and get a working, well tested, and useable API in the process, with almost no extra overhead. I’ll also show you how to do it without making your controllers a mess of respond_to blocks. If anything, you’re controllers will become cleaner and leaner.

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,343
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
23
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Building an API in Rails without Realizing It

  1. 1. Rails APIsMonday, February 25, 13
  2. 2. @markbatesMonday, February 25, 13
  3. 3. Monday, February 25, 13
  4. 4. Monday, February 25, 13
  5. 5. http://www.metacasts.tv CONFOO2013Monday, February 25, 13
  6. 6. Rails APIsMonday, February 25, 13
  7. 7. Rails APIsMonday, February 25, 13
  8. 8. e b APIs Rails WMonday, February 25, 13
  9. 9. you’re probably doing it wrongMonday, February 25, 13
  10. 10. Don’t Panic!Monday, February 25, 13
  11. 11. most APIs are an after thoughtMonday, February 25, 13
  12. 12. we can prevent that!Monday, February 25, 13
  13. 13. 3 simple rules for building an APIMonday, February 25, 13
  14. 14. 1. consume your own APIMonday, February 25, 13
  15. 15. 2. document your APIMonday, February 25, 13
  16. 16. 3. version your APIMonday, February 25, 13
  17. 17. building the APIMonday, February 25, 13
  18. 18. SOAMonday, February 25, 13
  19. 19. Service Oriented ArchitectureMonday, February 25, 13
  20. 20. SOA ProsMonday, February 25, 13
  21. 21. SOA Pros • Scales EasilyMonday, February 25, 13
  22. 22. SOA Pros • Scales Easily • Separate Concerns/Very CleanMonday, February 25, 13
  23. 23. SOA Pros • Scales Easily • Separate Concerns/Very Clean • Can be easier to maintainMonday, February 25, 13
  24. 24. SOA Pros • Scales Easily • Separate Concerns/Very Clean • Can be easier to maintain • Solid ArchitectureMonday, February 25, 13
  25. 25. SOA Pros • Scales Easily • Separate Concerns/Very Clean • Can be easier to maintain • Solid Architecture • Easier to refactor/rebuildMonday, February 25, 13
  26. 26. SOA ConsMonday, February 25, 13
  27. 27. SOA Cons • Can be more difficult to maintainMonday, February 25, 13
  28. 28. SOA Cons • Can be more difficult to maintain • More complex deploysMonday, February 25, 13
  29. 29. SOA Cons • Can be more difficult to maintain • More complex deploys • Managing several applicationsMonday, February 25, 13
  30. 30. SOA Cons • Can be more difficult to maintain • More complex deploys • Managing several applications • Potential for ‘out-of-sync’ appsMonday, February 25, 13
  31. 31. SOA Cons • Can be more difficult to maintain • More complex deploys • Managing several applications • Potential for ‘out-of-sync’ apps • More difficult to test integrationMonday, February 25, 13
  32. 32. API ClientMonday, February 25, 13
  33. 33. Client API ClientMonday, February 25, 13
  34. 34. Client API Client ClientMonday, February 25, 13
  35. 35. Client Service 1 Service 2 Client Service 3 ClientMonday, February 25, 13
  36. 36. a quick detourMonday, February 25, 13
  37. 37. Rails encourages poor API design!Monday, February 25, 13
  38. 38. Monday, February 25, 13
  39. 39.    #  POST  /todos    #  POST  /todos.json    def  create class  TodosController  <  ApplicationController        @todo  =  Todo.new(params[:todo])    #  GET  /todos      #  GET  /todos.json        respond_to  do  |format|    def  index            if  @todo.save        @todos  =  Todo.all                format.html  {  redirect_to  @todo,  notice:  Todo  was  successfully  created.  }                  format.json  {  render  json:  @todo,  status:  :created,  location:  @todo  }        respond_to  do  |format|            else            format.html  #  index.html.erb                format.html  {  render  action:  "new"  }            format.json  {  render  json:  @todos  }                format.json  {  render  json:  @todo.errors,  status:  :unprocessable_entity  }        end            end    end        end      end    #  GET  /todos/1      #  GET  /todos/1.json    #  PUT  /todos/1    def  show    #  PUT  /todos/1.json        @todo  =  Todo.find(params[:id])    def  update          @todo  =  Todo.find(params[:id])        respond_to  do  |format|              format.html  #  show.html.erb        respond_to  do  |format|            format.json  {  render  json:  @todo  }            if  @todo.update_attributes(params[:todo])        end                format.html  {  redirect_to  @todo,  notice:  Todo  was  successfully  updated.  }    end                format.json  {  head  :no_content  }              else    #  GET  /todos/new                format.html  {  render  action:  "edit"  }    #  GET  /todos/new.json                format.json  {  render  json:  @todo.errors,  status:  :unprocessable_entity  }    def  new            end        @todo  =  Todo.new        end      end        respond_to  do  |format|              format.html  #  new.html.erb    #  DELETE  /todos/1            format.json  {  render  json:  @todo  }    #  DELETE  /todos/1.json        end    def  destroy    end        @todo  =  Todo.find(params[:id])          @todo.destroy    #  GET  /todos/1/edit      def  edit        respond_to  do  |format|        @todo  =  Todo.find(params[:id])            format.html  {  redirect_to  todos_url  }    end            format.json  {  head  :no_content  }        end    end endMonday, February 25, 13
  40. 40. Don’t Scaffold!Monday, February 25, 13
  41. 41. Monday, February 25, 13
  42. 42. class  TodosController  <  ApplicationController      def  index        @todos  =  Todo.all    end      def  show        @todo  =  Todo.find(params[:id])    end      def  new        @todo  =  Todo.new    end      def  edit        @todo  =  Todo.find(params[:id])    end      def  create        @todo  =  Todo.new(params[:todo])        if  @todo.save            redirect_to  @todo,  notice:  Todo  was  successfully  created.        else            render  action:  "new"        end    end      def  update        @todo  =  Todo.find(params[:id])          if  @todo.update_attributes(params[:todo])            redirect_to  @todo,  notice:  Todo  was  successfully  updated.        else            render  action:  "edit"        end    end      def  destroy        @todo  =  Todo.find(params[:id])        @todo.destroy        redirect_to  todos_path,  notice:  Todo  was  successfully  destroyed.    end endMonday, February 25, 13
  43. 43. class  TodosController  <  ApplicationController    inherit_resources endMonday, February 25, 13
  44. 44. Inherited Resources https://github.com/josevalim/inherited_resourcesMonday, February 25, 13
  45. 45. Monday, February 25, 13
  46. 46. class  Api::V1::TodosController  <  ApplicationController    respond_to  :json      before_filter  do        request.format  =  :json    end      def  index        @todos  =  Todo.all        respond_with  @todos    end      def  show        @todo  =  Todo.find(params[:id])        respond_with  @todo    end      def  create        @todo  =  Todo.new(params[:todo])        if  @todo.save            respond_with  @todo        else            render  json:  @todo.errors,  status:  :unprocessable_entity        end    end      def  update        @todo  =  Todo.find(params[:id])          if  @todo.update_attributes(params[:todo])            respond_with  @todo        else            render  json:  @todo.errors,  status:  :unprocessable_entity        end    end      def  destroy        @todo  =  Todo.find(params[:id])        @todo.destroy        head  :no_content    end endMonday, February 25, 13
  47. 47. version your API! Api::V1::TodosController /api/v1/todosMonday, February 25, 13
  48. 48. i prefer URL versioningMonday, February 25, 13
  49. 49. others prefer header versioningMonday, February 25, 13
  50. 50. just pick one and stick with it!Monday, February 25, 13
  51. 51. SOA ReviewMonday, February 25, 13
  52. 52. SOA Review • We’ve cleaned up our codeMonday, February 25, 13
  53. 53. SOA Review • We’ve cleaned up our code • We know the API WorksMonday, February 25, 13
  54. 54. SOA Review • We’ve cleaned up our code • We know the API Works • We’re now in a good place to scaleMonday, February 25, 13
  55. 55. consuming the APIMonday, February 25, 13
  56. 56. don’t use Rails viewsMonday, February 25, 13
  57. 57. JavaScriptMonday, February 25, 13
  58. 58. CORSMonday, February 25, 13
  59. 59. Cross-origin Resource SharingMonday, February 25, 13
  60. 60. rack-cors https://github.com/cyu/rack-corsMonday, February 25, 13
  61. 61. module  YourApp    class  Application  <  Rails::Application      #  ...      config.middleware.use  Rack::Cors  do        allow  do            origins  *            resource  *,  headers:  :any,                                          methods:  [:get,  :post,  :put,  :delete,  :options]        end    end     endMonday, February 25, 13
  62. 62. JavaScript ProsMonday, February 25, 13
  63. 63. JavaScript Pros • Scales Easily/Pushes processing to client sideMonday, February 25, 13
  64. 64. JavaScript Pros • Scales Easily/Pushes processing to client side • Separate Concerns/Very CleanMonday, February 25, 13
  65. 65. JavaScript Pros • Scales Easily/Pushes processing to client side • Separate Concerns/Very Clean • Can be easier to maintainMonday, February 25, 13
  66. 66. JavaScript Pros • Scales Easily/Pushes processing to client side • Separate Concerns/Very Clean • Can be easier to maintain • “Responsive/Native” feel for clientsMonday, February 25, 13
  67. 67. JavaScript Pros • Scales Easily/Pushes processing to client side • Separate Concerns/Very Clean • Can be easier to maintain • “Responsive/Native” feel for clients • Easily consumes your APIMonday, February 25, 13
  68. 68. JavaScript ConsMonday, February 25, 13
  69. 69. JavaScript Cons • Can be more difficult to maintainMonday, February 25, 13
  70. 70. JavaScript Cons • Can be more difficult to maintain • Multiple languages (backend/front-end)Monday, February 25, 13
  71. 71. JavaScript Cons • Can be more difficult to maintain • Multiple languages (backend/front-end) • Difficult to test integrationMonday, February 25, 13
  72. 72. JavaScript Cons • Can be more difficult to maintain • Multiple languages (backend/front-end) • Difficult to test integration • JavaScriptMonday, February 25, 13
  73. 73. JavaScript Cons • Can be more difficult to maintain • Multiple languages (backend/front-end) • Difficult to test integration • JavaScript • Paradigm shift in architectureMonday, February 25, 13
  74. 74. JavaScript Cons • Can be more difficult to maintain • Accessibility issues • Multiple languages (backend/front-end) • Difficult to test integration • JavaScript • Paradigm shift in architectureMonday, February 25, 13
  75. 75. JavaScript Cons • Can be more difficult to maintain • Accessibility issues • Multiple languages (backend/front-end) • SEO concerns • Difficult to test integration • JavaScript • Paradigm shift in architectureMonday, February 25, 13
  76. 76. JavaScript Cons • Can be more difficult to maintain • Accessibility issues • Multiple languages (backend/front-end) • SEO concerns • Difficult to test integration • !!Internet Explorer!! • JavaScript • Paradigm shift in architectureMonday, February 25, 13
  77. 77. pick a frameworkMonday, February 25, 13
  78. 78. don’t just use jQueryMonday, February 25, 13
  79. 79. the big threeMonday, February 25, 13
  80. 80. Backbone.js http://backbonejs.org/Monday, February 25, 13
  81. 81. ember http://emberjs.com/Monday, February 25, 13
  82. 82. Angular.js http://angularjs.org/Monday, February 25, 13
  83. 83. i can’t use JavaScriptMonday, February 25, 13
  84. 84. 2 approachesMonday, February 25, 13
  85. 85. “compiled” sitesMonday, February 25, 13
  86. 86. build your own API library (and open source it!)Monday, February 25, 13
  87. 87. Monday, February 25, 13
  88. 88. class  TodosController  <  ApplicationController      def  index        @todos  =  ApiLib::Todo.all    end      def  show        @todo  =  ApiLib::Todo.find(params[:id])    end      def  new        @todo  =  ApiLib::Todo.new    end      def  edit        @todo  =  ApiLib::Todo.find(params[:id])    end      def  create        @todo  =  ApiLib::Todo.new(params[:todo])        if  @todo.save            redirect_to  @todo,  notice:  Todo  was  successfully  created.        else            render  action:  "new"        end    end      def  update        @todo  =  ApiLib::Todo.find(params[:id])          if  @todo.update_attributes(params[:todo])            redirect_to  @todo,  notice:  Todo  was  successfully  updated.        else            render  action:  "edit"        end    end      def  destroy        @todo  =  ApiLib::Todo.find(params[:id])        @todo.destroy        redirect_to  todos_path,  notice:  Todo  was  successfully  destroyed.    end endMonday, February 25, 13
  89. 89. hey! there is duplicate* code nowMonday, February 25, 13
  90. 90. is there? or did we just move it around?Monday, February 25, 13
  91. 91. Todo became ApiLib::TodoMonday, February 25, 13
  92. 92. we now have a reference implementationMonday, February 25, 13
  93. 93. make sure to cache!!Monday, February 25, 13
  94. 94. The HackMonday, February 25, 13
  95. 95. Please don’t do this!Monday, February 25, 13
  96. 96. I’m Serious.Monday, February 25, 13
  97. 97. Don’t use this hack!Monday, February 25, 13
  98. 98. I probably shouldn’t even show you it.Monday, February 25, 13
  99. 99. Ok, I’ll show you, but don’t tell people where you heard it.Monday, February 25, 13
  100. 100. Monday, February 25, 13
  101. 101. class  TodosController  <  ApplicationController      def  index        res  =  Api::V1::TodosController.action(:index).call(env)        @todos  =  JSON.parse(res[2].body).map  do  |data|            OpenStruct.new(data)        end    end   endMonday, February 25, 13
  102. 102. projects worth notingMonday, February 25, 13
  103. 103. rails-apiMonday, February 25, 13
  104. 104. Monday, February 25, 13
  105. 105. api_docMonday, February 25, 13
  106. 106. Monday, February 25, 13
  107. 107. Monday, February 25, 13
  108. 108. Final ThoughtsMonday, February 25, 13
  109. 109. Final Thoughts • Consume your APIMonday, February 25, 13
  110. 110. Final Thoughts • Consume your API • Version your APIMonday, February 25, 13
  111. 111. Final Thoughts • Consume your API • Version your API • Document your APIMonday, February 25, 13
  112. 112. Final Thoughts • Consume your API • Version your API • Document your API • Did I mention consume your own API?Monday, February 25, 13
  113. 113. Thank You http://www.metacasts.tv CONFOO2013 @markbatesMonday, February 25, 13

×