Desenvolvendo com Python e Google App Engine

Importante: a documentação oficial do Google App Engine aqui referenciada está disponível em português. Basta selecionar o idioma no canto inferior direito, caso esteja em outro idioma.

Sumário do post:

No último post nós vimos como desenvolver um serviço web bem simples usando Python e CGI. Mas, conforme vimos no próprio post, CGI não é o mecanismo mais adequado para dar suporte a um aplicativo web.

Do seu início até final da década de 90, a web era usada principalmente para a publicação de conteúdo em HTML. Porém, algum tempo depois ela passou a ser usada também como um ambiente para execução de aplicações completas.

O crescimento das aplicações possibilitou a observação de que boa parte dos projetos web tinham alguns componentes básicos em comum, gerando uma grande quantidade de retrabalho a cada novo projeto, o que acarretaria um alto custo para cada projeto, e também aumentaria as chances de o sistema apresentar defeitos. Visando eliminar boa parte do retrabalho, foram criados os frameworks de desenvolvimento, que fornecem vários serviços básicos para serem reutilizados pela aplicação, de forma que esta não precise reimplementá-los. (obs.: framework poderia ser traduzido como arcabouço)

A segurança de um aplicativo é um dos aspectos para os quais os frameworks possuem um conjunto de serviços para oferecer ao desenvolvedor. Isso é muito importante, pois não é todo programador que sabe como lidar com aspectos de segurança de uma forma adequada. Gerenciamento do banco de dados é outro serviço comumente oferecidos por frameworks para desenvolvimento web. Enfim, eles oferecem um ferramental bem interessante para que o desenvolvedor de uma aplicação web se preocupe principalmente com as funcionalidades e com a lógica de negócio do seu aplicativo, deixando um pouco “de lado” alguns aspectos que ficam sob responsabilidade do framework.

Alguns dos principais frameworks para desenvolvimento web em Python são:

O que nós vamos utilizar neste post não é apenas um framework, mas sim um conjunto completo para desenvolvimento, implantação e execução de aplicativos web, fornecido pela Google: o Google App Engine. Neste post, iremos apresentar o desenvolvimento de um aplicativozinho web que retorna alguma frase famosa para o usuário, algo como a frase do dia. Mas antes disso, vamos ver do que se trata o Google App Engine.

O Google App Engine

gaelogo

O Google App Engine (GAE) é uma plataforma para desenvolvimento de aplicativos web para serem hospedados na infraestrutura da Google. Além de oferecer uma interface bem interessante para gerenciamento dos aplicativos web (veja na figura abaixo), o GAE fornece de lambuja o balanceamento de carga da aplicação, espalhando a execução dela por vários servidores se assim for necessário, e alocando automaticamente mais recursos para a aplicação que estiver rodando nessa infraestrutura. Além da disponibilizar e gerenciar a infraestrura para o desenvolvedor, o GAE ainda provê uma série de facilidades para o desenvolvimento, como um framework para persistência de dados, para tratamento de requisições, para caching de dados, dentre outras coisas legais. E, pra ficar mais interessante ainda, é gratuito para quem quiser testar ou desenvolver aplicativos sem maiores pretensões.

http.5.1

Painel de controle do GAE

Bom, chega de propaganda e vamos ao que interessa!

Instalando e configurando o GAE

Como já foi comentado, a hospedagem de aplicativos escritos para o GAE fica por conta da Google, mas para podermos testar localmente nosso app, é preciso que instalemos um ambiente próprio para isso. Siga os passos abaixo:

  1. Baixe o arquivo correspondente à sua plataforma clicando aqui;
  2. Descompacte o arquivo acima no diretório de sua preferência;

Mais informações sobre a instalação do ambiente podem ser encontradas aqui.

Desenvolvendo nosso app

Vamos começar agora o desenvolvimento de nosso aplicativo de frase do dia. A primeira coisa a fazer é criar um diretório onde nosso app ficará localizado. Podemos chamar tal diretório de frasedodia, ou o nome que você achar mais conveniente. Dentro do diretório recém criado, crie um arquivo chamado frasedodia.py e outro chamado app.yaml. O primeiro é a nossa aplicação em si e o último é o arquivo que irá conter as configurações do nosso projeto.
A estrutura do nosso projeto ficará assim:

frasedodia/
  frasedodia.py
  app.yaml

Agora, precisamos escrever as configurações do nosso projeto. Para isso, cole o seguinte conteúdo dentro do arquivo app.yaml:

application: frasedodia
version: 1
runtime: python
api_version: 1

handlers:
- url: /.*
  script: frasedodia.py

O mais importante a entender neste momento é a opção handlers. Dentro dela, temos um item chamado url com valor /.* e um atributo script com o nome do nosso arquivo .py como valor. Essa configuração significa que requisições para qualquer recurso dentro do projeto (/.*) serão encaminhadas para o arquivo frasedodia.py. Se por acaso quiséssemos que somente as requisições para os recursos contidos em uma pasta app fossem encaminhadas ao arquivo handlers.py, faríamos o seguinte:

handlers:
- url: /app/.*
  script: handlers.py

Assim, uma requisição para frasedodia.appspot.com/app/qualquercoisa seria encaminhada para o script definido na configuração acima (handlers.py). Agora vamos nos concentrar no código que irá atender às requisições do usuário.

Manipulador de requisições

Se quisermos tomar proveito das vantagens que o GAE nos fornece, é interessante que não usemos CGI. Vamos utilizar um framework para web bem simples chamado webapp2 que já é fornecido juntamente com o GAE.

O primeiro passo que devemos realizar é definir quais classes terão suas instâncias responsáveis por manipular requisições para determinadas URLs. Uma vez que já definimos que todas as requisições para o aplicativo serão direcionadas a frasedodia.py, devemos agora definir, dentro desse arquivo, o mapeamento de URLs para classes. Insira o código a seguir em frasedodia.py:

import webapp2
from google.appengine.ext.webapp.util import run_wsgi_app

mapeamento = [
    ('/', FraseDoDia)
]
app = webapp2.WSGIApplication(mapeamento)
run_wsgi_app(app)

No código acima, definimos que toda requisição para a raiz de nosso app será tratada por instâncias da classe FraseDoDia. Mas, a classe FraseDoDia não é uma classe qualquer. Ela deve obrigatoriamente estender a classe webapp2.RequestHandler, para que suas instâncias sejam também instâncias de RequestHandler. Nosso app irá criar uma instância da classe FraseDoDia e irá chamar nessa instância o método apropriado para tratar a requisição (get() para o caso de requisição GET ou post() para o caso de requisição POST). Esse método irá tratar a requisição e devolver uma resposta ao cliente. Tudo isso é feito automagicamente pelo framework de suporte, ficando ao nosso cargo apenas criar as classes que irão ser responsáveis por tratar as requisições.

Objetos do tipo RequestHandler possuem dois atributos muito importantes para o desenvolvedor:

  • self.request: é uma instância de Request, contendo a requisição recebida do usuário;
  • self.response: é uma instância de Response, contendo a mensagem a ser enviada como resposta à requisição do usuário.

Dessa forma, instâncias da classe RequestHandler devem fazer o seguinte, a cada requisição recebida:

  1. Tratar os dados recebidos através do objeto self.request;
  2. Gravar os dados a serem enviados ao usuário no objeto self.response.

Assim, devemos então implementar nossa classe FraseDoDia como uma subclasse de RequestHandler e nela implementar o método get() para retornar a frase para o cliente. Vamos então adicionar o código da classe ao nosso arquivo frasedodia.py:

import webapp2
from google.appengine.ext.webapp.util import run_wsgi_app

class FraseDoDia(webapp2.RequestHandler):

    def get(self):
        self.response.headers['Content-Type'] = 'text/json'
        self.response.out.write('{"frase": "Uma frase qualquer!"}')

mapeamento = [
    ('/', FraseDoDia)
]
app = webapp2.WSGIApplication(mapeamento)
run_wsgi_app(app)

Vendo o código acima, dá pra entender que quando ocorre uma requisição GET para o recurso / de nossa aplicação, um objeto do tipo FraseDoDia será designado pelo framework de suporte para tratar tal requisição, executando o método get(). Esse método, por sua vez, faz duas coisas:

  1. Adiciona ao cabeçalho da resposta HTTP — self.response.headers — o tipo do conteúdo a ser enviado como resposta ao cliente (text/json), de forma que o navegador saiba o que fazer com o conteúdo recebido;
  2. Escreve no corpo da resposta HTTP — self.response — o conteúdo a ser enviado ao cliente, que são dados representados em formato JSON.

Tudo o que precisamos fazer é implementar a classe que vai tratar das requisições à determinadas URLs, sem a necessidade de chamá-las nem nada. Quem faz isso é o ambiente de suporte provido pelo framework webapp.

Tendo implementado uma versão básica de nosso serviço, vamos colocar nosso ambiente de testes em funcionamento.

Executando o ambiente de testes

Vá até o local onde você extraiu o ambiente do GAE em sua máquina. Dentro dessa pasta, execute o seguinte comando:

./dev_appserver.py /caminho/para/o/projeto/frasedodia/

O caminho mostrado acima, passado como argumento para o programa dev_appserver.py, é referente ao diretório onde criamos os arquivos app.yaml e frasedodia.py.

O comando acima iniciou o servidor local para desenvolvimento e testes na porta 8080. Podemos acessar o serviço através da URL: http://localhost:8080/. Ao acessar essa URL, você terá como resposta o conteúdo JSON retornado pelo nosso serviço Web:

{"frase": "Uma frase qualquer!"}

Por enquanto estamos retornando apenas uma frase constante, e a idéia do serviço é retornar uma frase aleatória. Para tanto, temos algumas opções:

  • Manter algumas strings em memória em uma lista;
  • Manter registros no banco de dados e buscar um ao receber uma requisição.

Por fins de simplicidade, vamos seguir a primeira opção. Vamos adicionar uma nova classe chamada FraseAleatoriaDoDia, implementar o método get(), já que essa classe vai estender RequestHandler, e adicionar a nova classe no mapeamento de URLs, relacionado a URL /random. Veja o código completo abaixo:

import random
import webapp2
from google.appengine.ext.webapp.util import run_wsgi_app

class FraseDoDia(webapp2.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/json'
        self.response.out.write('{"frase": "Uma frase qualquer!"}')

class FraseAleatoriaDoDia(webapp2.RequestHandler):
    frases = [
        ('Insanity: doing the same thing over and over again and expecting different results', 'Albert Einstein'),
        ('The world is a dangerous place to live; not because of the people who are evil, but because of the people who don\'t do anything about it.', 'Albert Einstein'),
        ('A person who never made a mistake never tried anything new.', 'Albert Einstein'),
        ('Love all, trust a few, do wrong to none.', 'William Shakespeare'),
        ('A fool thinks himself to be wise, but a wise man knows himself to be a fool.', 'William Shakespeare'),
        ('Darkness cannot drive out darkness; only light can do that. Hate cannot drive out hate; only love can do that.', 'Martin Luther King, Jr.')
    ]

    def get(self):
        self.response.headers['Content-Type'] = 'text/json'
        i = random.randint(0, len(self.frases)-1)
        self.response.out.write('{"frase": "%s", "autor": "%s"}' % (self.frases[i][0], self.frases[i][1]))

mapeamento = [
    ('/', FraseDoDia),
    ('/random', FraseAleatoriaDoDia),
]
app = webapp2.WSGIApplication(mapeamento)
run_wsgi_app(app)

Rode o servidor de aplicação local com./dev_appserver.py /caminho/para/o/projeto/frasedodia/ e acesse http://localhost:8080/random para obter uma das frases.

Com o app funcionando, agora você pode registrar e fazer upload do mesmo para os servidores da Google, se assim quiser. Se desejar colocar em produção o app que implementamos aqui, siga as instruções contidas na documentação oficial, na seção que trata sobre o upload de um app.

Depois de fazer o upload de seu app, você poderá acessá-lo através de uma URL dentro de .appspot.com, como: http://id_da_aplicacao.appspot.com. Para ver informações sobre a sua aplicação, você pode acessar o painel de controle da sua conta no GAE através do endereço: appengine.google.com/.

O Google App Engine é uma ótima opção para dar suporte a uma aplicação web, visto que com ele eliminamos a necessidade de contratar um plano de hospedagem, de gerenciar o servidor web, de cuidar do balanceamento de carga, etc. Vale a pena dar uma estudada mais a fundo no assunto. 🙂

Aprenda mais

6 comentários sobre “Desenvolvendo com Python e Google App Engine

  1. Pingback: Programming Google App Engine | WWW.MINFOWORDS.COM
  2. Pingback: Tratando dados de formulários com Google App Engine | Python Help
  3. Pingback: Google App Engine e Datastore | Python Help
  4. Pingback: Templates de páginas com Python e Google App Engine | Python Help
  5. Pingback: Um blog com Google App Engine | Python Help
  6. Pingback: Web2Py – Links utéis | Cássio S. S. Santos's Blog

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s