Top Banner
Diseño de APIs con Ruby Edwin Cruz @soſtr8 #SGRuby Friday, June 15, 2012
86
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Diseño de APIs con Ruby

Diseño de APIs con Ruby

Edwin Cruz @softr8

#SGRuby

Friday, June 15, 2012

Page 2: Diseño de APIs con Ruby

PLAN

•Que es una API

• Como implementar una buena API

• Usando Ruby on Rails para implementar una API

• Patrones de diseño

Friday, June 15, 2012

Page 3: Diseño de APIs con Ruby

ApplicationProgrammingInterface

Friday, June 15, 2012

Page 4: Diseño de APIs con Ruby

API

Es una manera para comunicar dos aplicaciones entre ellas.

Friday, June 15, 2012

Page 5: Diseño de APIs con Ruby

TIPOS DE API

• Library

• SDK

•Web services

Friday, June 15, 2012

Page 6: Diseño de APIs con Ruby

PRIMERAS API - SOAP

SimpleObjectAccessProtocol

Friday, June 15, 2012

Page 7: Diseño de APIs con Ruby

REST

REpresentationStateTransfer

Friday, June 15, 2012

Page 8: Diseño de APIs con Ruby

CRUD

CreateReadUpdateDelete

AltasBajasCambiosConsultas

Friday, June 15, 2012

Page 9: Diseño de APIs con Ruby

REST ⋍ CRUD

Friday, June 15, 2012

Page 10: Diseño de APIs con Ruby

Recursos a través de URIUso de verbos HTTP

REST ⋍ CRUD

Friday, June 15, 2012

Page 11: Diseño de APIs con Ruby

REST-ISH + JSON

Friday, June 15, 2012

Page 12: Diseño de APIs con Ruby

REST-ISH + JSON

=

Friday, June 15, 2012

Page 13: Diseño de APIs con Ruby

REST-ISH + JSON

=Cosas Increibles

Friday, June 15, 2012

Page 14: Diseño de APIs con Ruby

RECURSO

Friday, June 15, 2012

Page 15: Diseño de APIs con Ruby

RECURSO

Cualquier cosa expuesta mediante web

Friday, June 15, 2012

Page 16: Diseño de APIs con Ruby

RECURSO

Cualquier cosa expuesta mediante webTienen una representación en datos

Friday, June 15, 2012

Page 17: Diseño de APIs con Ruby

RECURSO

Cualquier cosa expuesta mediante webTienen una representación en datosCon un servicio web intercambiamos representaciones de recursos

Friday, June 15, 2012

Page 18: Diseño de APIs con Ruby

REQUISITOS REST

Friday, June 15, 2012

Page 19: Diseño de APIs con Ruby

REQUISITOS REST

Separación de responsabilidades

Friday, June 15, 2012

Page 20: Diseño de APIs con Ruby

REQUISITOS REST

Separación de responsabilidades Cliente/Servidor

Friday, June 15, 2012

Page 21: Diseño de APIs con Ruby

REQUISITOS REST

Separación de responsabilidades Cliente/ServidorSin estado

Friday, June 15, 2012

Page 22: Diseño de APIs con Ruby

REQUISITOS REST

Separación de responsabilidades Cliente/ServidorSin estado“Cacheable”

Friday, June 15, 2012

Page 23: Diseño de APIs con Ruby

REQUISITOS REST

Separación de responsabilidades Cliente/ServidorSin estado“Cacheable”Sistema a capas

Friday, June 15, 2012

Page 24: Diseño de APIs con Ruby

REQUISITOS REST

Separación de responsabilidades Cliente/ServidorSin estado“Cacheable”Sistema a capasInterface uniforme

Friday, June 15, 2012

Page 25: Diseño de APIs con Ruby

¿PORQUÉ UN API?

Friday, June 15, 2012

Page 26: Diseño de APIs con Ruby

¿PORQUÉ UN API?

Aumenta la flexibilidad de un servicio

Friday, June 15, 2012

Page 27: Diseño de APIs con Ruby

¿PORQUÉ UN API?

Aumenta la flexibilidad de un servicioAumenta la utilidad de un servicio

Friday, June 15, 2012

Page 28: Diseño de APIs con Ruby

¿PORQUÉ UN API?

Aumenta la flexibilidad de un servicioAumenta la utilidad de un servicio

Libera los datos de usuario

Friday, June 15, 2012

Page 29: Diseño de APIs con Ruby

¿PORQUÉ UN API?

Aumenta la flexibilidad de un servicioAumenta la utilidad de un servicio

Libera los datos de usuarioProporciona valor de negocio

Friday, June 15, 2012

Page 30: Diseño de APIs con Ruby

¿QUÉ CARACTERÍSTICAS?

Friday, June 15, 2012

Page 31: Diseño de APIs con Ruby

¿QUÉ CARACTERÍSTICAS?

Fácil de implementar y mantener

Friday, June 15, 2012

Page 32: Diseño de APIs con Ruby

¿QUÉ CARACTERÍSTICAS?

Fácil de implementar y mantenerBuen rendimiento

Friday, June 15, 2012

Page 33: Diseño de APIs con Ruby

¿QUÉ CARACTERÍSTICAS?

Fácil de implementar y mantenerBuen rendimientoEscalable

Friday, June 15, 2012

Page 34: Diseño de APIs con Ruby

¿QUÉ CARACTERÍSTICAS?

Fácil de implementar y mantenerBuen rendimientoEscalableFácil de entender y usar

Friday, June 15, 2012

Page 35: Diseño de APIs con Ruby

¿CUÁLES SON LOS RETOS?

Friday, June 15, 2012

Page 36: Diseño de APIs con Ruby

¿CUÁLES SON LOS RETOS?

La red es un eslabón débil

Friday, June 15, 2012

Page 37: Diseño de APIs con Ruby

¿CUÁLES SON LOS RETOS?

La red es un eslabón débilAPI incompleta pone estrés en el cliente

Friday, June 15, 2012

Page 38: Diseño de APIs con Ruby

¿CUÁLES SON LOS RETOS?

La red es un eslabón débilAPI incompleta pone estrés en el clienteAdministrar Cambios

Friday, June 15, 2012

Page 39: Diseño de APIs con Ruby

DISEÑAR UNA BUENA API

Friday, June 15, 2012

Page 40: Diseño de APIs con Ruby

CONVENCIONES REST

Friday, June 15, 2012

Page 41: Diseño de APIs con Ruby

GET /api/products #Listado

REST ⋍ CRUD

{"products"  :      [        {"product"  :  {  "id"  :  1,  "name"  :  "Producto  1",  "status"  :  "archived"}  },        {"product"  :  {  "id"  :  2,  "name"  :  "Producto  2",  "status"  :  "active"    }  }    ]}

Friday, June 15, 2012

Page 42: Diseño de APIs con Ruby

REST ⋍ CRUD

GET /api/products/2 #Ver

{"product"  :  {  "id"  :  2,  "name"  :  "Producto  2",  "status"  :  "active"    }  }

Friday, June 15, 2012

Page 43: Diseño de APIs con Ruby

REST ⋍ CRUD

POST /api/products #Crear

{    "name"  :  "Producto  2"}

Friday, June 15, 2012

Page 44: Diseño de APIs con Ruby

REST ⋍ CRUD

PUT /api/products/2 #Actualizar

{    "name"  :  "Producto  dos"}

Friday, June 15, 2012

Page 45: Diseño de APIs con Ruby

REST ⋍ CRUD

DELETE /api/products/2 #Eliminar

Friday, June 15, 2012

Page 46: Diseño de APIs con Ruby

VERSIONANDO TU API

• API Interna (entre aplicaciones)

• API Externa (aplicacion movil ? )

• API Usuarios (publico en general)

Friday, June 15, 2012

Page 47: Diseño de APIs con Ruby

VERSIONANDO TU API

/int/api/products/ext/api/products/pub/api/products

Friday, June 15, 2012

Page 48: Diseño de APIs con Ruby

VERSIONANDO TU API

/int/api/products?version=2/ext/api/products?version=2/pub/api/products?version=2

Friday, June 15, 2012

Page 49: Diseño de APIs con Ruby

VERSIONANDO TU API

/v2/int/api/products/v2/ext/api/products/v2/pub/api/products

Friday, June 15, 2012

Page 50: Diseño de APIs con Ruby

MUNDO IDEAL

Friday, June 15, 2012

Page 51: Diseño de APIs con Ruby

MUNDO IDEAL

Uso de: Accept Header

Friday, June 15, 2012

Page 52: Diseño de APIs con Ruby

MUNDO IDEAL

Uso de: Accept Header

Accept: application/vnd.mycompany.com;version=2,application/json

Friday, June 15, 2012

Page 53: Diseño de APIs con Ruby

CODIGOS HTTP200 OK201 Created202 Accepted

400 Bad Request401 Unauthorized402 Payment Required404 Not Found409 Conflict422 Unprocessable Entity

500 Internal Server Error503 Service Unavailable

Friday, June 15, 2012

Page 54: Diseño de APIs con Ruby

CODIGOS HTTP

HTTP/1.1 401 Unauthorized

{ “errors”: [ “api_key not found” ]}

Friday, June 15, 2012

Page 55: Diseño de APIs con Ruby

CODIGOS HTTPHTTP/1.1 401 Unauthorized

{ “errors”: [ “api_key no valida”, “api_key no puede contener espacios” ]}

Friday, June 15, 2012

Page 56: Diseño de APIs con Ruby

CODIGOS HTTP

HTTP/1.1 401 Unauthorized

{ “errors”: [ “api_key no encontrada, por favor visita http://account.myapp.com/api para obtenerla” ]}

Friday, June 15, 2012

Page 57: Diseño de APIs con Ruby

CODIGOS HTTP

HTTP/1.1 400 Bad Request

{ “errors”: [ “Estructura JSON no valida”, “unexpected TSTRING, expected ‘}’ at line 2” ]}

Friday, June 15, 2012

Page 58: Diseño de APIs con Ruby

DOCUMENTACIONHTTP/1.1 422 Unprocessable Entity

{ “errors”: [ “vendor_code: no puede estar vacio” ], “documentacion”: [ “vendor_code”: [ “descripcion” : “Codigo asignado por proveedor”, “formato” : “Combinacion de tres letras seguidas de 4 numeros”, “ejemplo” : “SOL1234” ] ]}

Friday, June 15, 2012

Page 59: Diseño de APIs con Ruby

CODIGOS HTTP

HTTP/1.1 503 Service Unavailable

{ “messages”: [ “En mantenimiento” ]}

Friday, June 15, 2012

Page 60: Diseño de APIs con Ruby

OPCIONES AVANZADAS

• Simuladores

• Autenticación

• Validadores

• Limite de uso

• Rapidez

• Balanceo

Friday, June 15, 2012

Page 61: Diseño de APIs con Ruby

USANDO RUBY ON RAILS PARA

IMLEMENTAR UNA API

Friday, June 15, 2012

Page 62: Diseño de APIs con Ruby

APIS ON RAILS - REST

products GET /products(.:format) products#index POST /products(.:format) products#create new_product GET /products/new(.:format) products#newedit_product GET /products/:id/edit(.:format) products#edit product GET /products/:id(.:format) products#show PUT /products/:id(.:format) products#update DELETE /products/:id(.:format) products#destroy

MyApp::Application.routes.draw do resources :productsend

Friday, June 15, 2012

Page 63: Diseño de APIs con Ruby

APIS ON RAILS - REST

products GET /api/products(.:format) products#index POST /api/products(.:format) products#create new_product GET /api/products/new(.:format) products#newedit_product GET /api/products/:id/edit(.:format) products#edit product GET /api/products/:id(.:format) products#show PUT /api/products/:id(.:format) products#update DELETE /api/products/:id(.:format) products#destroy

MyApp::Application.routes.draw do scope ‘/api’ do resources :products endend

Friday, June 15, 2012

Page 64: Diseño de APIs con Ruby

APIS ON RAILS - VERSIONES

v2_products GET /v2/products(.:format) V1/products#index POST /v2/products(.:format) V1/products#create new_v2_product GET /v2/products/new(.:format) V1/products#newedit_v2_product GET /v2/products/:id/edit(.:format) V1/products#edit v2_product GET /v2/products/:id(.:format) V1/products#show PUT /v2/products/:id(.:format) V1/products#update DELETE /v2/products/:id(.:format) V1/products#destroy

gem 'versionist'MyApp::Application.routes.draw do api_version(:module => 'V1', :path => 'v2') do resources :products endend

Friday, June 15, 2012

Page 65: Diseño de APIs con Ruby

APIS ON RAILS, CONTROLADOR

class V2::ProductsController < ApplicationController respond_to :json def index @products = V2::Product.paginate(:page => (params[:page] || 1), :per_page => (params[:per_page] || 100)).all respond_with @products end def show @product = V2::Product.find(params[:id]) respond_with @product end def update @product = V2::Product.find(params[:id]) @product.update_attributes(params[:product]) respond_with @product end def destroy @product = V2::Product.find(params[:id]) respond_with @product.destroy endend

Friday, June 15, 2012

Page 66: Diseño de APIs con Ruby

APIS ON RAILS - MODELO

class V2::Product < Product

JSON_ATTRIBUTES = { properties: [ :id, :upc, :sku, :list_cost, :color, :dimension, :size, :created_at, :updated_at, ], methods: [ :units_on_hand ] }

end

Friday, June 15, 2012

Page 67: Diseño de APIs con Ruby

APIS ON RAILS, CONTROLADOR

gem ‘rabl’class V3::ProductsController < ApplicationController respond_to :json, :xml def index @products = V3::Product.paginate(:page => (params[:page] || 1), :per_page => (params[:per_page] || 100)).all end def show @product = V3::Product.find(params[:id]) end def update @product = V3::Product.find(params[:id]) @product.update_attributes(params[:product]) end def destroy @product = V3::Product.find(params[:id]) render json: {}, status: @product.destroy ? :ok : :unprocessable_entity endend

Friday, June 15, 2012

Page 68: Diseño de APIs con Ruby

APIS ON RAILSVISTAS

#app/views/api/v3/products/index.rabl

collection @productsattributes :id, :name, :statusnode(:url) {|product| product_url(product) }node(:current_stock) {|product| product.variants.map(&:on_hand).sum }child :variants do attributes :upc, :color, :size, :on_handend

{"products"  :      [        {"product"  :  {  "id"  :  1,  "name"  :  "Producto  1",  "status"  :  "archived",  “current_stock”  :  10,            “variants”  :  [  {“upc”  :  “ASDFS”,  “color”  :  “negro”,  “size”  :  “M”,  “on_hand”  :  10}  ]            }        }    ]}

Friday, June 15, 2012

Page 69: Diseño de APIs con Ruby

APIS ON RAILSVISTAS

gem ‘jbuilder’Jbuilder.encode do |json| json.content format_content(@message.content) json.(@message, :created_at, :updated_at)

json.author do |json| json.name @message.creator.name.familiar json.email_address @message.creator.email_address_with_name json.url url_for(@message.creator, format: :json) end

if current_user.admin? json.visitors calculate_visitors(@message) end

json.comments @message.comments, :content, :created_at

end

Friday, June 15, 2012

Page 70: Diseño de APIs con Ruby

APIS ON RAILSVISTAS

gem ‘active_model_serializer’class PostSerializer < ActiveModel::Serializer attributes :id, :body attribute :title, :key => :name

has_many :comments

def tags tags.order :name endend

Friday, June 15, 2012

Page 71: Diseño de APIs con Ruby

APIS ON RAILSSEGURIDAD

DeviseAutenticacion Flexible para aplicaciones RailsCompuesta de 12 modulos: database authenticable, token authenticable, omniauthable, confirmable, recoverable, registerable, trackable, timeoutable, validatable, lockable

Friday, June 15, 2012

Page 72: Diseño de APIs con Ruby

APIS ON RAILSSEGURIDAD

DeviseAutenticacion Flexible para aplicaciones RailsCompuesta de 12 modulos: database authenticable, token authenticable, omniauthable, confirmable, recoverable, registerable, trackable, timeoutable, validatable, lockable

Friday, June 15, 2012

Page 73: Diseño de APIs con Ruby

APIS ON RAILSSEGURIDAD

gem ‘rabl’class V3::ProductsController < ApplicationController before_filter :authenticate_user! respond_to :json, :xml def index @products = V3::Product.paginate(:page => (params[:page] || 1), :per_page => (params[:per_page] || 100)).all end def show @product = V3::Product.find(params[:id]) end def update @product = V3::Product.find(params[:id]) @product.update_attributes(params[:product]) end def destroy @product = V3::Product.find(params[:id]) render json: {}, status: @product.destroy ? :ok : :unprocessable_entity endend

Friday, June 15, 2012

Page 74: Diseño de APIs con Ruby

APIS ON RAILSPRUEBAS

describe V3::ProductsController do

before do @request.env["HTTP_ACCEPT"] = "application/json" end

describe "#index" do context "cuando no se pasa ningun atributo" do it "regresa los registros en paginas" do get :index response.should be_success data = JSON.parse(response.body) Product.count.should > 0 data['products'].length.should == Product.count end end endend

Friday, June 15, 2012

Page 75: Diseño de APIs con Ruby

APIS ON RAILSPRUEBAS

describe V3::ProductsController do

before do @request.env["HTTP_ACCEPT"] = "application/json" end

describe "#show" do context "pasando un id inexistente" do it "responde con http 404 y un mensaje de error" do get :show, id: -1 response.code.should == "404" JSON.parse(response.body)['error'].should == "ActiveRecord::RecordNotFound" JSON.parse(response.body)['message'].should == "Couldn't find Product with id=-1" end end endend

Friday, June 15, 2012

Page 76: Diseño de APIs con Ruby

APIS ON RAILSPRUEBAS

describe V3::ProductsController do

before do @request.env["HTTP_ACCEPT"] = "application/json" end

describe "#create" do context "con malos atributos" do it "responde con un error" do post :create, product: {bad_key: "foo"} response.code.should == "400" json_response = JSON.parse(response.body) json_response['error'].should == "ActiveRecord::UnknownAttributeError" json_response['message'].should == "unknown attribute: bad_key" end end endend

Friday, June 15, 2012

Page 77: Diseño de APIs con Ruby

APIS ON RAILSPRUEBAS

describe V3::ProductsController do

before do @request.env["HTTP_ACCEPT"] = "application/json" end

describe "#create" do context "con atributos correctos" do it "responde correctamente y crea el producto" do expect { post :create, product: {name: "productito"} }.to change(Product, :count).by(1) end end endend

Friday, June 15, 2012

Page 78: Diseño de APIs con Ruby

RAILS A DIETA

Friday, June 15, 2012

Page 79: Diseño de APIs con Ruby

RAILS A DIETA

Rails es modular

Friday, June 15, 2012

Page 80: Diseño de APIs con Ruby

RAILS A DIETA

Rails es modularPara crear APIs, algunos Middlewares no son

necesarios

Friday, June 15, 2012

Page 81: Diseño de APIs con Ruby

RAILS A DIETA

Rails es modularPara crear APIs, algunos Middlewares no son

necesariosrails-api

Friday, June 15, 2012

Page 82: Diseño de APIs con Ruby

<Module:0x007ff271221e40>, ActionDispatch::Routing::Helpers, #<Module:0x007ff2714ad268>, ActionController::Base, ActionDispatch::Routing::RouteSet::MountedHelpers, HasScope, ActionController::Compatibility, ActionController::ParamsWrapper, ActionController::Instrumentation, ActionController::Rescue, ActiveSupport::Rescuable, ActionController::HttpAuthentication::Token::ControllerMethods, ActionController::HttpAuthentication::Digest::ControllerMethods, ActionController::HttpAuthentication::Basic::ControllerMethods, ActionController::RecordIdentifier, ActionController::DataStreaming, ActionController::Streaming, ActionController::ForceSSL, ActionController::RequestForgeryProtection, AbstractController::Callbacks, ActiveSupport::Callbacks, ActionController::Flash, ActionController::Cookies, ActionController::MimeResponds, ActionController::ImplicitRender, ActionController::Caching, ActionController::Caching::Fragments, ActionController::Caching::ConfigMethods, ActionController::Caching::Pages, ActionController::Caching::Actions, ActionController::ConditionalGet, ActionController::Head, ActionController::Renderers::All, ActionController::Renderers, ActionController::Rendering, ActionController::Redirecting, ActionController::RackDelegation, ActiveSupport::Benchmarkable, AbstractController::Logger, ActionController::UrlFor, AbstractController::UrlFor, ActionDispatch::Routing::UrlFor, ActionDispatch::Routing::PolymorphicRoutes, ActionController::HideActions, ActionController::Helpers, AbstractController::Helpers, AbstractController::AssetPaths, AbstractController::Translation, AbstractController::Layouts, AbstractController::Rendering, AbstractController::ViewPaths, ActionController::Metal, AbstractController::Base, ActiveSupport::Configurable, Object, ActiveSupport::Dependencies::Loadable, Mongoid::Extensions::Object::Yoda, Mongoid::Extensions::Object::Substitutable, Mongoid::Extensions::Object::Reflections, Mongoid::Extensions::Object::DeepCopy, Mongoid::Extensions::Object::Checks, JSON::Ext::Generator::GeneratorMethods::Object, PP::ObjectMixin, Kernel, BasicObject

Friday, June 15, 2012

Page 83: Diseño de APIs con Ruby

<Module:0x007ff271221e40>, ActionDispatch::Routing::Helpers, #<Module:0x007ff2714ad268>, ActionController::Base, ActionDispatch::Routing::RouteSet::MountedHelpers, HasScope, ActionController::Compatibility, ActionController::ParamsWrapper, ActionController::Instrumentation, ActionController::Rescue, ActiveSupport::Rescuable, ActionController::HttpAuthentication::Token::ControllerMethods, ActionController::HttpAuthentication::Digest::ControllerMethods, ActionController::HttpAuthentication::Basic::ControllerMethods, ActionController::RecordIdentifier, ActionController::DataStreaming, ActionController::Streaming, ActionController::ForceSSL, ActionController::RequestForgeryProtection, AbstractController::Callbacks, ActiveSupport::Callbacks, ActionController::Flash, ActionController::Cookies, ActionController::MimeResponds, ActionController::ImplicitRender, ActionController::Caching, ActionController::Caching::Fragments, ActionController::Caching::ConfigMethods, ActionController::Caching::Pages, ActionController::Caching::Actions, ActionController::ConditionalGet, ActionController::Head, ActionController::Renderers::All, ActionController::Renderers, ActionController::Rendering, ActionController::Redirecting, ActionController::RackDelegation, ActiveSupport::Benchmarkable, AbstractController::Logger, ActionController::UrlFor, AbstractController::UrlFor, ActionDispatch::Routing::UrlFor, ActionDispatch::Routing::PolymorphicRoutes, ActionController::HideActions, ActionController::Helpers, AbstractController::Helpers, AbstractController::AssetPaths, AbstractController::Translation, AbstractController::Layouts, AbstractController::Rendering, AbstractController::ViewPaths, ActionController::Metal, AbstractController::Base, ActiveSupport::Configurable, Object, ActiveSupport::Dependencies::Loadable, Mongoid::Extensions::Object::Yoda, Mongoid::Extensions::Object::Substitutable, Mongoid::Extensions::Object::Reflections, Mongoid::Extensions::Object::DeepCopy, Mongoid::Extensions::Object::Checks, JSON::Ext::Generator::GeneratorMethods::Object, PP::ObjectMixin, Kernel, BasicObject

#<Module:0x007f9211d5cd70>, ActionDispatch::Routing::Helpers, #<Module:0x007f9211f7b5e8>, ActionController::API, ActiveRecord::Railties::ControllerRuntime, ActionDispatch::Routing::RouteSet::MountedHelpers, ActionController::Instrumentation, ActionController::Rescue, ActiveSupport::Rescuable, ActionController::DataStreaming, ActionController::ForceSSL, AbstractController::Callbacks, ActiveSupport::Callbacks, ActionController::ConditionalGet, ActionController::Head, ActionController::Renderers::All, ActionController::Renderers, ActionController::Rendering, AbstractController::Rendering, AbstractController::ViewPaths, ActionController::Redirecting, ActionController::RackDelegation, ActiveSupport::Benchmarkable, AbstractController::Logger, ActionController::UrlFor, AbstractController::UrlFor, ActionDispatch::Routing::UrlFor, ActionDispatch::Routing::PolymorphicRoutes, ActionController::HideActions, ActionController::Metal, AbstractController::Base, ActiveSupport::Configurable, Object, JSON::Ext::Generator::GeneratorMethods::Object, ActiveSupport::Dependencies::Loadable, PP::ObjectMixin, Kernel, BasicObject

Friday, June 15, 2012

Page 84: Diseño de APIs con Ruby

use ActionDispatch::Staticuse Rack::Lockuse #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x007fd3b32928c0>use Rack::Runtimeuse Rack::MethodOverrideuse ActionDispatch::RequestIduse Rails::Rack::Loggeruse ActionDispatch::ShowExceptionsuse ActionDispatch::DebugExceptionsuse ActionDispatch::RemoteIpuse ActionDispatch::Reloaderuse ActionDispatch::Callbacksuse ActionDispatch::Cookiesuse ActionDispatch::Session::CookieStoreuse ActionDispatch::Flashuse ActionDispatch::ParamsParseruse ActionDispatch::Headuse Rack::ConditionalGetuse Rack::ETaguse ActionDispatch::BestStandardsSupportuse Rack::Mongoid::Middleware::IdentityMap

Friday, June 15, 2012

Page 85: Diseño de APIs con Ruby

use ActionDispatch::Staticuse Rack::Lockuse #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x007fd3b32928c0>use Rack::Runtimeuse Rack::MethodOverrideuse ActionDispatch::RequestIduse Rails::Rack::Loggeruse ActionDispatch::ShowExceptionsuse ActionDispatch::DebugExceptionsuse ActionDispatch::RemoteIpuse ActionDispatch::Reloaderuse ActionDispatch::Callbacksuse ActionDispatch::Cookiesuse ActionDispatch::Session::CookieStoreuse ActionDispatch::Flashuse ActionDispatch::ParamsParseruse ActionDispatch::Headuse Rack::ConditionalGetuse Rack::ETaguse ActionDispatch::BestStandardsSupportuse Rack::Mongoid::Middleware::IdentityMap

use ActionDispatch::Staticuse Rack::Lockuse #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x007fe74448cf50>use Rack::Runtimeuse ActionDispatch::RequestIduse Rails::Rack::Loggeruse ActionDispatch::ShowExceptionsuse ActionDispatch::DebugExceptionsuse ActionDispatch::RemoteIpuse ActionDispatch::Reloaderuse ActionDispatch::Callbacksuse ActiveRecord::ConnectionAdapters::ConnectionManagementuse ActiveRecord::QueryCacheuse ActionDispatch::ParamsParseruse ActionDispatch::Headuse Rack::ConditionalGetuse Rack::ETag

Friday, June 15, 2012

Page 86: Diseño de APIs con Ruby

Gracias!

Preguntas?

Edwin [email protected]

@softr8

Friday, June 15, 2012