Tutorial de AngularJS y Google App Engine en Español (Parte I)
Hasta ahora hemos visto: Introducción
Bienvenidos a mi nueva serie de tutoriales: Aprendiendo AngularJS y Google App Engine. El objetivo de esta serie es enseñar al lector (a lo largo de diferentes posts) Todo lo que necesita saber para iniciarse en el mundo del desarrollo web con las últimas tecnologías utilizando la infraestructura gratuita y altamente escalable de Google. No importa si apenas vas empezando o ya eres un desarrollador avanzado, todos aprenderán algo aquí. Trabajaremos con tecnologías como HTML/CSS/Coffeescript/jQuery/Python y algunas otras más, tocando temas como Bootstrap 3 y por supuesto, mucho de AngularJS. Entendimiento básico de las tecnologías antes mencionadas es recomendable pero no obligatorio.
Hoy veremos: Estructura, MVC + REST
NOTA: No copies y pegues los snippets de código desde aquí, usa su enlace en Gist (abajo de cada bloque) para ello.
El objetivo que esta primera parte tiene es el de enseñarles cómo estructurar un proyecto en Google App Engine para trabajar cómodamente. Una de las ventajas que tiene GAE es su flexibilidad, el hecho de poder utilizar cualquier tipo de acomodo que te venga a bien en tus directorios y archivos para trabajar mientras tu descriptor (app.yaml) esté en orden... Pero el hecho de poder hacer las cosas como queramos no quiere decir que no debamos seguir algún tipo de orden, ¿verdad? Para esta serie de tutoriales, la aplicación que crearemos se basará en la arquitectura MVC (Model-View-Controller) y el principio REST. Conforme avancemos en el tutorial, notarán que esta app estará fuertemente influenciada por la "Manera Rails" de hacer las cosas, puesto que yo trabajo principalmente en Ruby On Rails. Y bueno, a todo esto...
¿Qué es el MVC y Qué es REST?
El MVC es un patrón de arquitectura que se utiliza en la construcción de aplicaciones web. Se basa en 3 componentes básicos: Modelos, Vistas y Controladores. Un Modelo es un archivo/script que precisamente "modela" (Es decir, define en código, o describe pues) los entes/objetos que manejaremos en nuestra base de datos. En el caso de la app en turno manejaremos proyectos que pueden tener un nombre, una imagen, una descripción, un autor y una URL. El archivo de Modelos tiene como nombre "models.py" y se ve así:
from google.appengine.ext import ndb
class Project(ndb.Model):
name = ndb.StringProperty(indexed=False)
img_url = ndb.StringProperty(indexed=False)
description = ndb.StringProperty(indexed=False)
author = ndb.StringProperty(indexed=False)
url = ndb.StringProperty(indexed=False)
Código en: https://gist.github.com/Jmlevick/a3bae23111fc2e02353e
Nótese que ninguno de los campos está siendo indexado. Indexar alguna propiedad del modelo hace que la búsqueda de objetos en nuestra base de datos (basándonos en el atributo indexado) Nos suelte un resultado casi de inmediato sin importar el número de records en la DB. En este caso no indexaremos puesto que no es necesario para la app que vamos a hacer. Los índices pueden ser buenos para acelerar las lecturas a la base de datos pero alentan las escrituras y ocupan más espacio en disco/memoria (según dónde los almacenes), tema para otra ocasión.
Una Vista es lo que el usuario ve en la aplicación. Son las páginas que le mostramos al acceder a la app e interactuar en ella. En las vistas creamos toda la UI y UX con respecto a lo que vamos a desarrollar. Pueden llevar código HTML, CSS, Javascript y también algún lenguaje embedido (Como Python/Ruby/PHP) según el framework que estés usando. En el caso de nuestro proyecto de ejemplo, las vistas pueden llevar código python embedido a través de un lenguaje de plantillas que veremos después. De momento tenemos algunas vistas pero no tienen código para mostrar en esta etapa del tutorial, son archivos HTML vacíos.
Un Controlador es "el pegamento" que une a los otros 2 atributos del MVC (por describirlo de alguna manera). Es básicamente un archivo que le indica a la aplicación cómo ha de responder a una request del usuario (Qué debe pasar si entran a la página principal, qué pasa si quieren entrar a la página individual de un objeto etc). En App Engine los controladores son llamados "handlers" y están escritos en Python, además de que también conllevan otra funcionalidad y es la del routing, (el describir las URL's accesibles de la aplicación y cómo responder a ellas cuando la gente accesa) con un poco de ayuda del app.yaml (más adelante veremos este archivo a fondo). Para esta parte de nuestro tutorial, el archivo de controlador (main.py) sólo lleva estas líneas:
import os
import jinja2
import webapp2
from models.models import *
Código en: https://gist.github.com/Jmlevick/2758c8bb8ff5b1fd291e
Luego ahondaremos en el código completo que terminará teniendo.
Terminamos con el MVC. Ahora pasemos a REST. En cuanto a REST, se trata de un principio de creación de aplicaciones web que sostiene que toda aplicación se puede "construir" (por no encontrar una palabra más adecuada) sobre algunas acciones básicas cuyos nombres y definiciones varían según frameworks, pero por ejemplo en Rails (lo explicaré así porque en este tutorial usaremos ese arquetipo) tenemos las acciones Index, Show, New, Create, Edit, Update y Destroy. Cuyas funcionalidades respetan los principios de REST al permitir lo siguiente:
Index: Da acceso a todos los entes guardados en la base de datos
Show: Da acceso a un ente específico
New: Permite crear un nuevo objeto
Create: Es lo que sucede entre que creas el objeto y se guarda en la base de datos (por explicarlo de alguna manera)
Edit: Permite editar un Objeto existente
Update: Es lo que sucede entre que editas un objeto existente y se guarda en la base de datos con los nuevos atributos (por explicarlo de alguna manera).
Destroy: Permite destruir un objeto.
Cada una de estas acciones son descritas con métodos/funciones en el controlador de una aplicación y tienen una ruta propia que permite el acceso desde el navegador además de una vista (Cuya existencia es nula en las acciones de Create, Update y Destroy, pues no se necesita en realidad para éstas). Además podemos omitir vistas de acciones con las que el usuario no interactúa directamente o bien, que no responden a requests HTTP.
Estructurando el proyecto
Ya que entiendes éstas bases que usaremos, es momento de trabajar un poco y el día de hoy estructuraremos el proyecto que vamos a crear. Para empezar, dentro de la carpeta google_appengine que se genera tras instalar el SDK de Python en tu computadora (o bien extraerlo según tu plataforma) Crearemos una carpeta vacía llamada "portfolio". Dentro de esta carpeta hemos de crear la siguiente estructura de archivos y carpetas:
portfolio
├── app.yaml
├── index.yaml
├── main.py
├── models
├── __init__.py
└── models.py
├── static
├── css
├── img
├── js
└── src
└── views
├── edit.html
├── index.html
├── new.html
└── show.html
Entiéndase que todo lo que no tiene extensión es una carpeta y lo que sí, es un archivo. Terminamos así entonces con 7 directorios y 9 archivos anidados de la manera en que se muestra en el diagrama de arriba. Ahora, a explicar qué es cada cosa (y/o qué contiene):
Es un archivo descriptor de la aplicación. Le describe la aplicación a App Engine, delimita algunas rutas y define librerías a utilizar. Es el corazón central de tu app, su archivo de configuración. Ha de contener el siguiente código:
application: myPortfolio
version: 1
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /.*
script: main.application
secure: optional
- url: /new
script: main.application
login: admin
secure: optional
- url: /edit
script: main.application
login: admin
secure: optional
- url: /css
static_dir: static/css
- url: /img
static_dir: static/img
- url: /js
static_dir: static/js
- url: /favicon\.ico
static_files: static/favicon.ico
upload: static/favicon\.ico
libraries:
- name: webapp2
version: latest
- name: jinja2
version: latest
Código en: https://gist.github.com/Jmlevick/734634a8d437fe94bb3a
De aquí únicamente cambiaremos "myPortfolio" por el nombre de tu app, mismo que eliges al crearla en el dashboard de http://appengine.google.com. el parámetro de Version es la versión de tu app, Runtime el entorno a usar (en este caso Python 2.7) Api es la versión del API de App Engine más reciente para ese entorno (que es la 1 de momento). Y el parámetro Threadsafe habilita la capacidad de tu aplicación para procesar varias requests al mismo tiempo, por default lo recomendado es usar "true". Toda la sección de Handlers es puro routing, decimos qué URL's se pueden accesar y qué archivo de controlador las manejará, en nuestro caso sólo tenemos 1 archivo de controlador (main.py) que está en la raíz del proyecto y como vamos a usar webapp2 (el framework predeterminado de app engine) en lugar de poner "main.py" en el parámetro de "script" de nuestras rutas tenemos que poner main.application para referenciar dicho controlador; Hay otras opciones que verás, como "secure" o "login" y también notarás que la primera ruta tiene un comodín, lo que significa que cualquier request que se haga a la aplicación desde la raíz en adelante (http://myapp.appspot.com/loquesea) ha de procesarse con el mismo script de controlador. Si no necesitásemos restringir el acceso a ciertas URL's (como las que permiten crear y destruir objetos en la DB) bastaría con este primer handler, pero como no es el caso tenemos que definir los demás con la opción "login:admin" para que solo los administradores de la app tengan acceso a esas URL's y por ende, a sus funciones (Luego ahondaremos en esto). "secure" simplemente habilita o deshabilita el HTTPS en la aplicación, yo uso el parámetro "optional" para que la gente pueda usar HTTPS si quiere o HTTP normal, no forzando ni una ni otra opción. Otra opción que se ve ahí es "static_dir" y básicamente dice qué directorio dentro de la aplicación contiene "las respuestas" (archivos) a una request de determinada URL para assets (CSS, JS, etc).
El último handler simplemente sube el favicon a app engine y le dice dónde se encuentra y a qué URL responde.
En cuanto a las librerías, tenemos 2: webapp2 (Framework web de app engine) y jinja2, un motor de plantillas. Se pueden definir versiones específicas o usar siempre la más actualizada con "lastest" (como se ve en nuestro archivo app.yaml de arriba). Más adelante ahondaremos en éstas 2 librerías conforme construyamos la app. Pueden leer más sobre el app.yaml y todo lo que se puede hacer/definir con él por acá.
Este archivo tiene este código:
# This index.yaml is automatically updated whenever the dev_appserver
# detects that a new type of query is run. If you want to manage the
# index.yaml file manually, remove the above marker line (the line
# saying "# AUTOGENERATED"). If you want to manage some indexes
# manually, move them above the marker line. The index.yaml file is
# automatically uploaded to the admin console when you next deploy
# your application using appcfg.py.
Código en: https://gist.github.com/Jmlevick/efb81a1381e3227d66de
Y pues se podría decir que "va vacío". Lo único importante son las primeras 2 líneas (indexes y AUTOGENERATED) Que permiten reconocerlo a app engine y cambiarlo al vuelo para generar índices en la base de datos cuando los estamos ocupando.
Este es el controlador de nuestra aplicación, ya hablamos de él arriba, sus funciones/propósito y mostramos el código que tiene hasta el momento.
Contiene 2 cosas: un archivo de inicialización y el archivo de modelo que mostramos arriba. Sirve para organizar todo lo referente a modelación de bases de datos (obviamente) dentro de la aplicación, sus archivos:
Va vacío, sólo sirve para que un programa python pueda reconocer esta carpeta como un módulo e importar scripts que tenga adentro a voluntad del usuario.
Sirve para modelar los entes de nuestra aplicación, ya explicamos arriba este archivo y mostramos su código... En una aplicación más grande, lo ideal es crear un archivo de modelo por cada ente dentro de la app y meterlo a nuestra carpeta de models.
Contene todas las carpetas de assets de la aplicación (css, js, img, y en este caso src), sus carpetas:
Contiene todas las hojas de estilo de nuestra app
Contendrá todos los javascript que nuestra app lleve
Contiene todas las imágenes que se necesiten en la aplicación
Es una carpeta que contendrá archivos .coffee de coffeescript, Toda la app la escribiremos en coffeescript (la parte de Angular pues) y lo compilaremos en automático al directiorio JS, de donde se jalarán los scripts para levantar la app en producción.
Contiene las vistas de nuestra aplicación (de momento archivos HTML vacíos), sus archivos:
Sirve para que el usuario vea todos los proyectos en nuestro portafolio
Sirve para que el usuario vea los detalles individuales de 1 solo proyecto en el portafolio
Sirve para crear nuevos proyectos y añadirlos al portafolio
Sirve para editar los atributos de proyectos ya existentes en el portafolio.
En el video a continuación, puedes ver cómo queda la estructura de directorios (y los archivos) para esta primera etapa del tutorial, por si te quedó duda o te confundiste con algo:
Y con esto acabamos esta primera parte. No olviden suscribirse al RSS del blog para estar al tanto de cuándo se publican nuevas partes del tutorial:
Y para poder contestar dudas más rápido y eso, les recomiendo también seguirme en twitter y mandarme menciones.
P.D. Aquí es un buen momento para usar Git en tu App, a esta rama yo la llamo "01structure" en mi app de ejemplo ;)
¿Te gustó el artículo? - Twittear Ahora