En esta platica trate de transmitir mejores practicas que se deben tener en cuenta cuando se diseña una API, y como ruby on rails te podria ayudar a desarrollarla en muy poco tiempo
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
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
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
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
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
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)
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
dicho de una manera mas sencilla:\n\n
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
Estas son algunos ejemplos de APIs, pueden ser tanto como librerias como SDK&#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
Estas fueron las primeras API&#x2019;s que se empezaron a consumir en el mundo web, luego llegaron las wsdl&#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
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&#x2019;s unicas por lo tanto, es un patron de dise&#xF1;o para web services\n\nQue requisitos debe tener una aplicacion para ser RESTful ?\n
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&#xE1;s explicito posible el mensaje\n\n
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&#xE1;s explicito posible el mensaje\n\n
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&#xE1;s explicito posible el mensaje\n\n
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&#xE1;s explicito posible el mensaje\n\n
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&#xE1;s explicito posible el mensaje\n\n
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&#xE1;s explicito posible el mensaje\n\n
operaciones comunes en sistemas de informacion, generalmente todo gira alrededor de estas operaciones basicas\n
\n
Representacion en datos, basicamente es un documento que se va a transferir del servidor al cliente\n\nOrigen de alguna informacion en especifico\n
Representacion en datos, basicamente es un documento que se va a transferir del servidor al cliente\n\nOrigen de alguna informacion en especifico\n
Representacion en datos, basicamente es un documento que se va a transferir del servidor al cliente\n\nOrigen de alguna informacion en especifico\n
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
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
Ejemplo: middleware\n
Ejemplo: middleware\n
Ejemplo: middleware\n
Como va a estar abierto a m&#xE1;s personas, ejemplo de clientes, cuotas, \nnada de prametros ocultos, cuando regrese errores que los haga bien descriptivo\nbuena documentacion, eventos,\n
Como va a estar abierto a m&#xE1;s personas, ejemplo de clientes, cuotas, \nnada de prametros ocultos, cuando regrese errores que los haga bien descriptivo\nbuena documentacion, eventos,\n
Como va a estar abierto a m&#xE1;s personas, ejemplo de clientes, cuotas, \nnada de prametros ocultos, cuando regrese errores que los haga bien descriptivo\nbuena documentacion, eventos,\n
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
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
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
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
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
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
\n
Una buena API siempre debe seguir convenciones REST, basicamente es seguir la convencion de un buen patron de dise&#xF1;o para solucionar este problema.\n\n
GET, POST, DELETE, PUT, etc\n
\n
\n
\n
\n
no regresaria ningun contenido, solo un http status code\n
\n
\n
muy dificil de adminsitrar, porque un solo controlador se encargaria de despachar todas las versiones\n
\n
\n
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
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
401, Se excede la cuota mensual\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
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&#x2019;s, Accesos basados en roles\n
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
Rails ya nos da todo para hacer aplicaciones REST\n
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
\n
\n
\n
\n
\n
\n
\n
\n
Funciona transparente con el .to_json, active_model_serializer es bueno para aplicaciones web que usan javascript frameworks como ember o backbone\n
\n
\n
\n
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