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

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