SlideShare a Scribd company logo
Diseño de APIs con Ruby
   Edwin Cruz @softr8
PLAN
• Que   es una API

• Como   implementar una buena API

• Usando   Ruby on Rails para implementar una
 API

• Patrones   de diseño
“   Application
    Programming
    Interface


                  “
API

  Es una manera para
     comunicar dos
aplicaciones entre ellas.
TIPOS DE API


• Library

• SDK

• Web   services
PRIMERAS API - SOAP

       Simple
       Object
       Access
       Protocol
REST

REpresentation
State
Transfer
REQUISITOS REST
REQUISITOS REST

Separación de responsabilidades
REQUISITOS REST

Separación de responsabilidades
Cliente/Servidor
REQUISITOS REST

Separación de responsabilidades
Cliente/Servidor
Sin estado
REQUISITOS REST

Separación de responsabilidades
Cliente/Servidor
Sin estado
Puede ser “Cacheable”
REQUISITOS REST

Separación de responsabilidades
Cliente/Servidor
Sin estado
Puede ser “Cacheable”
Sistema a capas
REQUISITOS REST

Separación de responsabilidades
Cliente/Servidor
Sin estado
Puede ser “Cacheable”
Sistema a capas
Interface uniforme
CRUD

Create   Altas
Read     Bajas
Update   Cambios
Delete   Consultas
REST + CRUD
REST + CRUD


   Recursos a través de URLs únicas
Usando correctamente los verbos HTTP
RECURSO
RECURSO

Cualquier accion expuesta a travez de un servidor
web
RECURSO

Cualquier accion expuesta a travez de un servidor
web
Tienen una representación en datos
RECURSO

Cualquier accion expuesta a travez de un servidor
web
Tienen una representación en datos
Con un servicio web intercambiamos
representaciones de recursos
REST-ISH + JSON
REST-ISH + JSON

       =
REST-ISH + JSON

         =
  Cosas Increibles
¿PORQUÉ UN API?
¿PORQUÉ UN API?

Aumenta la flexibilidad y utilidad de tus
              aplicaciones
¿PORQUÉ UN API?

Aumenta la flexibilidad y utilidad de tus
              aplicaciones
     Proporciona valor de negocio
¿PORQUÉ UN API?

Aumenta la flexibilidad y utilidad de tus
              aplicaciones
     Proporciona valor de negocio
 Ayuda a comunicar aplicaciones entre ellas
¿QUÉ
CARACTERÍSTICAS?
¿QUÉ
CARACTERÍSTICAS?

 Fácil de implementar y mantener
¿QUÉ
CARACTERÍSTICAS?

 Fácil de implementar y mantener
 Buen rendimiento
¿QUÉ
CARACTERÍSTICAS?

 Fácil de implementar y mantener
 Buen rendimiento
 Escalable
¿CUÁLES SON LOS
    RETOS?
¿CUÁLES SON LOS
           RETOS?
La red es un eslabón débil, GEO localizacion de los
clientes
¿CUÁLES SON LOS
           RETOS?
La red es un eslabón débil, GEO localizacion de los
clientes
Administrar Cambios
¿CUÁLES SON LOS
           RETOS?
La red es un eslabón débil, GEO localizacion de los
clientes
Administrar Cambios
Uso indebido
¿CUÁLES SON LOS
           RETOS?
La red es un eslabón débil, GEO localizacion de los
clientes
Administrar Cambios
Uso indebido
Balanceo de trafico
¿CUÁLES SON LOS
           RETOS?
La red es un eslabón débil, GEO localizacion de los
clientes
Administrar Cambios
Uso indebido
Balanceo de trafico
Picos de uso
¿CUÁLES SON LOS
           RETOS?
La red es un eslabón débil, GEO localizacion de los
clientes
Administrar Cambios
Uso indebido
Balanceo de trafico
Picos de uso
Errores
DISEÑAR UNA BUENA
        API
CONVENCIONES REST
USAR CORRECTAMENTE
    VERBOS HTTP
REST + CRUD

                       GET /api/products #Listado
{"products" :
  [
    {"product" : { "id" : 1, "name" : "Producto 1", "status" : "archived"} },
    {"product" : { "id" : 2, "name" : "Producto 2", "status" : "active" } }
  ]
}
REST + CRUD

                         GET /api/products/2 #Ver


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

                       POST /api/products #Crear

{
    "name" : "Producto 2"
}
REST + CRUD
                  PUT /api/products/2 #Actualizar


{
    "name" : "Producto dos"
}
REST + CRUD
DELETE /api/products/2 #Eliminar
VERSIONES DE LA API

• API   Interna (entre aplicaciones)

• API   Externa (aplicacion movil ? )

• API   Usuarios (publico en general)
VERSIONANDO TU API

    /int/api/products
    /ext/api/products
    /pub/api/products
VERSIONANDO TU API

 /int/api/products?version=2
 /ext/api/products?version=2
 /pub/api/products?version=2
VERSIONANDO TU API

   /v2/int/api/products
   /v2/ext/api/products
   /v2/pub/api/products
VERSIONANDO TU API


http://int.myapp.com/products
http://api.myapp.com/products
MUNDO IDEAL
MUNDO IDEAL

Uso de: Accept Header
MUNDO IDEAL

Uso de: Accept Header


Accept: application/vnd.mycompany.com;version=2,application/json
CODIGOS HTTP
200 OK
201 Created
202 Accepted

400   Bad Request
401   Unauthorized
402   Payment Required
404   Not Found
409   Conflict
422   Unprocessable Entity

500 Internal Server Error
503 Service Unavailable
CODIGOS HTTP

HTTP/1.1 200 ok
GET /v1/products
{"products" :
  [
    {"product" : { "id" : 1, "name" : "Producto 1", "status" : "archived"} },
    {"product" : { "id" : 2, "name" : "Producto 2", "status" : "active" } }
  ]
}
CODIGOS HTTP
 HTTP/1.1 201 Created
 POST /v1/products
 {
   “product”: [
     “name” : “name”
   ]
 }
CODIGOS HTTP
HTTP/1.1 400 Bad Request

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

HTTP/1.1 401 Unauthorized

{
    “errors”: [
      “api_key not found”
    ]
}
CODIGOS HTTP
HTTP/1.1 401 Unauthorized

{
  “errors”: [
    “api_key no valida”,
    “api_key no puede contener
espacios”
  ]
}
CODIGOS HTTP
HTTP/1.1 401 Unauthorized

{
  “errors”: [
    “api_key no encontrada, por favor
visita http://account.myapp.com/api para
obtenerla”
  ]
}
CODIGOS HTTP
HTTP/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”
      ]
  ]
}
CODIGOS HTTP
HTTP/1.1 500 Internal Server Error

{
    “exception”: [
      “Base de datos no disponible”
    ]
}
CODIGOS HTTP

HTTP/1.1 503 Service Unavailable

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

• Simuladores

• Autenticación

• Validadores

• Limite   de uso

• Rapidez

• Balanceo
USANDO RUBY ON
     RAILS PARA
IMLEMENTAR UNA API
APIS ON RAILS - REST
#config/routes.rb
MyApp::Application.routes.draw do
  resources :products
end




$ rake routes
    products GET       /products(.:format)            products#index
              POST     /products(.:format)            products#create
 new_product GET       /products/new(.:format)        products#new
edit_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
APIS ON RAILS - REST
#config/routes.rb
MyApp::Application.routes.draw do
  scope ‘/api’ do
    resources :products
  end
end



    products GET      /api/products(.:format)            products#index
             POST     /api/products(.:format)            products#create
 new_product GET      /api/products/new(.:format)        products#new
edit_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
APIS ON RAILS -
                VERSIONES
gem 'versionist'
#config/routes.rb
MyApp::Application.routes.draw do
  api_version(:module => 'V1', :path => 'v2') do
    resources :products
  end
end



    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#new
edit_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
APIS ON RAILS,
             CONTROLADOR
class V1::ProductsController < ApplicationController
  def index
    products = Product.paginate(:page => (params[:page] || 1),
                                 :per_page => (params[:per_page] || 100)).all
    render :json => products.to_json
  end
  def show
    product = Product.find(params[:id])
    render :json => product.to_json
  end
  def update
    product = Product.find(params[:id])
    product.update_attributes(params[:product])
    render :json => product.to_json
  end
  def destroy
    product = Product.find(params[:id])
    head product.destroy ? :ok : :unprocessable_entity
  end
end
APIS ON RAILS,
                CONTROLADOR
class ApplicationController < ActionController::Base
  rescue_from ActiveRecord::UnknownAttributeError, ArgumentError do |exception|
    respond_with_error(exception, 400)
  end
  rescue_from ActiveRecord::RecordNotFound do |exception|
    respond_with_error(exception, 404)
  end
  rescue_from ActiveRecord::RecordInvalid do |exception|
    respond_with_error(exception, 422, errors: exception.record.errors.messages)
  end
  rescue_from RuntimeError do |exception|
    respond_with_error(exception, 500)
  end

  private
  def respond_with_error(exception, code, errors = {})
    render json: {error: exception.class.to_s,
                  message: exception.to_s,
                  errors: errors},
           status: code
  end
end
APIS ON RAILS,
              CONTROLADOR
class V2::ProductsController < ApplicationController
  respond_to [:json, :xml, :html]
  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
  end
end
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
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
  end
end
APIS ON RAILS
                           VISTAS
#app/views/api/v3/products/index.rabl

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




{"products" :
  [
    {"product" : { "id" : 1, "name" : "Producto 1", "status" : "archived", “current_stock” : 10,
      “variants” : [ {“upc” : “ASDFS”, “color” : “negro”, “size” : “M”, “on_hand” : 10} ]
      }
    }
  ]
}
APIS ON RAILS
                 VISTAS
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
APIS ON RAILS
                 VISTAS

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

  has_many :comments

  def tags
    tags.order :name
  end
end
APIS ON RAILS
           SEGURIDAD
Devise
Autenticacion Flexible para aplicaciones Rails
Compuesta de 12 modulos: database authenticable,
token authenticable, omniauthable, confirmable,
recoverable, registerable, trackable, timeoutable,
validatable, lockable
APIS ON RAILS
           SEGURIDAD
Devise
Autenticacion Flexible para aplicaciones Rails
Compuesta de 12 modulos: database authenticable,
token authenticable, omniauthable, confirmable,
recoverable, registerable, trackable, timeoutable,
validatable, lockable
APIS ON RAILS
                 SEGURIDAD
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
  end
end
ESCRIBIENDO PRUEBAS
APIS ON RAILS
                  PRUEBAS
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
  end
end
APIS ON RAILS
                   PRUEBAS
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_response = JSON.parse(response.body)
        json_response['error'].should == "ActiveRecord::RecordNotFound"
        json_response['message'].should == "Couldn't find Product with id=-1"
      end
    end
  end
end
APIS ON RAILS
                   PRUEBAS
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
  end
end
APIS ON RAILS
                   PRUEBAS
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
  end
end
ROR, DEMACIADO PARA
       LAS API?

• Helpers

• Vistas

• Administracion   de assets

• Generadores   de html

• Template   engines
<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,
 JSON::Ext::Generator::GeneratorMethods::Object,
 PP::ObjectMixin,
 Kernel,
 BasicObject
<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,   #<Module:0x007f9211d5cd70>,
 ActionController::HttpAuthentication::Basic::ControllerMethods,     ActionDispatch::Routing::Helpers,
 ActionController::RecordIdentifier,                                 #<Module:0x007f9211f7b5e8>,
 ActionController::DataStreaming,                                    ActionController::API,
 ActionController::Streaming,                                        ActiveRecord::Railties::ControllerRuntime,
 ActionController::ForceSSL,                                         ActionDispatch::Routing::RouteSet::MountedHelpers,
 ActionController::RequestForgeryProtection,                         ActionController::Instrumentation,
 AbstractController::Callbacks,                                      ActionController::Rescue,
 ActiveSupport::Callbacks,                                           ActiveSupport::Rescuable,
 ActionController::Flash,                                            ActionController::DataStreaming,
 ActionController::Cookies,                                          ActionController::ForceSSL,
 ActionController::MimeResponds,                                     AbstractController::Callbacks,
 ActionController::ImplicitRender,                                   ActiveSupport::Callbacks,
 ActionController::Caching,                                          ActionController::ConditionalGet,
 ActionController::Caching::Fragments,                               ActionController::Head,
 ActionController::Caching::ConfigMethods,                           ActionController::Renderers::All,
 ActionController::Caching::Pages,                                   ActionController::Renderers,
 ActionController::Caching::Actions,                                 ActionController::Rendering,
 ActionController::ConditionalGet,                                   AbstractController::Rendering,
 ActionController::Head,                                             AbstractController::ViewPaths,
 ActionController::Renderers::All,                                   ActionController::Redirecting,
 ActionController::Renderers,                                        ActionController::RackDelegation,
 ActionController::Rendering,                                        ActiveSupport::Benchmarkable,
 ActionController::Redirecting,                                      AbstractController::Logger,
 ActionController::RackDelegation,                                   ActionController::UrlFor,
 ActiveSupport::Benchmarkable,                                       AbstractController::UrlFor,
 AbstractController::Logger,                                         ActionDispatch::Routing::UrlFor,
 ActionController::UrlFor,                                           ActionDispatch::Routing::PolymorphicRoutes,
 AbstractController::UrlFor,                                         ActionController::HideActions,
 ActionDispatch::Routing::UrlFor,                                    ActionController::Metal,
 ActionDispatch::Routing::PolymorphicRoutes,                         AbstractController::Base,
 ActionController::HideActions,                                      ActiveSupport::Configurable,
 ActionController::Helpers,                                          Object,
 AbstractController::Helpers,                                        JSON::Ext::Generator::GeneratorMethods::Object,
 AbstractController::AssetPaths,                                     ActiveSupport::Dependencies::Loadable,
 AbstractController::Translation,                                    PP::ObjectMixin,
 AbstractController::Layouts,                                        Kernel,
 AbstractController::Rendering,                                      BasicObject
 AbstractController::ViewPaths,
 ActionController::Metal,
 AbstractController::Base,
 ActiveSupport::Configurable,
 Object,
 ActiveSupport::Dependencies::Loadable,
 JSON::Ext::Generator::GeneratorMethods::Object,
 PP::ObjectMixin,
 Kernel,
 BasicObject
RAILS A DIETA
RAILS A DIETA
  Rails es modular
RAILS A DIETA
              Rails es modular
Para crear APIs, algunos Middlewares no son
                    necesarios
RAILS A DIETA
              Rails es modular
Para crear APIs, algunos Middlewares no son
                    necesarios

                rails-api
use ActionDispatch::Static
use Rack::Lock
use
#<ActiveSupport::Cache::Strategy::Loc
alCache::Middleware:0x007fd3b32928c0>
use Rack::Runtime
use Rack::MethodOverride
use ActionDispatch::RequestId
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use ActionDispatch::DebugExceptions
use ActionDispatch::RemoteIp
use ActionDispatch::Reloader
use ActionDispatch::Callbacks
use ActionDispatch::Cookies
use
ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use ActionDispatch::ParamsParser
use ActionDispatch::Head
use Rack::ConditionalGet
use Rack::ETag
use
ActionDispatch::BestStandardsSupport
use
use ActionDispatch::Static
use Rack::Lock
use                                     use ActionDispatch::Static
#<ActiveSupport::Cache::Strategy::Loc   use Rack::Lock
alCache::Middleware:0x007fd3b32928c0>   use
use Rack::Runtime                       #<ActiveSupport::Cache::Strategy::LocalCac
use Rack::MethodOverride                he::Middleware:0x007fe74448cf50>
use ActionDispatch::RequestId           use Rack::Runtime
use Rails::Rack::Logger                 use ActionDispatch::RequestId
use ActionDispatch::ShowExceptions      use Rails::Rack::Logger
use ActionDispatch::DebugExceptions     use ActionDispatch::ShowExceptions
use ActionDispatch::RemoteIp            use ActionDispatch::DebugExceptions
use ActionDispatch::Reloader            use ActionDispatch::RemoteIp
use ActionDispatch::Callbacks           use ActionDispatch::Reloader
use ActionDispatch::Cookies             use ActionDispatch::Callbacks
use                                     use
ActionDispatch::Session::CookieStore    ActiveRecord::ConnectionAdapters::Connecti
use ActionDispatch::Flash               onManagement
use ActionDispatch::ParamsParser        use ActiveRecord::QueryCache
use ActionDispatch::Head                use ActionDispatch::ParamsParser
use Rack::ConditionalGet                use ActionDispatch::Head
use Rack::ETag                          use Rack::ConditionalGet
use                                     use Rack::ETag
ActionDispatch::BestStandardsSupport
use
RAILS-API?

• ActiveRecord    (manejo de errores)

• Validaciones   (responder a varios formatos)

• Controladores, sistema   de rutas (versionamiento)

• Muchas   librerias(Gems)

• Autenticación   (oauth, token, basic auth)

• Mismos   web servers confiables (mismo hosting)
RAILS-API?


• REST

• CRUD
CONCLUSION
CONCLUSION


Rails es perfecto para API’s!
Gracias!

Preguntas?
              Edwin Cruz
      edwin@crowdint.com
                 @softr8
Ad

Recommended

PDF
Diseño de APIs con Ruby
Software Guru
 
PDF
Refactoring JavaScript Applications
Jovan Vidić
 
PPTX
AHOY FB Hack Day 2017
Ian Yu-Hsun Lin
 
PDF
Ionic - Revolutionizing Hybrid Mobile Application Development
Justin James
 
PPTX
Rapid mobile development with Ionic framework - Voxxdays Ticino 2015
Alessio Delmonti
 
KEY
Agile toolkit present 2012
Romans Malinovskis
 
PDF
ParisJS #10 : RequireJS
Julien Cabanès
 
PDF
Building Better Web APIs with Rails
All Things Open
 
PDF
Continuous Integration and Deployment Best Practices on AWS
Danilo Poccia
 
PDF
Building Mobile Friendly APIs in Rails
Jim Jeffers
 
PPTX
REST API Best Practices & Implementing in Codeigniter
Sachin G Kulkarni
 
PPTX
API Workshop: Deep dive into REST APIs
Tom Johnson
 
PDF
Building Awesome APIs in Grails
clatimer
 
PDF
Google Cloud Endpointsによる API構築
Keiji Ariyama
 
PPTX
Developing Apps with Azure AD
SharePointRadi
 
PDF
Creating Rich Server API’s for your Mobile Apps - Best Practices and Guidelines
Jonathan Guthrie
 
PDF
Don't screw it up! How to build durable API
Alessandro Cinelli (cirpo)
 
PDF
APIs REST Usables con Hypermedia por Javier Ramirez, para codemotion
javier ramirez
 
PPT
Creating a World-Class RESTful Web Services API
David Keener
 
PPTX
All Things API Presentation - Gordon Weakleim [HomeAway]
Cloud Elements
 
PPTX
Araport Workshop Tutorial 2: Authentication and the Agave Profiles Service
stevemock
 
PDF
Api's and ember js
Edwin Cruz
 
PPTX
Web API with ASP.NET MVC by Software development company in india
iFour Institute - Sustainable Learning
 
PPTX
Azure API Management - why should I care?
Jouni Heikniemi
 
ODP
Creating REST Applications with the Slim Micro-Framework by Vikram Vaswani
vvaswani
 
PDF
Serverless Framework Workshop - Tyler Hendrickson, Chicago/burbs
AWS Chicago
 
PDF
From Backbone to Ember and Back(bone) Again
jonknapp
 
PPTX
2013 02-apache conna-api-manager-asanka
WSO2
 
PDF
Codigo Escalable WDT
Edwin Cruz
 
PDF
SGCE 2015 - eCommerce platforms
Edwin Cruz
 

More Related Content

Similar to Api development with rails (20)

PDF
Continuous Integration and Deployment Best Practices on AWS
Danilo Poccia
 
PDF
Building Mobile Friendly APIs in Rails
Jim Jeffers
 
PPTX
REST API Best Practices & Implementing in Codeigniter
Sachin G Kulkarni
 
PPTX
API Workshop: Deep dive into REST APIs
Tom Johnson
 
PDF
Building Awesome APIs in Grails
clatimer
 
PDF
Google Cloud Endpointsによる API構築
Keiji Ariyama
 
PPTX
Developing Apps with Azure AD
SharePointRadi
 
PDF
Creating Rich Server API’s for your Mobile Apps - Best Practices and Guidelines
Jonathan Guthrie
 
PDF
Don't screw it up! How to build durable API
Alessandro Cinelli (cirpo)
 
PDF
APIs REST Usables con Hypermedia por Javier Ramirez, para codemotion
javier ramirez
 
PPT
Creating a World-Class RESTful Web Services API
David Keener
 
PPTX
All Things API Presentation - Gordon Weakleim [HomeAway]
Cloud Elements
 
PPTX
Araport Workshop Tutorial 2: Authentication and the Agave Profiles Service
stevemock
 
PDF
Api's and ember js
Edwin Cruz
 
PPTX
Web API with ASP.NET MVC by Software development company in india
iFour Institute - Sustainable Learning
 
PPTX
Azure API Management - why should I care?
Jouni Heikniemi
 
ODP
Creating REST Applications with the Slim Micro-Framework by Vikram Vaswani
vvaswani
 
PDF
Serverless Framework Workshop - Tyler Hendrickson, Chicago/burbs
AWS Chicago
 
PDF
From Backbone to Ember and Back(bone) Again
jonknapp
 
PPTX
2013 02-apache conna-api-manager-asanka
WSO2
 
Continuous Integration and Deployment Best Practices on AWS
Danilo Poccia
 
Building Mobile Friendly APIs in Rails
Jim Jeffers
 
REST API Best Practices & Implementing in Codeigniter
Sachin G Kulkarni
 
API Workshop: Deep dive into REST APIs
Tom Johnson
 
Building Awesome APIs in Grails
clatimer
 
Google Cloud Endpointsによる API構築
Keiji Ariyama
 
Developing Apps with Azure AD
SharePointRadi
 
Creating Rich Server API’s for your Mobile Apps - Best Practices and Guidelines
Jonathan Guthrie
 
Don't screw it up! How to build durable API
Alessandro Cinelli (cirpo)
 
APIs REST Usables con Hypermedia por Javier Ramirez, para codemotion
javier ramirez
 
Creating a World-Class RESTful Web Services API
David Keener
 
All Things API Presentation - Gordon Weakleim [HomeAway]
Cloud Elements
 
Araport Workshop Tutorial 2: Authentication and the Agave Profiles Service
stevemock
 
Api's and ember js
Edwin Cruz
 
Web API with ASP.NET MVC by Software development company in india
iFour Institute - Sustainable Learning
 
Azure API Management - why should I care?
Jouni Heikniemi
 
Creating REST Applications with the Slim Micro-Framework by Vikram Vaswani
vvaswani
 
Serverless Framework Workshop - Tyler Hendrickson, Chicago/burbs
AWS Chicago
 
From Backbone to Ember and Back(bone) Again
jonknapp
 
2013 02-apache conna-api-manager-asanka
WSO2
 

More from Edwin Cruz (11)

PDF
Codigo Escalable WDT
Edwin Cruz
 
PDF
SGCE 2015 - eCommerce platforms
Edwin Cruz
 
PDF
Devops with ansible
Edwin Cruz
 
PDF
Containers in 5... 9 minutes
Edwin Cruz
 
PDF
Chilango Rails Ecommerce Lightning talk
Edwin Cruz
 
PDF
Home made ceviche
Edwin Cruz
 
PDF
FSL Vallarta, mejorando el rendimiento de las aplicaciones web
Edwin Cruz
 
PPTX
Presentacion Programador Apasionado
Edwin Cruz
 
PPTX
MagmaRails - Passionate Programmer
Edwin Cruz
 
PPTX
Presentacion programador apasionado
Edwin Cruz
 
PPTX
Migrando Rails Apps entre Cloud y Bare Metal Servers
Edwin Cruz
 
Codigo Escalable WDT
Edwin Cruz
 
SGCE 2015 - eCommerce platforms
Edwin Cruz
 
Devops with ansible
Edwin Cruz
 
Containers in 5... 9 minutes
Edwin Cruz
 
Chilango Rails Ecommerce Lightning talk
Edwin Cruz
 
Home made ceviche
Edwin Cruz
 
FSL Vallarta, mejorando el rendimiento de las aplicaciones web
Edwin Cruz
 
Presentacion Programador Apasionado
Edwin Cruz
 
MagmaRails - Passionate Programmer
Edwin Cruz
 
Presentacion programador apasionado
Edwin Cruz
 
Migrando Rails Apps entre Cloud y Bare Metal Servers
Edwin Cruz
 
Ad

Recently uploaded (20)

PDF
EIS-Webinar-Engineering-Retail-Infrastructure-06-16-2025.pdf
Earley Information Science
 
PPTX
Security Tips for Enterprise Azure Solutions
Michele Leroux Bustamante
 
PDF
Coordinated Disclosure for ML - What's Different and What's the Same.pdf
Priyanka Aash
 
PDF
PyCon SG 25 - Firecracker Made Easy with Python.pdf
Muhammad Yuga Nugraha
 
PPTX
UserCon Belgium: Honey, VMware increased my bill
stijn40
 
PDF
Raman Bhaumik - Passionate Tech Enthusiast
Raman Bhaumik
 
PDF
Hyderabad MuleSoft In-Person Meetup (June 21, 2025) Slides
Ravi Tamada
 
PPTX
Securing Account Lifecycles in the Age of Deepfakes.pptx
FIDO Alliance
 
PDF
Cracking the Code - Unveiling Synergies Between Open Source Security and AI.pdf
Priyanka Aash
 
PDF
Python Conference Singapore - 19 Jun 2025
ninefyi
 
PDF
Connecting Data and Intelligence: The Role of FME in Machine Learning
Safe Software
 
PDF
AI Agents and FME: A How-to Guide on Generating Synthetic Metadata
Safe Software
 
PPTX
" How to survive with 1 billion vectors and not sell a kidney: our low-cost c...
Fwdays
 
PDF
Enhance GitHub Copilot using MCP - Enterprise version.pdf
Nilesh Gule
 
PDF
Quantum AI Discoveries: Fractal Patterns Consciousness and Cyclical Universes
Saikat Basu
 
PDF
Using the SQLExecutor for Data Quality Management: aka One man's love for the...
Safe Software
 
PDF
From Manual to Auto Searching- FME in the Driver's Seat
Safe Software
 
PPTX
OpenACC and Open Hackathons Monthly Highlights June 2025
OpenACC
 
PDF
Mastering AI Workflows with FME by Mark Döring
Safe Software
 
PPTX
Curietech AI in action - Accelerate MuleSoft development
shyamraj55
 
EIS-Webinar-Engineering-Retail-Infrastructure-06-16-2025.pdf
Earley Information Science
 
Security Tips for Enterprise Azure Solutions
Michele Leroux Bustamante
 
Coordinated Disclosure for ML - What's Different and What's the Same.pdf
Priyanka Aash
 
PyCon SG 25 - Firecracker Made Easy with Python.pdf
Muhammad Yuga Nugraha
 
UserCon Belgium: Honey, VMware increased my bill
stijn40
 
Raman Bhaumik - Passionate Tech Enthusiast
Raman Bhaumik
 
Hyderabad MuleSoft In-Person Meetup (June 21, 2025) Slides
Ravi Tamada
 
Securing Account Lifecycles in the Age of Deepfakes.pptx
FIDO Alliance
 
Cracking the Code - Unveiling Synergies Between Open Source Security and AI.pdf
Priyanka Aash
 
Python Conference Singapore - 19 Jun 2025
ninefyi
 
Connecting Data and Intelligence: The Role of FME in Machine Learning
Safe Software
 
AI Agents and FME: A How-to Guide on Generating Synthetic Metadata
Safe Software
 
" How to survive with 1 billion vectors and not sell a kidney: our low-cost c...
Fwdays
 
Enhance GitHub Copilot using MCP - Enterprise version.pdf
Nilesh Gule
 
Quantum AI Discoveries: Fractal Patterns Consciousness and Cyclical Universes
Saikat Basu
 
Using the SQLExecutor for Data Quality Management: aka One man's love for the...
Safe Software
 
From Manual to Auto Searching- FME in the Driver's Seat
Safe Software
 
OpenACC and Open Hackathons Monthly Highlights June 2025
OpenACC
 
Mastering AI Workflows with FME by Mark Döring
Safe Software
 
Curietech AI in action - Accelerate MuleSoft development
shyamraj55
 
Ad

Api development with rails

  • 1. Diseño de APIs con Ruby Edwin Cruz @softr8
  • 2. PLAN • Que es una API • Como implementar una buena API • Usando Ruby on Rails para implementar una API • Patrones de diseño
  • 3. Application Programming Interface “
  • 4. API Es una manera para comunicar dos aplicaciones entre ellas.
  • 5. TIPOS DE API • Library • SDK • Web services
  • 6. PRIMERAS API - SOAP Simple Object Access Protocol
  • 9. REQUISITOS REST Separación de responsabilidades
  • 10. REQUISITOS REST Separación de responsabilidades Cliente/Servidor
  • 11. REQUISITOS REST Separación de responsabilidades Cliente/Servidor Sin estado
  • 12. REQUISITOS REST Separación de responsabilidades Cliente/Servidor Sin estado Puede ser “Cacheable”
  • 13. REQUISITOS REST Separación de responsabilidades Cliente/Servidor Sin estado Puede ser “Cacheable” Sistema a capas
  • 14. REQUISITOS REST Separación de responsabilidades Cliente/Servidor Sin estado Puede ser “Cacheable” Sistema a capas Interface uniforme
  • 15. CRUD Create Altas Read Bajas Update Cambios Delete Consultas
  • 17. REST + CRUD Recursos a través de URLs únicas Usando correctamente los verbos HTTP
  • 19. RECURSO Cualquier accion expuesta a travez de un servidor web
  • 20. RECURSO Cualquier accion expuesta a travez de un servidor web Tienen una representación en datos
  • 21. RECURSO Cualquier accion expuesta a travez de un servidor web Tienen una representación en datos Con un servicio web intercambiamos representaciones de recursos
  • 24. REST-ISH + JSON = Cosas Increibles
  • 26. ¿PORQUÉ UN API? Aumenta la flexibilidad y utilidad de tus aplicaciones
  • 27. ¿PORQUÉ UN API? Aumenta la flexibilidad y utilidad de tus aplicaciones Proporciona valor de negocio
  • 28. ¿PORQUÉ UN API? Aumenta la flexibilidad y utilidad de tus aplicaciones Proporciona valor de negocio Ayuda a comunicar aplicaciones entre ellas
  • 30. ¿QUÉ CARACTERÍSTICAS? Fácil de implementar y mantener
  • 31. ¿QUÉ CARACTERÍSTICAS? Fácil de implementar y mantener Buen rendimiento
  • 32. ¿QUÉ CARACTERÍSTICAS? Fácil de implementar y mantener Buen rendimiento Escalable
  • 34. ¿CUÁLES SON LOS RETOS? La red es un eslabón débil, GEO localizacion de los clientes
  • 35. ¿CUÁLES SON LOS RETOS? La red es un eslabón débil, GEO localizacion de los clientes Administrar Cambios
  • 36. ¿CUÁLES SON LOS RETOS? La red es un eslabón débil, GEO localizacion de los clientes Administrar Cambios Uso indebido
  • 37. ¿CUÁLES SON LOS RETOS? La red es un eslabón débil, GEO localizacion de los clientes Administrar Cambios Uso indebido Balanceo de trafico
  • 38. ¿CUÁLES SON LOS RETOS? La red es un eslabón débil, GEO localizacion de los clientes Administrar Cambios Uso indebido Balanceo de trafico Picos de uso
  • 39. ¿CUÁLES SON LOS RETOS? La red es un eslabón débil, GEO localizacion de los clientes Administrar Cambios Uso indebido Balanceo de trafico Picos de uso Errores
  • 42. USAR CORRECTAMENTE VERBOS HTTP
  • 43. REST + CRUD GET /api/products #Listado {"products" : [ {"product" : { "id" : 1, "name" : "Producto 1", "status" : "archived"} }, {"product" : { "id" : 2, "name" : "Producto 2", "status" : "active" } } ] }
  • 44. REST + CRUD GET /api/products/2 #Ver {"product" : { "id" : 2, "name" : "Producto 2", "status" : "active" } }
  • 45. REST + CRUD POST /api/products #Crear { "name" : "Producto 2" }
  • 46. REST + CRUD PUT /api/products/2 #Actualizar { "name" : "Producto dos" }
  • 47. REST + CRUD DELETE /api/products/2 #Eliminar
  • 48. VERSIONES DE LA API • API Interna (entre aplicaciones) • API Externa (aplicacion movil ? ) • API Usuarios (publico en general)
  • 49. VERSIONANDO TU API /int/api/products /ext/api/products /pub/api/products
  • 50. VERSIONANDO TU API /int/api/products?version=2 /ext/api/products?version=2 /pub/api/products?version=2
  • 51. VERSIONANDO TU API /v2/int/api/products /v2/ext/api/products /v2/pub/api/products
  • 54. MUNDO IDEAL Uso de: Accept Header
  • 55. MUNDO IDEAL Uso de: Accept Header Accept: application/vnd.mycompany.com;version=2,application/json
  • 56. CODIGOS HTTP 200 OK 201 Created 202 Accepted 400 Bad Request 401 Unauthorized 402 Payment Required 404 Not Found 409 Conflict 422 Unprocessable Entity 500 Internal Server Error 503 Service Unavailable
  • 57. CODIGOS HTTP HTTP/1.1 200 ok GET /v1/products {"products" : [ {"product" : { "id" : 1, "name" : "Producto 1", "status" : "archived"} }, {"product" : { "id" : 2, "name" : "Producto 2", "status" : "active" } } ] }
  • 58. CODIGOS HTTP HTTP/1.1 201 Created POST /v1/products { “product”: [ “name” : “name” ] }
  • 59. CODIGOS HTTP HTTP/1.1 400 Bad Request { “errors”: [ “Estructura JSON no valida”, “unexpected TSTRING, expected ‘}’ at line 2” ] }
  • 60. CODIGOS HTTP HTTP/1.1 401 Unauthorized { “errors”: [ “api_key not found” ] }
  • 61. CODIGOS HTTP HTTP/1.1 401 Unauthorized { “errors”: [ “api_key no valida”, “api_key no puede contener espacios” ] }
  • 62. CODIGOS HTTP HTTP/1.1 401 Unauthorized { “errors”: [ “api_key no encontrada, por favor visita http://account.myapp.com/api para obtenerla” ] }
  • 63. CODIGOS HTTP HTTP/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” ] ] }
  • 64. CODIGOS HTTP HTTP/1.1 500 Internal Server Error { “exception”: [ “Base de datos no disponible” ] }
  • 65. CODIGOS HTTP HTTP/1.1 503 Service Unavailable { “messages”: [ “En mantenimiento” ] }
  • 66. OPCIONES AVANZADAS • Simuladores • Autenticación • Validadores • Limite de uso • Rapidez • Balanceo
  • 67. USANDO RUBY ON RAILS PARA IMLEMENTAR UNA API
  • 68. APIS ON RAILS - REST #config/routes.rb MyApp::Application.routes.draw do resources :products end $ rake routes products GET /products(.:format) products#index POST /products(.:format) products#create new_product GET /products/new(.:format) products#new edit_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
  • 69. APIS ON RAILS - REST #config/routes.rb MyApp::Application.routes.draw do scope ‘/api’ do resources :products end end products GET /api/products(.:format) products#index POST /api/products(.:format) products#create new_product GET /api/products/new(.:format) products#new edit_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
  • 70. APIS ON RAILS - VERSIONES gem 'versionist' #config/routes.rb MyApp::Application.routes.draw do api_version(:module => 'V1', :path => 'v2') do resources :products end end 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#new edit_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
  • 71. APIS ON RAILS, CONTROLADOR class V1::ProductsController < ApplicationController def index products = Product.paginate(:page => (params[:page] || 1), :per_page => (params[:per_page] || 100)).all render :json => products.to_json end def show product = Product.find(params[:id]) render :json => product.to_json end def update product = Product.find(params[:id]) product.update_attributes(params[:product]) render :json => product.to_json end def destroy product = Product.find(params[:id]) head product.destroy ? :ok : :unprocessable_entity end end
  • 72. APIS ON RAILS, CONTROLADOR class ApplicationController < ActionController::Base rescue_from ActiveRecord::UnknownAttributeError, ArgumentError do |exception| respond_with_error(exception, 400) end rescue_from ActiveRecord::RecordNotFound do |exception| respond_with_error(exception, 404) end rescue_from ActiveRecord::RecordInvalid do |exception| respond_with_error(exception, 422, errors: exception.record.errors.messages) end rescue_from RuntimeError do |exception| respond_with_error(exception, 500) end private def respond_with_error(exception, code, errors = {}) render json: {error: exception.class.to_s, message: exception.to_s, errors: errors}, status: code end end
  • 73. APIS ON RAILS, CONTROLADOR class V2::ProductsController < ApplicationController respond_to [:json, :xml, :html] 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 end end
  • 74. 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
  • 75. 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 end end
  • 76. APIS ON RAILS VISTAS #app/views/api/v3/products/index.rabl collection @products attributes :id, :name, :status node(:url) {|product| product_url(product) } node(:current_stock) {|product| product.variants.map(&:on_hand).sum } child :variants do attributes :upc, :color, :size, :on_hand end {"products" : [ {"product" : { "id" : 1, "name" : "Producto 1", "status" : "archived", “current_stock” : 10, “variants” : [ {“upc” : “ASDFS”, “color” : “negro”, “size” : “M”, “on_hand” : 10} ] } } ] }
  • 77. APIS ON RAILS VISTAS 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
  • 78. APIS ON RAILS VISTAS gem ‘active_model_serializer’ class PostSerializer < ActiveModel::Serializer attributes :id, :body attribute :title, :key => :name has_many :comments def tags tags.order :name end end
  • 79. APIS ON RAILS SEGURIDAD Devise Autenticacion Flexible para aplicaciones Rails Compuesta de 12 modulos: database authenticable, token authenticable, omniauthable, confirmable, recoverable, registerable, trackable, timeoutable, validatable, lockable
  • 80. APIS ON RAILS SEGURIDAD Devise Autenticacion Flexible para aplicaciones Rails Compuesta de 12 modulos: database authenticable, token authenticable, omniauthable, confirmable, recoverable, registerable, trackable, timeoutable, validatable, lockable
  • 81. APIS ON RAILS SEGURIDAD 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 end end
  • 83. APIS ON RAILS PRUEBAS 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 end end
  • 84. APIS ON RAILS PRUEBAS 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_response = JSON.parse(response.body) json_response['error'].should == "ActiveRecord::RecordNotFound" json_response['message'].should == "Couldn't find Product with id=-1" end end end end
  • 85. APIS ON RAILS PRUEBAS 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 end end
  • 86. APIS ON RAILS PRUEBAS 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 end end
  • 87. ROR, DEMACIADO PARA LAS API? • Helpers • Vistas • Administracion de assets • Generadores de html • Template engines
  • 88. <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, JSON::Ext::Generator::GeneratorMethods::Object, PP::ObjectMixin, Kernel, BasicObject
  • 89. <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, #<Module:0x007f9211d5cd70>, ActionController::HttpAuthentication::Basic::ControllerMethods, ActionDispatch::Routing::Helpers, ActionController::RecordIdentifier, #<Module:0x007f9211f7b5e8>, ActionController::DataStreaming, ActionController::API, ActionController::Streaming, ActiveRecord::Railties::ControllerRuntime, ActionController::ForceSSL, ActionDispatch::Routing::RouteSet::MountedHelpers, ActionController::RequestForgeryProtection, ActionController::Instrumentation, AbstractController::Callbacks, ActionController::Rescue, ActiveSupport::Callbacks, ActiveSupport::Rescuable, ActionController::Flash, ActionController::DataStreaming, ActionController::Cookies, ActionController::ForceSSL, ActionController::MimeResponds, AbstractController::Callbacks, ActionController::ImplicitRender, ActiveSupport::Callbacks, ActionController::Caching, ActionController::ConditionalGet, ActionController::Caching::Fragments, ActionController::Head, ActionController::Caching::ConfigMethods, ActionController::Renderers::All, ActionController::Caching::Pages, ActionController::Renderers, ActionController::Caching::Actions, ActionController::Rendering, ActionController::ConditionalGet, AbstractController::Rendering, ActionController::Head, AbstractController::ViewPaths, ActionController::Renderers::All, ActionController::Redirecting, ActionController::Renderers, ActionController::RackDelegation, ActionController::Rendering, ActiveSupport::Benchmarkable, ActionController::Redirecting, AbstractController::Logger, ActionController::RackDelegation, ActionController::UrlFor, ActiveSupport::Benchmarkable, AbstractController::UrlFor, AbstractController::Logger, ActionDispatch::Routing::UrlFor, ActionController::UrlFor, ActionDispatch::Routing::PolymorphicRoutes, AbstractController::UrlFor, ActionController::HideActions, ActionDispatch::Routing::UrlFor, ActionController::Metal, ActionDispatch::Routing::PolymorphicRoutes, AbstractController::Base, ActionController::HideActions, ActiveSupport::Configurable, ActionController::Helpers, Object, AbstractController::Helpers, JSON::Ext::Generator::GeneratorMethods::Object, AbstractController::AssetPaths, ActiveSupport::Dependencies::Loadable, AbstractController::Translation, PP::ObjectMixin, AbstractController::Layouts, Kernel, AbstractController::Rendering, BasicObject AbstractController::ViewPaths, ActionController::Metal, AbstractController::Base, ActiveSupport::Configurable, Object, ActiveSupport::Dependencies::Loadable, JSON::Ext::Generator::GeneratorMethods::Object, PP::ObjectMixin, Kernel, BasicObject
  • 91. RAILS A DIETA Rails es modular
  • 92. RAILS A DIETA Rails es modular Para crear APIs, algunos Middlewares no son necesarios
  • 93. RAILS A DIETA Rails es modular Para crear APIs, algunos Middlewares no son necesarios rails-api
  • 94. use ActionDispatch::Static use Rack::Lock use #<ActiveSupport::Cache::Strategy::Loc alCache::Middleware:0x007fd3b32928c0> use Rack::Runtime use Rack::MethodOverride use ActionDispatch::RequestId use Rails::Rack::Logger use ActionDispatch::ShowExceptions use ActionDispatch::DebugExceptions use ActionDispatch::RemoteIp use ActionDispatch::Reloader use ActionDispatch::Callbacks use ActionDispatch::Cookies use ActionDispatch::Session::CookieStore use ActionDispatch::Flash use ActionDispatch::ParamsParser use ActionDispatch::Head use Rack::ConditionalGet use Rack::ETag use ActionDispatch::BestStandardsSupport use
  • 95. use ActionDispatch::Static use Rack::Lock use use ActionDispatch::Static #<ActiveSupport::Cache::Strategy::Loc use Rack::Lock alCache::Middleware:0x007fd3b32928c0> use use Rack::Runtime #<ActiveSupport::Cache::Strategy::LocalCac use Rack::MethodOverride he::Middleware:0x007fe74448cf50> use ActionDispatch::RequestId use Rack::Runtime use Rails::Rack::Logger use ActionDispatch::RequestId use ActionDispatch::ShowExceptions use Rails::Rack::Logger use ActionDispatch::DebugExceptions use ActionDispatch::ShowExceptions use ActionDispatch::RemoteIp use ActionDispatch::DebugExceptions use ActionDispatch::Reloader use ActionDispatch::RemoteIp use ActionDispatch::Callbacks use ActionDispatch::Reloader use ActionDispatch::Cookies use ActionDispatch::Callbacks use use ActionDispatch::Session::CookieStore ActiveRecord::ConnectionAdapters::Connecti use ActionDispatch::Flash onManagement use ActionDispatch::ParamsParser use ActiveRecord::QueryCache use ActionDispatch::Head use ActionDispatch::ParamsParser use Rack::ConditionalGet use ActionDispatch::Head use Rack::ETag use Rack::ConditionalGet use use Rack::ETag ActionDispatch::BestStandardsSupport use
  • 96. RAILS-API? • ActiveRecord (manejo de errores) • Validaciones (responder a varios formatos) • Controladores, sistema de rutas (versionamiento) • Muchas librerias(Gems) • Autenticación (oauth, token, basic auth) • Mismos web servers confiables (mismo hosting)

Editor's Notes

  • #2: \n
  • #3: Mi plan es hablarles acerca de las famosas y muy comunmente usadas APIs, como implementar una buena API que todo mundo quedra usarla y como ruby on rails te ayudara a hacerla en muy poco tiempo\n
  • #4: dicho de una manera mas sencilla:\n\n
  • #5: Asi como las interfaces de usuario ayudan a los usuarios a comunicarse con las aplicaciones, las apis ayudan a comunicar dos softwares distintos entre ellos\n
  • #6: Estas son algunos ejemplos de APIs, pueden ser tanto como librerias como SDK&amp;#x2019;s, el problema con esto, es que generalmente tienen que ser usadas en el mismo lenguaje de programacion, por ejemplo Net::HTTP es un ejemplo de la API de ruby para establecer conexiones http\n
  • #7: Estas fueron las primeras API&amp;#x2019;s que se empezaron a consumir en el mundo web, luego llegaron las wsdl&amp;#x2019;s y generalmente eran con mensajes en xml demaciaaado complejas, en esta platica quiero enfocarme a algunas mejores practicas para implementar apis usando las nuevas caracteristicas que se agregaron al http 1.1, especificamente al famoso REST\n
  • #8: REST nacio en la implementacion de HTTP 1.1, de alguna manera fue mejora del 1.0, y no es mas que un estilo o convension para transferir datos entre el servidor web y el navegador. REST es una manera de organizar recursos con url&amp;#x2019;s unicas por lo tanto, es un patron de dise&amp;#xF1;o para web services\n\nQue requisitos debe tener una aplicacion para ser RESTful ?\n
  • #9: El server se encarga del almacenamiento, el cliente se encarga de la UI y del estado.\n\nSin estado significa que ninguna llamada REST depende de llamadas pasadas, ocea que el servidor no mantiene ningun valor del cliente en sesion \n\nLa respuesta puede ser cacheable por el cliente o no, se debe de expresar explicitamente, para evitar que el cliente tenga copias obsoletas - Incrementa escalabilidad -\n\nEl cliente nunca podra saber si esta conectado al servidor final - balanceo de cargar, cache -\n\nInterface uniforme es que tiene que ser lo m&amp;#xE1;s explicito posible el mensaje\n\n
  • #10: El server se encarga del almacenamiento, el cliente se encarga de la UI y del estado.\n\nSin estado significa que ninguna llamada REST depende de llamadas pasadas, ocea que el servidor no mantiene ningun valor del cliente en sesion \n\nLa respuesta puede ser cacheable por el cliente o no, se debe de expresar explicitamente, para evitar que el cliente tenga copias obsoletas - Incrementa escalabilidad -\n\nEl cliente nunca podra saber si esta conectado al servidor final - balanceo de cargar, cache -\n\nInterface uniforme es que tiene que ser lo m&amp;#xE1;s explicito posible el mensaje\n\n
  • #11: El server se encarga del almacenamiento, el cliente se encarga de la UI y del estado.\n\nSin estado significa que ninguna llamada REST depende de llamadas pasadas, ocea que el servidor no mantiene ningun valor del cliente en sesion \n\nLa respuesta puede ser cacheable por el cliente o no, se debe de expresar explicitamente, para evitar que el cliente tenga copias obsoletas - Incrementa escalabilidad -\n\nEl cliente nunca podra saber si esta conectado al servidor final - balanceo de cargar, cache -\n\nInterface uniforme es que tiene que ser lo m&amp;#xE1;s explicito posible el mensaje\n\n
  • #12: El server se encarga del almacenamiento, el cliente se encarga de la UI y del estado.\n\nSin estado significa que ninguna llamada REST depende de llamadas pasadas, ocea que el servidor no mantiene ningun valor del cliente en sesion \n\nLa respuesta puede ser cacheable por el cliente o no, se debe de expresar explicitamente, para evitar que el cliente tenga copias obsoletas - Incrementa escalabilidad -\n\nEl cliente nunca podra saber si esta conectado al servidor final - balanceo de cargar, cache -\n\nInterface uniforme es que tiene que ser lo m&amp;#xE1;s explicito posible el mensaje\n\n
  • #13: El server se encarga del almacenamiento, el cliente se encarga de la UI y del estado.\n\nSin estado significa que ninguna llamada REST depende de llamadas pasadas, ocea que el servidor no mantiene ningun valor del cliente en sesion \n\nLa respuesta puede ser cacheable por el cliente o no, se debe de expresar explicitamente, para evitar que el cliente tenga copias obsoletas - Incrementa escalabilidad -\n\nEl cliente nunca podra saber si esta conectado al servidor final - balanceo de cargar, cache -\n\nInterface uniforme es que tiene que ser lo m&amp;#xE1;s explicito posible el mensaje\n\n
  • #14: El server se encarga del almacenamiento, el cliente se encarga de la UI y del estado.\n\nSin estado significa que ninguna llamada REST depende de llamadas pasadas, ocea que el servidor no mantiene ningun valor del cliente en sesion \n\nLa respuesta puede ser cacheable por el cliente o no, se debe de expresar explicitamente, para evitar que el cliente tenga copias obsoletas - Incrementa escalabilidad -\n\nEl cliente nunca podra saber si esta conectado al servidor final - balanceo de cargar, cache -\n\nInterface uniforme es que tiene que ser lo m&amp;#xE1;s explicito posible el mensaje\n\n
  • #15: operaciones comunes en sistemas de informacion, generalmente todo gira alrededor de estas operaciones basicas\n
  • #16: \n
  • #17: Representacion en datos, basicamente es un documento que se va a transferir del servidor al cliente\n\nOrigen de alguna informacion en especifico\n
  • #18: Representacion en datos, basicamente es un documento que se va a transferir del servidor al cliente\n\nOrigen de alguna informacion en especifico\n
  • #19: Representacion en datos, basicamente es un documento que se va a transferir del servidor al cliente\n\nOrigen de alguna informacion en especifico\n
  • #20: Hace un momento comentaba de que los primeros web services usaban estructuras de datos basadas en definiciones xml, llegaban a ser mensajes demaciado grandes, y era complicado para un humano leerlas, entonces que pasa, si usamos una estructura mas sensilla?\nPorque JSON ?, si se te complica hacer una estructura con json, algo estas haciendo mal, mensajes son muy cortos, human readable, gzip\n
  • #21: Hace un momento comentaba de que los primeros web services usaban estructuras de datos basadas en definiciones xml, llegaban a ser mensajes demaciado grandes, y era complicado para un humano leerlas, entonces que pasa, si usamos una estructura mas sensilla?\nPorque JSON ?, si se te complica hacer una estructura con json, algo estas haciendo mal, mensajes son muy cortos, human readable, gzip\n
  • #22: Ejemplo: middleware\n
  • #23: Ejemplo: middleware\n
  • #24: Ejemplo: middleware\n
  • #25: Como va a estar abierto a m&amp;#xE1;s personas, ejemplo de clientes, cuotas, \nnada de prametros ocultos, cuando regrese errores que los haga bien descriptivo\nbuena documentacion, eventos,\n
  • #26: Como va a estar abierto a m&amp;#xE1;s personas, ejemplo de clientes, cuotas, \nnada de prametros ocultos, cuando regrese errores que los haga bien descriptivo\nbuena documentacion, eventos,\n
  • #27: Como va a estar abierto a m&amp;#xE1;s personas, ejemplo de clientes, cuotas, \nnada de prametros ocultos, cuando regrese errores que los haga bien descriptivo\nbuena documentacion, eventos,\n
  • #28: administracion de cambios\nsi tienes duda de que publicar en tu api, no la publiques, alguien mas la va a implementar y tendras que soportarla\n
  • #29: administracion de cambios\nsi tienes duda de que publicar en tu api, no la publiques, alguien mas la va a implementar y tendras que soportarla\n
  • #30: administracion de cambios\nsi tienes duda de que publicar en tu api, no la publiques, alguien mas la va a implementar y tendras que soportarla\n
  • #31: administracion de cambios\nsi tienes duda de que publicar en tu api, no la publiques, alguien mas la va a implementar y tendras que soportarla\n
  • #32: administracion de cambios\nsi tienes duda de que publicar en tu api, no la publiques, alguien mas la va a implementar y tendras que soportarla\n
  • #33: administracion de cambios\nsi tienes duda de que publicar en tu api, no la publiques, alguien mas la va a implementar y tendras que soportarla\n
  • #34: \n
  • #35: Una buena API siempre debe seguir convenciones REST, basicamente es seguir la convencion de un buen patron de dise&amp;#xF1;o para solucionar este problema.\n\n
  • #36: GET, POST, DELETE, PUT, etc\n
  • #37: \n
  • #38: \n
  • #39: \n
  • #40: \n
  • #41: no regresaria ningun contenido, solo un http status code\n
  • #42: \n
  • #43: \n
  • #44: muy dificil de adminsitrar, porque un solo controlador se encargaria de despachar todas las versiones\n
  • #45: \n
  • #46: \n
  • #47: La informacion contenida en el header la utiliza el cliente y el servidor para ponerse de acuerdo como van a transmitir la informacion, esto significa que el cliente le esta diciendo al servidor que el soporta la version 2 de la api, y que debe regresarsela en modo json\n
  • #48: La informacion contenida en el header la utiliza el cliente y el servidor para ponerse de acuerdo como van a transmitir la informacion, esto significa que el cliente le esta diciendo al servidor que el soporta la version 2 de la api, y que debe regresarsela en modo json\n
  • #49: 401, Se excede la cuota mensual\n
  • #50: \n
  • #51: \n
  • #52: \n
  • #53: \n
  • #54: \n
  • #55: \n
  • #56: \n
  • #57: \n
  • #58: \n
  • #59: Mashery\nLimite de uso, para limitar a los usuarios de no hacer mal uso de los recursos, CDN pero para APIS, Balanceo de cargas\nOauth\nSandbox para probar\nbloqueo de IP&amp;#x2019;s, Accesos basados en roles\n
  • #60: se puede aprovechar al maximo lo que rails ofrece para crear apis muy poderosa, rails ya tiene REST implementado, sistema de cache, autenticacion, logging de eventos, MVC, observers, se puede extender su funcionalidad muy facil, por ejemplo montarle un fulltext search engine como solr, es muy facil escribir pruebas unitarias\n
  • #61: Rails ya nos da todo para hacer aplicaciones REST\n
  • #62: Rails soporta namespaces para los recurcos nativamente, pero puede llegar a ser un problema al resolver los nombres de los controladores, para esto alguien mas ya hizo algo al respecto\n
  • #63: \n
  • #64: \n
  • #65: \n
  • #66: \n
  • #67: \n
  • #68: \n
  • #69: \n
  • #70: \n
  • #71: Funciona transparente con el .to_json, active_model_serializer es bueno para aplicaciones web que usan javascript frameworks como ember o backbone\n
  • #72: \n
  • #73: \n
  • #74: \n
  • #75: Las pruebas son muy importantes al momento de desarrollar cualquier software, existen herramientas que hacen de esto literalmente un placer, muy facil de automatizar las pruebas\n
  • #76: \n
  • #77: \n
  • #78: \n
  • #79: \n
  • #80: \n
  • #81: \n
  • #82: basico para una api\n
  • #83: basico para una api\n
  • #84: basico para una api\n
  • #85: \n
  • #86: \n
  • #87: \n
  • #88: \n
  • #89: \n