construindo apis usando rails

59
Criando APIs - Usando Rails Fernando Kakimoto Desenvolvedor @ ThoughtWorks

Upload: fernando-kakimoto

Post on 10-May-2015

969 views

Category:

Technology


4 download

DESCRIPTION

Essa apresentação aconteceu no 17 encontro dos usuários de Rails de PE - Frevo on Rails. Nela, eu abordo 4 tópicos importantes na hora de implementar APIs: Rest, Consistencia, Versionamento e Segurança.

TRANSCRIPT

Page 1: Construindo APIs Usando Rails

Criando APIs - Usando RailsFernando KakimotoDesenvolvedor @ ThoughtWorks

Page 2: Construindo APIs Usando Rails

O que é uma API mesmo?

Application Programming Interface

Biblioteca que inclui especificações para rotinas, estruturas de dados, objetos, classes e

variáveis

Page 3: Construindo APIs Usando Rails
Page 4: Construindo APIs Usando Rails
Page 5: Construindo APIs Usando Rails

Características de boas APIs

Fácil de aprender e memorizar

Dificilmente usada de maneira errada

Minimalista

Completa

Page 6: Construindo APIs Usando Rails

Tópicos para hoje

REST

Consistência

Versionamento

Segurança

Page 7: Construindo APIs Usando Rails

REST

REpresentational State Transfer

Um padrão arquitetural para sistemas hipermídias distribuídos

Page 8: Construindo APIs Usando Rails

REST

URL base

Tipo de mídia

Operações (Método HTTP)

Page 9: Construindo APIs Usando Rails

REST

GET https://api.twitter.com/1.1/statuses/ment

ions_timeline.json

Page 10: Construindo APIs Usando Rails

REST

GET https://api.twitter.com/1.1/statuses/ment

ions_timeline.json

URL base

Page 11: Construindo APIs Usando Rails

REST

GET https://api.twitter.com/1.1/statuses/ment

ions_timeline.jsonTipo de mídia

Page 12: Construindo APIs Usando Rails

REST

GET https://api.twitter.com/1.1/statuses/ment

ions_timeline.json

Método

Page 13: Construindo APIs Usando Rails

2 URLs base por recurso

• GET /tickets - recupera conjunto de tickets

• GET /tickets/12 - recupera o ticket #12

• POST /tickets - cria um novo ticket

• PUT /tickets/12 - atualiza ticket #12

• DELETE /tickets/12 - remove ticket #12

Page 14: Construindo APIs Usando Rails

Restrições REST

Cliente-Servidor

Stateless

Cacheable

Sistema em camadas

Interface Uniforme

Page 15: Construindo APIs Usando Rails

API RESTful

API implementada usando princípios HTTP e REST

Page 16: Construindo APIs Usando Rails

> nandokakimoto@Development$ rails new blog

> nandokakimoto@blog$ rails generate scaffold Post name:string title:string content:text

> nandokakimoto@blog$ rake routes

posts GET /posts(.:format) posts#index POST /posts(.:format) posts#create new_post GET /posts/new(.:format) posts#new edit_post GET /posts/:id/edit(.:format) posts#edit post GET /posts/:id(.:format) posts#show PUT /posts/:id(.:format) posts#update DELETE /posts/:id(.:format) posts#destroy

Page 17: Construindo APIs Usando Rails

Consistência

Page 18: Construindo APIs Usando Rails
Page 19: Construindo APIs Usando Rails

Métodos Safe

Métodos que nunca modificam um recurso

Dados não devem ser alterados como resultado de uma requisição GET

Page 20: Construindo APIs Usando Rails

Métodos Idempotentes

Métodos com o mesmo resultado mesmo que requisição seja repetida

diversas vezesPOST é o único método não idempotente

Page 21: Construindo APIs Usando Rails

Código de Resposta

Respostas HTTP padronizam como informar o cliente sobre o resultado da

sua requisição

Page 22: Construindo APIs Usando Rails

Código de Resposta

1xx - Informacional

2xx - Sucesso

3xx - Redirecionamento

4xx - Erro de cliente

5xx - Erro de servidor

Page 23: Construindo APIs Usando Rails

> nandokakimoto@blog$ curl -v http://localhost:3000/posts.json

* Connected to localhost (127.0.0.1) port 3000 (#0)> GET /posts.json HTTP/1.1<< HTTP/1.1 200 OK < Server: WEBrick/1.3.1 (Ruby/1.9.3/2013-06-27)[{"content": "Melhor evento ever <3 <3 <3", "created_at": "2013-09-03T02:12:26Z", "id": 1, "name": "Frevo on Rails", "title": "Evento 14 Setembro", "updated_at": "2013-09-03T02:12:26Z"}]

Page 24: Construindo APIs Usando Rails

> nandokakimoto@blog$ curl -v -d "post[name]=Geek Night&post[title]=Scala Dojo&post[content]=Come and learn Scala" http://localhost:3000/posts.json

* Connected to localhost (127.0.0.1) port 3000 (#0)> POST /posts.json HTTP/1.1> Host: localhost:3000<< HTTP/1.1 201 Created < Location: http://localhost:3000/posts/2< Server: WEBrick/1.3.1 (Ruby/1.9.3/2013-06-27){"content": "Come and learn Scala", "created_at": "2013-09-04T01:19:33Z", "id”: 2, "name": "Geek Night", "title":"Scala Dojo", "updated_at": "2013-09-04T01:19:33Z"}

Page 25: Construindo APIs Usando Rails

> nandokakimoto@blog$ curl -v -d "post[name]=Geek Night&post[content]=Come and learn Scala" http://localhost:3000/posts.json

* Connected to localhost (127.0.0.1) port 3000 (#0)> POST /posts.json HTTP/1.1> Host: localhost:3000> Content-Length: 56> < HTTP/1.1 422 < Server: WEBrick/1.3.1 (Ruby/1.9.3/2013-06-27)< Content-Length: 28{"title":["can't be blank"]}

Page 26: Construindo APIs Usando Rails

Versionamento

Page 27: Construindo APIs Usando Rails
Page 28: Construindo APIs Usando Rails

Versionamento

Sempre versione a sua APIDiferentes opniões sobre se a versão deve estar na URL ou no

cabeçalho

Page 29: Construindo APIs Usando Rails
Page 30: Construindo APIs Usando Rails

Versionamento

Versionist - https://github.com/bploetz/versionist

RocketPants - https://github.com/filtersquad/rocket_pants

Page 31: Construindo APIs Usando Rails

config/routes.rb

Page 32: Construindo APIs Usando Rails

> nandokakimoto@blog$ rake routes

(…)

GET /api/v1/products(.:format) api/v1/posts#indexPOST /api/v1/products(.:format) api/v1/posts#createGET /api/v1/products/new(.:format) api/v1/posts#newGET /api/v1/products/:id/edit(.:format) api/v1/posts#editGET /api/v1/products/:id(.:format) api/v1/posts#showPUT /api/v1/products/:id(.:format) api/v1/posts#updateDELETE /api/v1/products/:id(.:format) api/v1/posts#destroy

Page 33: Construindo APIs Usando Rails

app/controllers/api/v1/posts_controller.rb

Page 34: Construindo APIs Usando Rails

> nandokakimoto@blog$ curl -v http://localhost:3000/api/v1/posts.json

* Connected to localhost (127.0.0.1) port 3000 (#0)> GET /api/v1/posts HTTP/1.1> Host: localhost:3000<< HTTP/1.1 200 OK < Server: WEBrick/1.3.1 (Ruby/1.9.3/2013-06-27)< Content-Length: 330[{"content": "Melhor evento ever <3 <3 <3", "created_at":"2013-09-03T02:12:26Z", "id": 1, "name": "Frevo on Rails", "title": "Evento 14 Setembro", "updated_at": "2013-09-03T02:12:26Z"}, {"content": "Come and learn Scala", "created_at": "2013-09-04T01:19:33Z", "id": 2, "name": "Geek Night", "title": "Scala Dojo", "updated_at": "2013-09-04T01:19:33Z"}]

Page 35: Construindo APIs Usando Rails

> nandokakimoto@blog$ curl -v http://localhost:3000/api/v1/posts/15.json

* Connected to localhost (127.0.0.1) port 3000 (#0)> GET /api/v1/posts/15.json HTTP/1.1> Host: localhost:3000> < HTTP/1.1 404 Not Found < Server: WEBrick/1.3.1 (Ruby/1.9.3/2013-06-27)< Content-Length: 1<

Page 36: Construindo APIs Usando Rails

Versionamento

Novo RequisitoMostrar apenas id, nome e título do post

Page 37: Construindo APIs Usando Rails

config/routes.rb

Page 38: Construindo APIs Usando Rails

> nandokakimoto@blog$ rake routes

(…)

GET /api/v2/posts(.:format) api/v2/posts#index POST /api/v2/posts(.:format) api/v2/posts#create GET /api/v2/posts/new(.:format) api/v2/posts#new GET /api/v2/posts/:id/edit(.:format) api/v2/posts#edit GET /api/v2/posts/:id(.:format) api/v2/posts#show PUT /api/v2/posts/:id(.:format) api/v2/posts#update DELETE /api/v2/posts/:id(.:format) api/v2/posts#destroy

Page 39: Construindo APIs Usando Rails

app/controllers/api/v2/posts_controller.rb

Page 40: Construindo APIs Usando Rails

RABL

RABL (Ruby API Builder Language) consiste num sistema de template RAILS para geração de JSON

Page 41: Construindo APIs Usando Rails

app/views/api/v2/show.rabl.json

app/views/api/v2/index.rabl.json

Page 42: Construindo APIs Usando Rails

> nandokakimoto@blog$ curl -v http://localhost:3000/api/v2/posts

* Connected to localhost (127.0.0.1) port 3000 (#0)> GET /api/v2/posts HTTP/1.1> Host: localhost:3000<< HTTP/1.1 200 OK < Server: WEBrick/1.3.1 (Ruby/1.9.3/2013-06-27)< Content-Length: 113[{"id":1,"name":"Frevo on Rails","title":"Evento 14 Setembro"},{"id”:2,"name":"Geek Night","title":"Scala Dojo"}]

Page 43: Construindo APIs Usando Rails
Page 44: Construindo APIs Usando Rails

Segurança

Page 45: Construindo APIs Usando Rails

HTTP Basic Authentication

Solução mais simples

Fácil de implementar

Maioria dos clientes suportam

Page 46: Construindo APIs Usando Rails

app/controllers/api/v2/posts_controller.rb

Page 47: Construindo APIs Usando Rails

> nandokakimoto@blog$ curl -v http://localhost:3000/api/v2/posts

* Connected to localhost (127.0.0.1) port 3000 (#0)> GET /api/v2/posts HTTP/1.1> Host: localhost:3000<< HTTP/1.1 200 OK < Server: WEBrick/1.3.1 (Ruby/1.9.3/2013-06-27)< Content-Length: 113[{"id":1,"name":"Frevo on Rails","title":"Evento 14 Setembro"},{"id”:2,"name":"Geek Night","title":"Scala Dojo"}]

Page 48: Construindo APIs Usando Rails

> nandokakimoto@blog$ curl -v -d "post[name]=RubyConf&post[title]=RubyConf Details&post[content]=RubyConf was awesome" http://localhost:3000/api/v2/posts.json

* Connected to localhost (127.0.0.1) port 3000 (#0)> POST /api/v2/posts.json HTTP/1.1> Host: localhost:3000> Content-Length: 82> < HTTP/1.1 401 Unauthorized < WWW-Authenticate: Basic realm="Application"< Server: WEBrick/1.3.1 (Ruby/1.9.3/2013-06-27)< Content-Length: 27< HTTP Basic: Access denied.

Page 49: Construindo APIs Usando Rails

> nandokakimoto@blog$ curl -v -d "post[name]=RubyConf&post[title]=RubyConf Details&post[content]=RubyConf was awesome" http://localhost:3000/api/v2/posts.json -u "admin:secret"

* Connected to localhost (127.0.0.1) port 3000 (#0)* Server auth using Basic with user 'admin'> POST /api/v2/posts.json HTTP/1.1> Authorization: Basic YWRtaW46c2VjcmV0> Host: localhost:3000> Content-Length: 83> < HTTP/1.1 201 Created< Location: http://localhost:3000/api/v2/posts/3 < Server: WEBrick/1.3.1 (Ruby/1.9.3/2013-06-27)< Content-Length: 159{"id":3,"name":"RubyConf","title":"RubyConf Details”}

Page 50: Construindo APIs Usando Rails

Token de Acesso

Maior entropia

Token é salvo no servidor

Data de expiração

Page 51: Construindo APIs Usando Rails

> nandokakimoto@blog$ rails g model api_key access_tokeninvoke active_record

create db/migrate/20130907211645_create_api_keys.rb create app/models/api_key.rb invoke test_unit create test/unit/api_key_test.rb create test/fixtures/api_keys.yml

Page 52: Construindo APIs Usando Rails

app/model/api_key.rb

Page 53: Construindo APIs Usando Rails

app/controllers/api/v2/posts_controller.rb

Page 54: Construindo APIs Usando Rails

> nandokakimoto@blog$ curl -v http://localhost:3000/api/v2/posts

curl -v http://localhost:3000/api/v2/posts* Connected to localhost (127.0.0.1) port 3000 (#0)> GET /api/v2/posts HTTP/1.1> Host: localhost:3000> < HTTP/1.1 401 Unauthorized < WWW-Authenticate: Token realm="Application"< Server: WEBrick/1.3.1 (Ruby/1.9.3/2013-06-27)< Content-Length: 27< HTTP Token: Access denied.

Page 55: Construindo APIs Usando Rails

> nandokakimoto@blog$ curl -v http://localhost:3000/api/v2/posts -H 'Authorization: Token token=”8219a125816b331d0e478eeab566bf7c”'

* Connected to localhost (127.0.0.1) port 3000 (#0)> GET /api/v2/posts HTTP/1.1> Host: localhost:3000> Authorization: Token token="8219a125816b331d0e478eeab566bf7c"> < HTTP/1.1 200 OK < Server: WEBrick/1.3.1 (Ruby/1.9.3/2013-06-27)< Content-Length: 168[{"id":1,"name":"Frevo on Rails","title":"Evento 14 Setembro"},{"id":2,"name":"Geek Night","title":"Scala Dojo"},{"id":3,"name":"RubyConf","title":"RubyConf Details"}]

Page 56: Construindo APIs Usando Rails

OAuth

“An open protocol to allow secure authorization in a simple and standard method from web, mobile and desktop application”

- http://oauth.net -

Page 57: Construindo APIs Usando Rails

OAuth

Doorkeeper

Oauth2

Page 58: Construindo APIs Usando Rails

Tópicos Futuros

Filtros, ordenação, busca

Paginação

Documentação

Limitação de uso

Page 59: Construindo APIs Usando Rails

Pra Terminar

API é a intefarce de usuário para os desenvolvedores

Trabalhe para garantir que ela seja funcional e prazerosa de usar