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

Aula 1: HTTP Backend com Python e Webapp2

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).

Edson Hilios

September 30, 2014
Tweet

More Decks by Edson Hilios

Other Decks in Programming

Transcript

  1. 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.
  2. 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
  3. 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
  4. 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)
  5. 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)
  6. Verbos HTTP A mesma URL pode realizar ações diferentes: •

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

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

    do conteúdo (imagem, html, vídeo) • Cabeçalhos • Conteúdo
  9. 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
  10. Status da resposta HTTP • 1xx: Informação • 2xx: Sucesso

    • 3xx: Redirecionar • 4xx: Erro no cliente • 5xx: Erro no servidor
  11. 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
  12. Tipos de conteúdo • HTML text/html • Imagem image/gif, image/jpeg

    • Vídeo video/mp4 • JSON application/json
  13. 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.
  14. 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"
  15. JSON [ { "Carro": "EFG-9809", "Hora": "2014/08/03 15:01:32", "Temperatura": 3,

    "Coordenadas": {lat: 1.234, lng: -3.456} }, { ... }, { ... }, ... ]
  16. Recapitulando • URL: http://localhost/caminho/do/arquivo • Verbos: GET, POST, PUT, DELETE

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

    as informações dos caminhões. Construindo uma API API HTTP HTTP
  18. 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.
  19. 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.
  20. 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
  21. No seu computador crie um diretório vazio e o arquivo

    servidor.py. imt-webapp/ | models.py | servidor.py Estrutura
  22. 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!
  23. Testando o servidor if __name__ == '__main__': from paste import

    httpserver httpserver.serve(app) servidor.py
  24. 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
  25. Para parar aperte as teclas Ctrl + C e espere.

    A cada alteração dos arquivos do servidor você deve reinicia-lo. Stop!
  26. 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')
  27. 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'
  28. 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')
  29. Objetivos • Gerenciar dispositivos ▪ Listar ▪ Criar ▪ Atualizar

    ▪ Deletar • Gerencia medidas dos dispositivos ▪ Listar ▪ Criar
  30. 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
  31. 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
  32. 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()
  33. 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()
  34. 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
  35. Criando a base de dados e adicionando alguns dados fictícios:

    Estrutura de dados $ python migrate.py ___ ___ __ ____ _ ____ ___ __ _____ ___ ___ | |_) | | \ / /`_ | |_ | |\ | | |_ | |_) / /\ | | / / \ | |_) |_|_) |_|_/ \_\_/ |_|__ |_| \| |_|__ |_| \ /_/--\ |_| \_\_/ |_| \ ________________________________________________________________________
  36. 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
  37. from api import DevicesHandler # ... routes = [ #

    ..., ('/api/devices', DevicesHandler), ] Rota servidor.py
  38. 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
  39. Resposta [ { "id": 1, "nome": "DEF-1234", "obs": "DEF-1234", }

    ] [{"id": 1,"nome": "DEF-1234","obs": ""}] application/json
  40. 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
  41. 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
  42. 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
  43. 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
  44. 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
  45. 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
  46. 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?
  47. 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