Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Aula 1: HTTP Backend com Python e Webapp2

456d07b3f7a1ab66502e232fd9b1d378?s=47 Edson Hilios
September 30, 2014

Aula 1: HTTP Backend com Python e Webapp2

Nesta aula iremos aprender sobre o protocolo HTTP e sua aplicação para o desenvolvimento de APIs que podem ser utilizadas em diversos apps (Mobile, IoT e Web).

456d07b3f7a1ab66502e232fd9b1d378?s=128

Edson Hilios

September 30, 2014
Tweet

More Decks by Edson Hilios

Other Decks in Programming

Transcript

  1. HTTP Se comunicando através da internet 19 de Setembro de

    2014
  2. Enviando e recebendo informações Como que o caminhão do João

    vai enviar as informações até ele? ?
  3. None
  4. HTT-Quê? Em 1989 Tim Bernes-Lee cientista da computação britânico, trabalhando

    no CERN, fez uma proposta de software para aumentar a eficácia das comunicações no laboratório e, que poderia ser extendida ao mundo.
  5. World Wide Web HTT-Quê? Clientes Servidores http://www.ntu.edu.sg/home/ehchua/programming/webprogramming/HTTP_Basics.html

  6. HTT-Quê? Requisição Resposta www

  7. HTT-Quem? O seu navegador é responsável em transformar o endereço

    que digitou, em uma requisição HTTP.
  8. Uniform Resource Locator (URL) http://www.google.com:80/search?q=breaking%20bad • Protocolo • Endereço •

    Porta (opcional) • Caminho para o arquivo / pasta Parâmentro Query-string
  9. None
  10. Formatação da URL Caracteres ASCII: A B C D E

    F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 - _ . ~ Caracteres com significado especial: ! * ' ( ) ; : @ & = + $ , / ? % # [ ] http://en.wikipedia.org/wiki/Percent-encoding
  11. URLs http://localhost:8080 http://127.0.0.1:8080 https://facebook.com/zuck http://google.com/search?q=chrome mailto:user@test101.com ftp://www.ftp.org/docs/test.txt

  12. Requisição HTTP É apenas um texto com um formato padrão:

    • Uma ação / verbo • Caminho do arquivo ou pasta solicitado • O endereço do servidor • Informações de cabeçalho • Dados da requisição (ex: um formulário)
  13. Requisição HTTP GET /search/index.html HTTP/1.1 Host: www.google.com Accept: image/gif, image/jpeg,

    */* Accept-Language: en-us Content-Type: application/x-www-form-urlenconde Content-Length: 207 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0) q=breaking%20bad Requisição Headers / Cabeçalho Linha em branco Corpo (opicional)
  14. Verbos HTTP A mesma URL pode realizar ações diferentes: •

    http://host.com/artigos ▪ GET ▪ POST ▪ PUT ▪ DELETE
  15. Ações através dos verbos • GET • POST • PUT

    • DELETE CRUD Create - Read - Update - Delete Outros verbos: HEAD, TRACE, OPTIONS, CONNECT
  16. Resposta HTTP • Código do status da requisição • Tipo

    do conteúdo (imagem, html, vídeo) • Cabeçalhos • Conteúdo
  17. Resposta HTTP HTTP/1.1 200 Date: Sun, 18 Oct 2013 08:56:53

    GMT Server: Apache/2.2.14 (Win32) Last-Modified: Sat, 20 Nov 2012 07:16:26 GMT Content-Length: 44 Content-type: text/html <html><body><h1>Olá Mundo!</h1></body></html> Status da resposta Headers / Cabeçalho Linha em branco Corpo da resposta
  18. None
  19. Status da resposta HTTP • 1xx: Informação • 2xx: Sucesso

    • 3xx: Redirecionar • 4xx: Erro no cliente • 5xx: Erro no servidor
  20. Status importantes Código Descrição 200 OK 201 Criado 204 Modificado

    / Atualizado / Deletado 301 Movido a outro endereço 401 Não autorizado 403 Não permitido 404 Não encontrado 500 Erro interno do servidor http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
  21. Tipos de conteúdo • HTML text/html • Imagem image/gif, image/jpeg

    • Vídeo video/mp4 • JSON application/json
  22. JSON Padrão de formatação de texto para transmitir informações entre

    duas aplicações/computadores de forma eficiente. Todas as linguagens de programação já tem suporte ao formato, que se tornou *padrão.
  23. JSON Imagine uma tabela de banco de dados: Carro Hora

    Temperatura Coordenadas EFG-9809 2014/08/03 15:01:32 3ºC 51° 28' 38" ABC-5432 2014/06/30 12:34:56 4ºC 23° 42' 23" GTD-1357 2014/07/25 54:32:10 3ºC 56° 43' 83" FRA-7532 2014/08/01 01:23:45 2ºC 12° 28' 78" ZOO-6853 2014/07/31 32:54:21 5ºC 90° 23' 38"
  24. JSON [ { "Carro": "EFG-9809", "Hora": "2014/08/03 15:01:32", "Temperatura": 3,

    "Coordenadas": {lat: 1.234, lng: -3.456} }, { ... }, { ... }, ... ]
  25. Facebook App: Informação do banco de dados trafegando em JSON

    através do protocolo HTTP.
  26. Recapitulando • URL: http://localhost/caminho/do/arquivo • Verbos: GET, POST, PUT, DELETE

    • Status: 200, 404, 500 • Tipos de conteúdo: HTML, JSON
  27. Um serviço web capaz de criar, ler, atualizar e deletar

    as informações dos caminhões. Construindo uma API API HTTP HTTP
  28. Construindo uma API Uma API é um software que define

    um padrão de comunicação criando uma interface comum onde qualquer dispositivo pode cosumir suas informações.
  29. Servidores HTTP São programas de computador especializados em receber e

    requisições no formato HTTP, realizar alguma ação e fornecer uma resposta a eles.
  30. Quem usa Python?

  31. Frameworks são bibliotecas de código que visam adicionar uma funcionalidade

    genérica, de uma forma consitente, para simplificar a construção de uma ferramentas mais específicas, de maneira rapida e fácil. Frameworks HTTP
  32. Instalação $ pip install webob $ pip install paste $

    pip install webapp2
  33. No seu computador crie um diretório vazio e o arquivo

    servidor.py. imt-webapp/ | models.py | servidor.py Estrutura
  34. Gerando uma resposta import webapp2 class HelloWorld(webapp2.RequestHandler): def get(self): self.response.write('Ola

    Mundo!') # Nao utilizar acentos! servidor.py
  35. Rotas As rotas é um processo de pegar uma URL

    e decidir qual aplicação vai ser executada. Eles tem o papel de mapear o endereço com a função. GET /endereco class Hello(Request): def get(self): # Executa ação!
  36. Rotas routes = [ ('/', HelloWorld), ] app = webapp2.WSGIApplication(routes,

    debug=True) servidor.py
  37. Testando o servidor if __name__ == '__main__': from paste import

    httpserver httpserver.serve(app) servidor.py
  38. import webapp2 class HelloWorld(webapp2.RequestHandler): def get(self): self.response.write('Ola Mundo!') routes =

    [ ('/', HelloWorld), ] app = webapp2.WSGIApplication(routes, debug=True) if __name__ == '__main__': from paste import httpserver httpserver.serve(app) servidor.py
  39. Run baby run! $ python servidor.py serving on http://127.0.0.1:8080

  40. Para parar aperte as teclas Ctrl + C e espere.

    A cada alteração dos arquivos do servidor você deve reinicia-lo. Stop!
  41. class UrlHandler(webapp2.RequestHandler): def get(self): # Requisição self.request.method # GET self.request.url

    # http://localhost:8080/my-path?q=1 self.request.path # /my-path self.request.headers # [ … ] self.request.params # {'q': 1} # Resposta self.response.status = 200 # Padrão self.response.content_type = 'text/html' # Padrão self.response.redirect('http://www.google.com/') self.response.write('OK')
  42. Lendo as informações enviadas # GET /url?id=1234&log=true class UrlHandler(webapp2.RequestHandler): def

    get(self): self.request.params.get('id') # => 1234 self.request.params.get('log') # => 'true' self.request.params.get('foo') # => None self.request.params.get('foo', 'bar') # => 'bar'
  43. Método Dispatch Função que é executada toda vez que uma

    requisição é iniciada, é boa para iniciar a conexão com o banco de dados por exemplo. import sqlite3 class UrlHandler(webapp2.RequestHandler): def dispatch(self): self.dbconn = sqlite3.connect('db.sqlite3')
  44. Objetivos • Gerenciar dispositivos ▪ Listar ▪ Criar ▪ Atualizar

    ▪ Deletar • Gerencia medidas dos dispositivos ▪ Listar ▪ Criar
  45. Estrutura de Dados devices id PRIMARY KEY nome TEXT obs

    TEXT medidas id PRIMARY KEY device_id FOREIGN KEY recebido_em DATETIME temperatura INT humidade INT lat INT lng INT
  46. Modelos do Banco de dados Caso vocês não possuam o

    arquivo de modelos models.py, que pega as informações do banco de dados e as retorna tratadas, baixe o kit: http://bit.ly/imt-backend
  47. Modelo de dados import models # Dispositivos models.Devices.get_all() # Retorna

    todos os dispositivos models.Devices.get_by_id(XXX) # Retorna o dispositivo com ID models.Devices.get_by(id=XXX, foo='a') # Retorna o dispositivo com o parametro models.Devices.count() # Retorna a quantidade de dispositivos # Medidas models.Medidas.get_all() # SELECT * FROM medidas models.Medidas.get_by_id(XXX) # ... WHERE id=XXX models.Medidas.get_by(abc=XXX, foo='a') # ... WHERE abc=XXX AND foo='a' models.Medidas.count()
  48. Modelo de dados # Cria um novo device mas não

    salva no banco de dados d = models.Devices(nome='ABC', obs=123) print d["nome"] # => ABC print d["obs"] # => 123 d.save() # Executa o INSERT no banco de dados print d["id"] # => X (o ID do item após ser inserido no banco) d.delete()
  49. Modelo de dados # Retorna o dispositivo com o ID

    = 123 d = models.Devices.get_by_id(123) print d["nome"] # Exibe o nome salvo no banco d["nome"] = "Foo Bar" # Altera o nome d.save() # Realiza o UPDATE
  50. Criando a base de dados e adicionando alguns dados fictícios:

    Estrutura de dados $ python migrate.py ___ ___ __ ____ _ ____ ___ __ _____ ___ ___ | |_) | | \ / /`_ | |_ | |\ | | |_ | |_) / /\ | | / / \ | |_) |_|_) |_|_/ \_\_/ |_|__ |_| \| |_|__ |_| \ /_/--\ |_| \_\_/ |_| \ ________________________________________________________________________
  51. Planejando URLs /api/devices /api/devices/ID – Dispositivos – Medidas do dispositivo

  52. Devices Verbo URL Parâmetros GET /api/devices POST /api/devices PUT /api/devices

    {'id': N} DELETE /api/devices {'id': N}
  53. Crie o arquivo api.py. imt-webapp/ | api.py | models.py |

    servidor.py Estrutura
  54. Controlador de Devices import webapp2 import json import models class

    DevicesHandler(webapp2.RequestHandler): def get(self): pass def post(self): pass def put(self): pass def delete(self): pass api.py
  55. from api import DevicesHandler # ... routes = [ #

    ..., ('/api/devices', DevicesHandler), ] Rota servidor.py
  56. GET /api/devices def get(self): 'Retorna todos os devices registrados' devices

    = models.Devices.get_all() self.response.content_type = 'application/json' self.response.write( json.dumps(devices) # Converte para o formato JSON (devices.to_dict) ) api.py
  57. Resposta [ { "id": 1, "nome": "DEF-1234", "obs": "DEF-1234", }

    ] [{"id": 1,"nome": "DEF-1234","obs": ""}] application/json
  58. POST /api/devices def post(self): 'Cria um novo device, parametros: nome,

    obs' device = models.Device( nome=self.request.params.get('nome'), obs=self.request.params.get('obs') ) device.save() self.response.content_type = 201 # Criado com sucesso api.py
  59. PUT /api/devices def put(self): 'Atualiza um device, parametros: id, nome,

    obs' device = models.Device.get_by_id( self.request.params.get('id') ) if not device: self.abort(404) device['nome'] = self.request.params.get('nome') # device.nome = ... device['obs'] = self.request.params.get('obs') # device.obs = ... device.save() self.response.content_type = 204 # Atualizado com sucesso api.py
  60. DELETE /api/devices def delete(self): 'Deleta um device, parametros: id' device

    = models.Device.get_by_id( self.request.params.get('id') ) if not device: self.abort(404) device.delete() self.response.content_type = 204 # Deletado com sucesso api.py
  61. Medidas do Device Verbo URL Parâmetros GET /api/devices/(.+) {'device_id': N}

    POST /api/devices/(.+) {'device_id': N}
  62. Rota GET /api/devices/(.+) def get(self, device_id=None):

  63. Rota routes = [ # ..., ('/api/devices/(.+)', MedidasDeviceHandler), ] servidor.py

  64. Controlador de Medidas # ... class MedidasDeviceHandler(webapp2.RequestHandler): def get(self, device_id=None):

    pass def post(self, device_id=None): pass api.py
  65. GET /api/device/N def get(self, device_id): 'Retorna um device com todas

    as medidas coletadas' device = models.Devices.get_by_id(device_id) if not device: self.abort(404) device['medidas'] = device.medidas() self.response.content_type = 'application/json' self.response.write(json.dumps(device)) api.py
  66. Resposta { "id": 1, "nome": "DEF-1234", "obs": "DEF-1234", "medidas": [

    { "id": 3, "recebido_em": "2014-09-14 21:22:07", "temperatura": 2.19, "humidade": 0.2, "lat": -23.648241, "lng": -46.573678 }, ... ] } application/json
  67. POST /api/device/N def post(self, device_id): 'Cria uma nova medida para

    um device' device = models.Devices.get_by_id(device_id) if not device: self.abort(404) medida = models.Medidas( device_id=device_id, temperatura=self.request.params.get('temperatura'), humidade=self.request.params.get('humidade'), lat=self.request.params.get('lat'), lng=self.request.params.get('lng') ) medida.save() self.response.status = 204
  68. Alerta de temperatura Caso a temperatura ultrapasse 5ºC devemos enviar

    um email de alerta para que seja tomada as providencias. Em qual momento recolhemos a temperatura?
  69. import smtplib from email.mime.test import MIMEText # ... def post(self,

    device_id): # ... if not medida.temperatura >= 5: msg = MIMEText(''' Atencao! O dispositivo #{device_id} esta com a temperatura de {temperatura}C. '''.format(**medida)) msg['Subject'] = 'Temperatura alta!' s = smtplib.SMTP('smtp.gmail.com:587') s.starttls() s.login('username', '*****') s.sendmail('', '', msg.as_string()) s.quit() https://docs.python.org/2/library/email-examples.html
  70. Parabéns hipster!

  71. Próxima aula HTML & CSS