O App Engine gerencia automaticamente as instâncias de sua aplicação. Uma instância é um servidor web que é inicializado com as configurações e com o código de sua aplicação. Ele permite que você produza conteúdo dinâmico, por meio de frameworks compatíveis com o padrão WSGI do Python.
Nem todo o conteúdo de sua aplicação muda frequentemente. Arquivos de imagem, como logomarcas ou botões, arquivos de script e folhas de estilo CSS, são bons exemplos de recursos que não são alterados com frequência.
A infra-estrutura do Google App Engine permite que você disponibilize arquivos estáticos utilizando servidores dedicados a esta tarefa. Esses servidores são projetados para otimizar a entrega do conteúdo, utilizando diferentes níveis de cache.
O App Engine trata todos os arquivos que estão dentro da pasta de seu projeto como arquivos disponíveis para sua aplicação, mas os arquivos não são servidos como estáticos.
Isso significa que uma imagem
que estiver no caminho ola-mundo/imagens/logo.png
,
por exemplo, não estará visível se você tentar
acessá-la pelo URL http://localhost/imagens/logo.png.
Para utilizar esta infra-estrutura de arquivos estáticos,
nós configuramos um novo handler no arquivo app.yaml
,
como o arquivo abaixo:
handlers:
- url: /imagens
static_dir: imagens
- url: /.*
script: main.application
Na configuração acima, estamos definindo que
que todos os arquivos dentro da pasta imagens,
devem ficar disponíveis para qualquer URL que começar com
/imagens
.
Com a configuração acima, o App Engine vai utilizar os servidores de arquivos estáticos dedicados, sem que nossa aplicação seja cobrada pelo processamento para servir este conteúdo. Neste caso, apenas pagamos pelo volume trafegado. O tempo de vida do cache dos arquivos é definido por padrão para 10 minutos.
Como vimos no nosso olá mundo,
podemos produzir conteúdo dinamicamente
em resposta a uma requisição.
Fazemos isso por meio de RequestHandlers
,
que configuramos em nosso aplicativo WSGI
.
O acesso ao conteúdo dinâmico é realizado conforme
as regras definidas em dois parâmetros.
No arquivo app.yaml
definimos qual o arquivo de script
que vai processar nosso conteúdo.
Em nosso "olá mundo", utilizamos o script main.application
para responder por todas as requisições.
Dentro do script main.py
, nós direcionamos quais os
RequestHandlers são responsáveis por cada caminho.
Em nosso olá mundo, nós utilizamos apenas um caminho,
a raiz da aplicação ("/").
Nos dois locais, podemos utilizar expressões regulares para mapear scripts e RequestHandlers para diferentes caminhos. Expressões regulares são formas de descrever diferentes possibilidades de combinações de texto, utilizando alguns caracteres especiais.
Vamos utilizar os recursos de conteúdo estático e dinâmico do Google App Engine para desenvolver um pequeno website.
O website que iremos desenvolver terá como base um template, inicialmente estático, e um formulário de contato implementado utilizando o serviço de e-mails do Google App Engine.
Nosso website será baseado em um template que podemos obter do site Start Bootstrap (http://s.ronoaldo.net/start-bs). Neste site, você encontrará diversos modelos que foram desenvolvidos utilizando o Bootstrap (http://getbootstrap.com/), que é um kit de desenvolvimento de interfaces produzido pela equipe do Twitter.
Para nosso exemplo, vamos utilizar o template Business Casual (http://s.ronoaldo.net/template-business). Esse template possui todas as páginas necessárias para nosso objetivo.
Como todo conteúdo de nosso site será inicialmente estático,
vamos extrair o conteúdo do arquivo de template
para uma nova pasta, chamada static
e configurar
os mapeamentos deste conteúdo para ser servido.
mkdir -p ~/workspace/ola-mundo/static
wget http://s.ronoaldo.net/template-business -O ~/template.zip
cd ~/workspace/ola-mundo/ ; unzip ~/template.zip
static
.
No nitrous, você pode executar o comando: mv startbootstrap-business-casual-1.0.0/* static
rmdir startbootstrap-business-casual-1.0.0
Você deve estar com o seguinte layout de projeto:
ola-mundo/
|--app.yaml
|--main.py
|--static/
|--css/
|--fonts/
|--img/
|--js/
|--LICENSE
|--README.md
|--about.html
|--blog.html
|--contact.html
|--index.html
Vamos agora mapear todo o conteúdo
da pasta estática para ser servido pelo App Engine.
Edite o arquivo app.yaml
e configure um novo handler
antes do handler de script:
- url: /static
static_dir: static
Ao acessar o endereço de preview de nossa aplicação em http://localhost:8080/static/index.html, você deve visualizar o site com o template já em funcionamento.
Para exemplificar a flexibilidade do mapeamento de arquivos estáticos, vamos utilizar expressões regulares para disponbilizar nossos arquivos html e as pasta css, fonts, img e js à partir da raiz da aplicação. Vamos substituir os handlers anteriores pelos seguintes:
- url: /
static_files: static/index.html
upload: static/index.html
- url: /(.*\.html)$
static_files: static/\1
upload: static/.*\.html$
- url: /css
static_dir: static/css
- url: /fonts
static_dir: static/fonts
- url: /img
static_dir: static/img
- url: /js
static_dir: static/js
- url: /.*
script: main.application
O primeiro handler mapeia a raiz da aplicação /
para o arquivo static/index.html
.
O segundo handler utiliza o poder de expressões regulares
para capturar qualquer requisição de arquivo terminado por '.html',
e o mapeia para o arquivo equivalente na pasta estática.
Esses handlers diferem-se dos demais por serem um mapeamento de arquivos e não de diretórios. Portanto precisamos informar também o parâmetro upload, que indica qual arquivo corresponde à cada mapeamento.
Os demais handlers apenas mapeiam as pastas estáticas que possuem imagens, folhas de estilo e scripts como diretórios estáticos, mas disponíveis à partir da raiz, como fizemos anteriormente.
Com estas modificações, o nosso site agora está disponível para ser servido à partir da raiz da aplicação, utilizando a infra-estrutura de recursos estáticos do Google App Engine, e o recurso de cache que otimiza o carregamento das páginas.
Para concluir nosso exemplo, vamos transformar
o template do formulário de contato
em um formulário que realmente processe a requisição do usuário.
Para isso, iremos primeiro ajustar o conteúdo do template contact.html
com as seguintes alterações:
form
e inclua dois atributos: <form role="form" method="post" action="/contato">
input
deste formulário,
e inclua o atribut name
nas mesmas, com os valores:name="name"
para o campo Namename="email"
para o campo Email Addressname="phone"
para o campo Phone Numbername="message"
para o campo MessageVamos agora implementar o tratamento do nosso formulário de contato, utilizando um RequestHandler e o serviço de envio de e-mails do App Engine. Abra o arquivo main.py e substitua nosso olá mundo pelo o seguinte código:
import webapp2
from google.appengine.api import mail, app_identity
class Contato(webapp2.RequestHandler):
def post(self):
name = self.request.get("name")
email = self.request.get("email")
phone = self.request.get("phone")
message = self.request.get("message")
noreply = "no-reply@%s.appspotmail.com" %\
app_identity.get_application_id()
body="""Prezado %s,
Obrigado pelo seu contato.
Em breve retornamos.
Mensagem recebida:
%s
--
www.orangeinstitute.com.br""" % (name, message)
mail.send_mail(sender=noreply,
to=email,
subject="Obrigado pelo contato",
body=body)
self.response.write('Email enviado com sucesso!')
application = webapp2.WSGIApplication([
('/contato', Contato)
], debug=True)
No código acima, estamos utilizando duas APIs do App Engine.
A primeira permite que nosso código identifique o ID da aplicação
que está em execução.
A segunda, é o serviço de e-mails (mail
), que permite enviar mensagens.
Como remetente, o App Engine permite que você utilize alguns endereços:
appspotmail.com
,
que contenha o seu ID de aplicação.No código acima, utilizamos as duas APIs em conjunto para produzir um código resiliente que pode ser executado em ambiente local ou de produção.
Para fazer o teste de envio do formulário, basta acessar a página no preview em http://localhost:8080/contact.html. Prencha o formulário e clique no botão "Submit".
O browser deverá mostrar a mensagem de sucesso, como escrevemos esta mensagem na resposta. No terminal onde o servidor de desenvolvimento está em execução, você poderá visualizar o log do POST para '/contato', que contém os parâmetros utilizados para o envio. O servidor de desenvolvimento não envia os e-mails, apenas exibe a informação de log.
Concluímos com isso nosso website, que está agora funcional e pronto para o ambiente de produção.