Building an API in Rails without Realizing It

113
Rails APIs Monday, February 25, 13

description

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.

Transcript of Building an API in Rails without Realizing It

Page 1: Building an API in Rails without Realizing It

Rails APIsMonday, February 25, 13

Page 2: Building an API in Rails without Realizing It

@markbates

Monday, February 25, 13

Page 3: Building an API in Rails without Realizing It

Monday, February 25, 13

Page 4: Building an API in Rails without Realizing It

Monday, February 25, 13

Page 5: Building an API in Rails without Realizing It

http://www.metacasts.tv

CONFOO2013

Monday, February 25, 13

Page 6: Building an API in Rails without Realizing It

Rails APIsMonday, February 25, 13

Page 7: Building an API in Rails without Realizing It

Rails APIsMonday, February 25, 13

Page 8: Building an API in Rails without Realizing It

Rails APIsWeb

Monday, February 25, 13

Page 9: Building an API in Rails without Realizing It

you’re probably doing it wrong

Monday, February 25, 13

Page 10: Building an API in Rails without Realizing It

Don’t Panic!

Monday, February 25, 13

Page 11: Building an API in Rails without Realizing It

most APIs are an after thought

Monday, February 25, 13

Page 12: Building an API in Rails without Realizing It

we can prevent that!

Monday, February 25, 13

Page 13: Building an API in Rails without Realizing It

3 simple rules for building an API

Monday, February 25, 13

Page 14: Building an API in Rails without Realizing It

1. consume your own API

Monday, February 25, 13

Page 15: Building an API in Rails without Realizing It

2. document your API

Monday, February 25, 13

Page 16: Building an API in Rails without Realizing It

3. version your API

Monday, February 25, 13

Page 17: Building an API in Rails without Realizing It

building the API

Monday, February 25, 13

Page 18: Building an API in Rails without Realizing It

SOAMonday, February 25, 13

Page 19: Building an API in Rails without Realizing It

Service Oriented Architecture

Monday, February 25, 13

Page 20: Building an API in Rails without Realizing It

SOA Pros

Monday, February 25, 13

Page 21: Building an API in Rails without Realizing It

SOA Pros

• Scales Easily

Monday, February 25, 13

Page 22: Building an API in Rails without Realizing It

SOA Pros

• Scales Easily

• Separate Concerns/Very Clean

Monday, February 25, 13

Page 23: Building an API in Rails without Realizing It

SOA Pros

• Scales Easily

• Separate Concerns/Very Clean

• Can be easier to maintain

Monday, February 25, 13

Page 24: Building an API in Rails without Realizing It

SOA Pros

• Scales Easily

• Separate Concerns/Very Clean

• Can be easier to maintain

• Solid Architecture

Monday, February 25, 13

Page 25: Building an API in Rails without Realizing It

SOA Pros

• Scales Easily

• Separate Concerns/Very Clean

• Can be easier to maintain

• Solid Architecture

• Easier to refactor/rebuild

Monday, February 25, 13

Page 26: Building an API in Rails without Realizing It

SOA Cons

Monday, February 25, 13

Page 27: Building an API in Rails without Realizing It

SOA Cons

• Can be more difficult to maintain

Monday, February 25, 13

Page 28: Building an API in Rails without Realizing It

SOA Cons

• Can be more difficult to maintain

• More complex deploys

Monday, February 25, 13

Page 29: Building an API in Rails without Realizing It

SOA Cons

• Can be more difficult to maintain

• More complex deploys

• Managing several applications

Monday, February 25, 13

Page 30: Building an API in Rails without Realizing It

SOA Cons

• Can be more difficult to maintain

• More complex deploys

• Managing several applications

• Potential for ‘out-of-sync’ apps

Monday, February 25, 13

Page 31: Building an API in Rails without Realizing It

SOA Cons

• Can be more difficult to maintain

• More complex deploys

• Managing several applications

• Potential for ‘out-of-sync’ apps

• More difficult to test integration

Monday, February 25, 13

Page 32: Building an API in Rails without Realizing It

API Client

Monday, February 25, 13

Page 33: Building an API in Rails without Realizing It

API

Client

Client

Monday, February 25, 13

Page 34: Building an API in Rails without Realizing It

API Client

Client

Client

Monday, February 25, 13

Page 35: Building an API in Rails without Realizing It

Client

Client

Client

Service 1

Service 2

Service 3

Monday, February 25, 13

Page 36: Building an API in Rails without Realizing It

a quick detour

Monday, February 25, 13

Page 37: Building an API in Rails without Realizing It

Rails encourages poor API design!

Monday, February 25, 13

Page 38: Building an API in Rails without Realizing It

Monday, February 25, 13

Page 39: Building an API in Rails without Realizing It

class  TodosController  <  ApplicationController    #  GET  /todos    #  GET  /todos.json    def  index        @todos  =  Todo.all          respond_to  do  |format|            format.html  #  index.html.erb            format.json  {  render  json:  @todos  }        end    end      #  GET  /todos/1    #  GET  /todos/1.json    def  show        @todo  =  Todo.find(params[:id])          respond_to  do  |format|            format.html  #  show.html.erb            format.json  {  render  json:  @todo  }        end    end      #  GET  /todos/new    #  GET  /todos/new.json    def  new        @todo  =  Todo.new          respond_to  do  |format|            format.html  #  new.html.erb            format.json  {  render  json:  @todo  }        end    end      #  GET  /todos/1/edit    def  edit        @todo  =  Todo.find(params[:id])    end

   #  POST  /todos    #  POST  /todos.json    def  create        @todo  =  Todo.new(params[:todo])          respond_to  do  |format|            if  @todo.save                format.html  {  redirect_to  @todo,  notice:  'Todo  was  successfully  created.'  }                format.json  {  render  json:  @todo,  status:  :created,  location:  @todo  }            else                format.html  {  render  action:  "new"  }                format.json  {  render  json:  @todo.errors,  status:  :unprocessable_entity  }            end        end    end      #  PUT  /todos/1    #  PUT  /todos/1.json    def  update        @todo  =  Todo.find(params[:id])          respond_to  do  |format|            if  @todo.update_attributes(params[:todo])                format.html  {  redirect_to  @todo,  notice:  'Todo  was  successfully  updated.'  }                format.json  {  head  :no_content  }            else                format.html  {  render  action:  "edit"  }                format.json  {  render  json:  @todo.errors,  status:  :unprocessable_entity  }            end        end    end      #  DELETE  /todos/1    #  DELETE  /todos/1.json    def  destroy        @todo  =  Todo.find(params[:id])        @todo.destroy          respond_to  do  |format|            format.html  {  redirect_to  todos_url  }            format.json  {  head  :no_content  }        end    endend

Monday, February 25, 13

Page 40: Building an API in Rails without Realizing It

Don’t Scaffold!

Monday, February 25, 13

Page 41: Building an API in Rails without Realizing It

Monday, February 25, 13

Page 42: Building an API in Rails without Realizing It

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.'    endend

Monday, February 25, 13

Page 43: Building an API in Rails without Realizing It

class  TodosController  <  ApplicationController    inherit_resourcesend

Monday, February 25, 13

Page 44: Building an API in Rails without Realizing It

https://github.com/josevalim/inherited_resources

Inherited Resources

Monday, February 25, 13

Page 45: Building an API in Rails without Realizing It

Monday, February 25, 13

Page 46: Building an API in Rails without Realizing It

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    endend

Monday, February 25, 13

Page 47: Building an API in Rails without Realizing It

Api::V1::TodosController

version your API!

/api/v1/todos

Monday, February 25, 13

Page 48: Building an API in Rails without Realizing It

i prefer URL versioning

Monday, February 25, 13

Page 49: Building an API in Rails without Realizing It

others prefer header versioning

Monday, February 25, 13

Page 50: Building an API in Rails without Realizing It

just pick one and stick with it!

Monday, February 25, 13

Page 51: Building an API in Rails without Realizing It

SOA Review

Monday, February 25, 13

Page 52: Building an API in Rails without Realizing It

SOA Review

• We’ve cleaned up our code

Monday, February 25, 13

Page 53: Building an API in Rails without Realizing It

SOA Review

• We’ve cleaned up our code

• We know the API Works

Monday, February 25, 13

Page 54: Building an API in Rails without Realizing It

SOA Review

• We’ve cleaned up our code

• We know the API Works

• We’re now in a good place to scale

Monday, February 25, 13

Page 55: Building an API in Rails without Realizing It

consuming the API

Monday, February 25, 13

Page 56: Building an API in Rails without Realizing It

don’t use Rails views

Monday, February 25, 13

Page 57: Building an API in Rails without Realizing It

JavaScript

Monday, February 25, 13

Page 58: Building an API in Rails without Realizing It

CORSMonday, February 25, 13

Page 59: Building an API in Rails without Realizing It

Cross-origin Resource Sharing

Monday, February 25, 13

Page 60: Building an API in Rails without Realizing It

https://github.com/cyu/rack-cors

rack-cors

Monday, February 25, 13

Page 61: Building an API in Rails without Realizing It

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    end

Monday, February 25, 13

Page 62: Building an API in Rails without Realizing It

JavaScript Pros

Monday, February 25, 13

Page 63: Building an API in Rails without Realizing It

JavaScript Pros

• Scales Easily/Pushes processing to client side

Monday, February 25, 13

Page 64: Building an API in Rails without Realizing It

JavaScript Pros

• Scales Easily/Pushes processing to client side

• Separate Concerns/Very Clean

Monday, February 25, 13

Page 65: Building an API in Rails without Realizing It

JavaScript Pros

• Scales Easily/Pushes processing to client side

• Separate Concerns/Very Clean

• Can be easier to maintain

Monday, February 25, 13

Page 66: Building an API in Rails without Realizing It

JavaScript Pros

• Scales Easily/Pushes processing to client side

• Separate Concerns/Very Clean

• Can be easier to maintain

• “Responsive/Native” feel for clients

Monday, February 25, 13

Page 67: Building an API in Rails without Realizing It

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 API

Monday, February 25, 13

Page 68: Building an API in Rails without Realizing It

JavaScript Cons

Monday, February 25, 13

Page 69: Building an API in Rails without Realizing It

JavaScript Cons• Can be more difficult to maintain

Monday, February 25, 13

Page 70: Building an API in Rails without Realizing It

JavaScript Cons• Can be more difficult to maintain

• Multiple languages (backend/front-end)

Monday, February 25, 13

Page 71: Building an API in Rails without Realizing It

JavaScript Cons• Can be more difficult to maintain

• Multiple languages (backend/front-end)

• Difficult to test integration

Monday, February 25, 13

Page 72: Building an API in Rails without Realizing It

JavaScript Cons• Can be more difficult to maintain

• Multiple languages (backend/front-end)

• Difficult to test integration

• JavaScript

Monday, February 25, 13

Page 73: Building an API in Rails without Realizing It

JavaScript Cons• Can be more difficult to maintain

• Multiple languages (backend/front-end)

• Difficult to test integration

• JavaScript

• Paradigm shift in architecture

Monday, February 25, 13

Page 74: Building an API in Rails without Realizing It

JavaScript Cons• Can be more difficult to maintain

• Multiple languages (backend/front-end)

• Difficult to test integration

• JavaScript

• Paradigm shift in architecture

• Accessibility issues

Monday, February 25, 13

Page 75: Building an API in Rails without Realizing It

JavaScript Cons• Can be more difficult to maintain

• Multiple languages (backend/front-end)

• Difficult to test integration

• JavaScript

• Paradigm shift in architecture

• Accessibility issues

• SEO concerns

Monday, February 25, 13

Page 76: Building an API in Rails without Realizing It

JavaScript Cons• Can be more difficult to maintain

• Multiple languages (backend/front-end)

• Difficult to test integration

• JavaScript

• Paradigm shift in architecture

• Accessibility issues

• SEO concerns

• !!Internet Explorer!!

Monday, February 25, 13

Page 77: Building an API in Rails without Realizing It

pick a framework

Monday, February 25, 13

Page 78: Building an API in Rails without Realizing It

don’t just use jQuery

Monday, February 25, 13

Page 79: Building an API in Rails without Realizing It

the big three

Monday, February 25, 13

Page 80: Building an API in Rails without Realizing It

Backbone.js

http://backbonejs.org/

Monday, February 25, 13

Page 81: Building an API in Rails without Realizing It

ember

http://emberjs.com/

Monday, February 25, 13

Page 82: Building an API in Rails without Realizing It

Angular.js

http://angularjs.org/

Monday, February 25, 13

Page 83: Building an API in Rails without Realizing It

i can’t use JavaScript

Monday, February 25, 13

Page 84: Building an API in Rails without Realizing It

2 approaches

Monday, February 25, 13

Page 85: Building an API in Rails without Realizing It

“compiled” sites

Monday, February 25, 13

Page 86: Building an API in Rails without Realizing It

build your own API library (and open source it!)

Monday, February 25, 13

Page 87: Building an API in Rails without Realizing It

Monday, February 25, 13

Page 88: Building an API in Rails without Realizing It

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.'    endend

Monday, February 25, 13

Page 89: Building an API in Rails without Realizing It

hey! there is duplicate* code

now

Monday, February 25, 13

Page 90: Building an API in Rails without Realizing It

is there? or did we just move it

around?

Monday, February 25, 13

Page 91: Building an API in Rails without Realizing It

Todo became ApiLib::Todo

Monday, February 25, 13

Page 92: Building an API in Rails without Realizing It

we now have a reference

implementation

Monday, February 25, 13

Page 93: Building an API in Rails without Realizing It

make sure to cache!!

Monday, February 25, 13

Page 94: Building an API in Rails without Realizing It

The HackMonday, February 25, 13

Page 95: Building an API in Rails without Realizing It

Please don’t do this!

Monday, February 25, 13

Page 96: Building an API in Rails without Realizing It

I’m Serious.

Monday, February 25, 13

Page 97: Building an API in Rails without Realizing It

Don’t use this hack!

Monday, February 25, 13

Page 98: Building an API in Rails without Realizing It

I probably shouldn’t even show you it.

Monday, February 25, 13

Page 99: Building an API in Rails without Realizing It

Ok, I’ll show you, but don’t tell

people where you heard it.

Monday, February 25, 13

Page 100: Building an API in Rails without Realizing It

Monday, February 25, 13

Page 101: Building an API in Rails without Realizing It

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  end

Monday, February 25, 13

Page 102: Building an API in Rails without Realizing It

projects worth noting

Monday, February 25, 13

Page 103: Building an API in Rails without Realizing It

rails-apiMonday, February 25, 13

Page 104: Building an API in Rails without Realizing It

Monday, February 25, 13

Page 105: Building an API in Rails without Realizing It

api_docMonday, February 25, 13

Page 106: Building an API in Rails without Realizing It

Monday, February 25, 13

Page 107: Building an API in Rails without Realizing It

Monday, February 25, 13

Page 108: Building an API in Rails without Realizing It

Final Thoughts

Monday, February 25, 13

Page 109: Building an API in Rails without Realizing It

Final Thoughts

• Consume your API

Monday, February 25, 13

Page 110: Building an API in Rails without Realizing It

Final Thoughts

• Consume your API

• Version your API

Monday, February 25, 13

Page 111: Building an API in Rails without Realizing It

Final Thoughts

• Consume your API

• Version your API

• Document your API

Monday, February 25, 13

Page 112: Building an API in Rails without Realizing It

Final Thoughts

• Consume your API

• Version your API

• Document your API

• Did I mention consume your own API?

Monday, February 25, 13

Page 113: Building an API in Rails without Realizing It

http://www.metacasts.tv

CONFOO2013

Thank You

@markbates

Monday, February 25, 13