Arquitectura REST. Qué es y para qué sirve

Photo by Pankaj Patel on Unsplash

Si has llegado hasta aquí es porque quieres aprender un poco sobre esta arquitectura y probablemente tengas pocas nociones sobre esto. De lo contrario, te recomiendo que no sigas leyendo. Es un artículo para principiantes.

El problema con las API

Llegó el año 2000, y empezaron a verse de forma clara las ventajas de los Web Services para la comunicación entre sistemas. Entre aplicaciones web. Cliente-Servidor. En aquel entonces no existía ningún estándar sobre cómo diseñar una API. Se implementaban usando otros protocolos como SOAP. Difíciles de implementar. Pesados. Más complejos en todos los aspectos.

Entonces, un grupo de expertos liderado por Roy Fielding, creó la llamada arquitectura REST. Esto cambió por completo el desarrollo de servicios web hasta la fecha.

REpresentational State Transfer

Esto es lo que significan sus siglas. Se trata de una arquitectura para estandarizar comunicaciones web entre sistemas, logrando que se entiendan mucho mejor entre ellos. A los servicios que cumplen con este diseño se les llama servicios RESTful.

Cliente y Servidor

El servidor expone la API para que el cliente haga uso de ella. Por ejemplo, los servidores de Twitter o Instagram nos facilitan el formato de sus API y nosotros, desde una aplicación web o móvil, accedemos a las mismas para leer o incluso modificar información.

El cliente hace una petición, y el servidor envía una respuesta.

Una de las ventajas de REST es que cliente y servidor no tienen porqué depender del mismo código para entenderse intercambiando mensajes. El servidor puede actualizarse y cambiar, sin que el cliente tenga que hacerlo. Y al revés. Mientras no cambie el formato de los mensajes, no hay problema.

Sistemas Stateless (sin estado)

Antes que nada es importante saber qué significa que un sistema no tenga estado. En una arquitectura REST, cuando se comunican servidor con cliente, estos no necesitan saber en qué estado se encuentra cada uno. Entienden igualmente el mensaje. Ambos pueden entenderlo sin tener en cuenta los anteriores. La base de la arquitectura REST define una interacción orientada a recursos.

Estructura de las comunicaciones

La arquitectura REST se basa en que el cliente envía peticiones para recuperar o modificar recursos, y el servidor responde con el resultado, que puede ser con los datos que hemos pedido o el estado de la petición.

Una petición está formada por:

  • Un verbo HTTP que define la operación a realizar.
  • Una cabecera o header que incluye información sobre la petición.
  • Una ruta o path hacia un recurso.
  • El cuerpo del mensaje o body con los datos de la petición.

Verbos HTTP

Existen 4 verbos principales que forman parte de las peticiones HTTP para interactuar con una API REST, estos son:

  • GET
    Para recuperar información sobre un recurso específico.
  • POST
    Para crear un nuevo recurso.
  • PUT
    Actualizar un recurso
  • DELETE
    Eliminar un recurso

Por ejemplo, en el caso de una API sobre películas.

GET: Consulta y lee información sobre películas.
“/movies” nos permite acceder a todas ellas
“/movies/419” accedemos a la película con ID 419

GET https://www.domain.com/movies/419
Respuesta:
Status Code - 200 (OK)
{
"id": 419,
"title": "Eraserhead",
"year": "1977"
}

POST: Crea una nueva película
“/movies”

POST https://www.domain.com/movies
Respuesta:
Status Code - 201 (CREATED)
{
"movie": {
"id": 419,
"title": "Eraserhead",
"year": "1977"
}
}

PUT: Actualiza los datos de una película
“/movies/419” Actualizamos los datos de la película con id: 419

PUT https://www.domain.com/movies/419
Respuesta:
Status Code - 200 (OK)

DELETE: Elimina una película
“/movies/419” Elimina la película con id: 419

DELETE https://www.domain.com/movies/419
Respuesta:
Status Code - 204 (NO CONTENT)

Con esto deberíamos ofrecer las 4 funciones básicas de un modelo de datos. También conocidas con las siglas CRUD. Crear (Create), Leer (Read), Actualizar (Update) y Eliminar (Delete).

Cabeceras (headers) y parámetros Accept

A lo que he explicado le falta un detalle. Las cabeceras a incluir en las peticiones. El cliente debe enviar un tipo de contenido que el servidor sea capaz de entender. Para esto sirve el campo Accept. Se asegura que el servidor no enviará contenido que el cliente no pueda interpretar. Las opciones a enviar son MIME Types. Estos se utilizan para identificar los tipos de contenido del campo Accept. Consisten en un tipo y un subtipo.

Un tipo puede ser “image”, y un subtipo “image/jpeg”. O bien “text/css” para contenido de estilos CSS o “text/plain” para texto plano.

Algunos ejemplos más:

image — image/png, image/jpeg, image/gif
audio — audio/wav, image/mpeg
video — video/mp4, video/ogg
application — application/json, application/pdf, application/xml, application/octet-stream

Por ejemplo, un cliente que quiera acceder al contenido de una película, podría enviar una petición como esta:

GET /movies/885
Accept: text/html, application/xhtml

Respuestas del servidor

Cuando termina la operación de la API en el servidor, este nos enviará el resultado junto con una serie de datos para que podamos interpretar el éxito o no de la operación y el tipo de datos que recibimos.

Content Types

Cuando el servidor envía un payload hacia el cliente, debe incluir una cabecera llamada content-type. Esto es para que el cliente sepa qué tipo de contenido le llega. Estos datos también son MIME Types, tal y como indicamos anteriormente. Y además, el MIME Type que nos envía el servidor debe coincidir con el que envía el cliente en la cabecera Accept.

Pongamos un ejemplo sencillo que lo explica todo mucho mejor.

Petición del cliente:

GET /movies/445 HTTP/1.1
Accept: text/html, application/xhtml

Respuesta del servidor:

HTTP/1.1 200 (OK)
Content-Type: text/html

Códigos de respuesta

Las respuestas del servidor deben contener códigos de estado para avisar al cliente del éxito o no de cada operación. Para cada verbo HTTP tenemos una serie de códigos esperados que nos indicarán la ejecución correcta de cada operación:

  • GET: Código 200 (OK)
  • POST: Cödigo 201 (CREATED)
  • PUT : Código 200 (OK)
  • DELETE : Código 204 (NO CONTENT)

Las 3 mejores dashboard admin templates gratuitas de 2020

Las 3 mejores dashboard admin templates gratuitas de 2020

He hecho un poco de investigación para encontrar buenos Dashboards estilo “Admin” para uno de mis proyectos, y los he publicado en este artículo para compartir mi lista. Son solo 3, pero son las que he elegido tras analizar más de 30 porque creo que son las mejores.

Todos los que expongo son totalmente gratuitos con licencia MIT y tienen un mínimo de actividad y seguidores que aseguran, en mayor o menor medida, su continuidad y soporte de la comunidad.

Puntos a tener en cuenta para elegir un buen dashboard

  • Continuidad y soporte. Lo que os comentaba. Por muy bonito que sea, debe tener una comunidad mínimamente activa.
  • Que use un framework de CSS conocido y actualizado. La última versión de Foundation o de Bootstrap.
  • Que esté mínimanente probado en entornos productivos.
  • Que tenga repositorio público.
  • Revisa el apartado “Issues” para comprobar que los pequeños detalles e imperfecciones se van corrigiendo.
  • Que sea modular y utilice un gestor de paquetes.

Sleek Dashboard

Uno de los que más me ha gustado. Aunque todavía está en beta, a día de hoy la última versión es del 14 de enero de 2020. Además de los típicos componentes, formularios y tablas, tiene algunas páginas personalizadas interesantes como las de Chat, Contactos, Team y Calendario.

10TFrQGtSlB1jbOT5KcmHEw

Adminator

A destacar que también tiene adaptaciones a Flask y Django

0 Vf96FmFLQmQEvNBN

AdminLTE

Uno de los más veteranos, con distintas versiones para Bootstrap 3 y Bootstrap 4. Está creada por Colorlib y tiene plantillas premium opcionales. Se actualiza constantemente (la última actualización en el momento de escribir esto es de hace apenas 11 días). Actualizan constantemente las dependencias y hay mucha actividad. A tener muy en cuenta.

Debug remoto en Django con Docker y VS Code

Con el uso de contenedores virtualizados con Docker, el proceso de debug ha cambiado un poco. Ahora debemos conectarnos a las instancias virtualizadas para poder hacer debug de nuestro código, y a veces no es tan sencillo como parece.

En este caso explicaré cómo configuro normalmente mi entorno con VS Code para hacer debug remoto para el desarrollo de mis aplicaciones Django bajo Docker.

1uFOXOycdz17QphtnBCpHfQ

VS Code ya tiene una extensión de Docker que facilita las cosas. Soporta Node.js, Python y .NET Core.

Si abrimos la pestaña de docker, ya deberíamos ver un resumen con los contenedores, imágenes y demás.

El primer paso es añadir el módulo ptvsd (Python Tools for Visual Studio debug server) en nuestro fichero requirements.txt

ptvsd == 4.3.2

La versión 5 lleva tiempo en alpha, por lo que te recomiendo mirar en el repositorio oficial.

Ahora debes modificar el fichero launch.json de VS Code con este contenido:

{
"name": "Python: Django",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/manage.py",
"console": "integratedTerminal",
"args": [
"runserver",
"0.0.0.0:8000",
],
"django": true
},

Lo siguiente es modificar el fichero manage.py para añadir las siguientes lineas:

if settings.DEBUG:    
if os.environ.get('RUN_MAIN') or os.environ.get('WERKZEUG_RUN_MAIN'):
    import ptvsd
    ptvsd.enable_attach(address = ('0.0.0.0', 3000))
    print "Attached remote debugger"

Django hace live reload de manera que actualiza cada vez que detecta cambios en el código mientras trabajamos. El segundo if es para evitar que se inicialice dos veces.

El fichero manage.py (en mi caso con Django 3) quedaría de la siguiente forma:

El siguiente paso es asegurar que tenemos abierto el puerto 3000 desde Docker. En el caso de docker-compose.yml, yo tengo:

...
services:
...
web:
ports:
- "8000:8000"
- "3000:3000"

Instala también la extensión ms-python.python

2 1

Una vez hecho esto, ya deberíamos poder lanzar la instancia con nuestra configuración de debug. Deberíamos tener el perfil Python: Django (creado en el fichero launch.json) disponible en la pestaña de debug de VSCode, y basta con darle al play para que todo arranque.

3 1

Si lo hemos hecho bien, podremos ver como aparece “Dev Container: Existing Docker Compose…” en la parte inferior, lo cual nos indica que estamos conectados al contenedor Docker a través de VSCode y tenemos todo listo para debugar. En la siguiente captura podemos ver también el print del mensaje “Attached remote debugger” que hemos puesto en el manage.py.

4 3

Ojo con Redsys y Cloudflare, revisa esto para que se registren los pagos

Muchos de nosotros, lo primero que hacemos tras registrar un dominio o cuando llega la hora de publicar una web, es activar el registro y la cuenta en Cloudflare para apuntar las DNS del mismo y aprovechar las aplicaciones y mejoras que ofrece incluso con la capa gratuita.

Pero hay que tener mucho cuidado con lo que configuramos en Cloudflare. Al actuar como proxy pudiendo ser capaz de alterar todo el código y comportamiento de la web, también es posible que alguna de las modificaciones acabe causando un problema y que, en el caso que nos ocupa, lo apliquemos a un eCommerce Magento y deje de funcionar, por ejemplo, la pasarela de pago.

1VTPv2TJp69driCClBLUdlA
Dashboard de Cloudflare

Y si, esto es lo que puede ocurrir si utilizamos la pasarela de pago Redsys y nuestro eCommerce pasa por el proxy de Cloudflare, que los pagos dejen de confirmarse.

El usuario que realiza el pago en nuestro eCommerce Magento, sale de la web para dirigirse a la pasarela de pago. Una vez introducidos los datos y confirmada la compra, Redsys nos envía un callback con los datos de confirmación de la misma para que Magento cambie el estado de la transacción.

Asegurar constantemente el correcto funcionamiento de los cambios de estado con Redsys es clave para no terminar desquiciado y con tu cliente con los cojones hinchados.

El problema es que Cloudflare bloquea las peticiones callback que envía Redsys a nuestra web y estas no se registran correctamente.

Lo que hace Cloudflare concretamente es bloquear la petición de Redsys por no superar el “Browser integrity check”. En la siguiente captura podréis ver un ejemplo real de una petición callback hacia la url: /es/redsys/index/notify

3 4

Esto hace que el eCommerce (Magento, Prestashop, WooCommerce o cualquiera) no pueda cambiar el estado del pedido y el responsable de servirlos tenga problemas para saber si el pago se ha realizado correctamente o no.

Solución? Crear una regla de Firewall

La solución pasa por crear una regla en Cloudflare para que las peticones de Redsys no pasen por su sistema de comprobación de seguridad.

Podríamos crear una regla de URL con las ‘Page Rules’ pero no podemos limitarlas por IP y eso lo hace menos seguro. Debemos crear una regla de Firewall por URL y también por ASN.

Como vemos en la captura anterior, el ASN de Redsys / Sermepa es 31627. La regla de Firewall quedaría de esta manera:

4 6

Igualmente, tras hacer este cambio, es indispensable que hagas una nueva prueba de compra para asegurar que funciona. Duda siempre de todo, incluso de este post. Aprende qué significa crear esta regla y todo lo que conlleva. Puede que me funcione a mi pero no a ti. Puede que funcione hoy y no mañana. Que cambie el ASN de Redsys. Mil cosas para que todo vuelva a fallar.

Bienvenidos al fantástimo mundo de los eCommerce 😉

Qué motor de búsqueda elegir para tu eCommerce con Magento 2

1*J3qNac EyHkdkiwNtgIpwA

He estado un tiempo estudiando y probando distintos motores de búsqueda para Magento 2 y he llegado a varias conclusiones que quiero compartir.

En primer lugar, si estás en un artículo como este es porque probablemente el buscador de Magento se te haya quedado pequeño y estás buscando una alternativa. De todas formas, Magento 2.3.1 activa Elasticsearch como buscador por defecto. ¡Será por algo!

Pues bien, esto es lo que me pasó a mi en uno de los proyectos corporativos con Magento que desarrollamos en ACTIUM Digital. Se trataba de un proyecto relativamente ambicioso y el buscador era el punto clave. Pude dedicar cierto tiempo a estudiar e incluso probar unos cuantos para decantarnos por el que mejor se adaptaba a nuestras necesidades. Si una cosa tenemos clara, es que aunque hay que ser ágil y rápido probando y descartando, escatimar en I+D genera hipoteca técnica a largo plazo.

Dedícale tiempo y cariño. Un buen buscador mejorará la conversión en tu tienda online.

En este artículo explicaré mi experiencia y las conclusiones a las que he llegado utilizando:

  • Elasticsearch
  • Doofinder
  • Algolia

¿Qué ocurre con el buscador de Magento?

El buscador que trae por defecto Magento no es más que una búsqueda a través de la base de datos MySQL. No podemos compararlo con otros buscadores, especialmente con los que comento aquí. Esto trae la ventaja de que es fácil de configurar y nos ofrece un buscador en funcionamiento out of the box. Esto es suficiente para la mayoría de eCommerce relativamente pequeños y con un catálogo de productos que no supere los pocos miles.

Ahora bien, si nuestro eCommerce crece o es un proyecto que ya sabemos desde un principio que va a ser grande (miles de productos, visitas, etc.) o que simplemente queremos que tenga un buen buscador, hay que estudiar alternativas, además de pensar en crear una arquitectura escalable en todos los aspectos.

Otras desventajas

Además de ser ahora mismo una opción oficialmente deprecada. Con el buscador de MySQL no podremos usar funcionalidades como las sugerencias, el clustering, o la configuración del peso por atributo.

El indexer de Magento

Una de las partes más importantes a tener en cuenta y a entender cómo funciona es el propio sistema de indexación del catálogo de Magento.

Magento tiene un proceso para indexar toda la información del catálogo de productos, categorías y precios. Para que las búsquedas sean rápidas, Magento debe actualizar constantemente dicho índice. Si no pasamos por este proceso, cada vez que queramos buscar información sobre un producto Magento tendrá que pasar por todo un proceso de cálculo y consultas hasta obtenerlo. Esto ocurre por ejemplo con los precios y su constante actualización.

2 2

Para actualizar todos estos datos, Magento realiza una reindexación programable. Esta reindexación permite que la base de datos esté constantemente actualizada, pero es un proceso que puede llegar a ser muy lento.

Este proceso de reindexación tiene dos modos de actuación a tener muy en cuenta. Actualizar al guardar (Update on Save) que se ejecutará cada vez que modifiquemos datos, o actualización programada (Update on Schedule) que ejecutará el proceso programado cuando nosotros queramos.

Es importante conocer las dos modalidades de indexación porque entran muy en juego en cómo se actualiza también la información en buscadores externos a Magento como Elasticsearch, Doofinder o Algolia.

Elasticsearch

La primera opción a tener en cuenta si no queremos depender de servicios externos y de pago.

3 3
Logo de Elasticsearch

Elasticsearch está basado en un modelo de negocio Open Source, así que también podemos descargarlo y instalarlo en nuestra propia infraestructura. En mi caso, creamos un servidor adicional y exclusivo para Elasticsearch y, desde Magento, conectamos a la instancia del buscador.

Basta con indicarle el host, el puerto y el prefijo del índice. Magento se encargará de enviarle la información para que elastic la tenga almacenada en su motor, y Elastic devolverá los resultados cuando el usuario haga una búsqueda. Todo de forma rápida y transparente.

4 4
Opciones de configuración de Elasticsearch en Magento 2

Aunque la mejora interna y del buscador es indiscutible respecto a la opción MySQL, la parte visual y la personalización de Elastic siguen un poco limitadas y son complejas de modificar. Una opción a tener en cuenta es utilizar plugins como Elastic Search for Magento 2 de Amasty que permite, entre otras cosas, configurar el autocompletado, utilizar sinónimos y búsqueda personalizable con atributos y el peso de los mismos.

Una de las grandes ventajas es que al tratarse de un motor de búsqueda que puedes instalar en tus servidor sin depender de otros, el precio se reduce significativamente. A cambio, tendrás que mantener el servicio, actualizarlo y quizá perder más tiempo configurándolo, pero tienes el control absoluto del mismo y no tendrás un susto en la factura si pasas de 5.000 SKU a 100 o 200.000 como era nuestro caso.

Doofinder

Se trata de un buscador inteligente, de los que puedes añadir y configurar en el Frontend en pocos minutos y con una simple llamada a un JavaScript. Ofrecen un plugin para Magento 2 que se encarga de enviar via API los productos a sus servidores para procesarlos y ofrecerte de vuelta los resultados de cada búsqueda.

5
Logo de Doofinder

El proceso es realmente sencillo y funciona a la primera. Creas un buscador, configuras las claves de la API, instalas el módulo en Magento y poca cosa más. Eso si, hay que repasar bien el manual oficial del módulo doofinder-magento2.

6

Hace tiempo tenían un método de integración mediante feeds (como el Feed URL que se ve en la imagen) pero en breve será eliminado. El método principal es a través de su API Rest.

Además de filtros y sugerencias, también puedes configurar qué campos de tus productos y con qué “peso” se utilizarán para las búsquedas.

7
Opciones de configuración de campos y peso.

Lo importante a tener en cuenta es que el módulo de Doofinder, a través del cron de Magento, envía los datos de los productos a su motor de búsqueda. Tras un primer envío, hay que cambiar la configuración del indexer a Update on Save para que cualquier actualización sea enviada a Doofinder, quien cobra por uso de su API, así que este método reduce el número de peticiones.

Actualización a 16 de marzo de 2020
Desde Doofinder me comentan que están trabajando en una nueva versión que incluirá una implementación del Instant Search similar a la de Algolia, con la que permitirán una capa de personalización superior a la actual, logrando un resultado similar al del Instantsearch.js. En cuanto pueda probarlo volveré a actualizar el post.

Cuidado, porque si cambiamos el método de indexación a Update on Schedule, Doofinder reindexará todo el contenido y además nos cobrará por todas las peticiones enviadas. No recomiendan esta opción. El módulo, por otra parte, se asegura de cambiar la configuración a Update on Save tras la primera actualización.

8
Ejemplo de los resultados que muestra Doofinder. Imagen de su blog oficial.

Antes de integrar Doofinder, asegurate de entender bien cómo funciona el workflow de integración para evitar que choque con alguno de tus módulos o integraciones.

Debo añadir que tienen un soporte técnico muy bueno y rápido. También en español. Además de ayudarte en el proceso de integración, resuelven muy bien cualquier tipo de duda que tengas y se adaptan todo lo que pueden a tus problemas o necesidades. A nosotros nos ampliaron el periodo de prueba tras tener algunos problemas y fueron comprensivos en todo momento.

Por desgracia, en nuestro caso en concreto, el sistema de actualización de artículos de Magento necesitaba atacar directamente la base de datos y no podíamos ejecutar la actualización con el Update on Save de Magento. No pudimos implementarlo.

Algolia

Algolia nos pareció algo más maduro y fiable, así que decidimos probarlo incluso sabiendo que probablemente se nos escaparía de presupuesto. Todo estaba encima de la mesa. Como comentaba, un buen buscador es clave para un buen retorno en ventas. Si sabemos lo que buscamos, utilizamos el buscador. No la navegación por categorías.

9
Logo de Algolia

El plugin para Magento 2 tiene una página en Github más quedecente, con actualizaciones constantes y varios participantes. Ver cosas como esta nos garantiza que, desactualizado, no lo está.

10

Algolia es quizá el más completo de todos. La documentación oficial es ordenada, limpia y no le falta nada! Al igual que Doofinder, Algolia también se configura con Magento a través de clave de API. El módulo se puede descargar de forma gratuita a través del Marketplace de Magento

Recomiendo probar la demo que tienen publicada con un Magento y la plantilla Luma. En ella podemos ver lo rápido que aparecen los resultados y lo robusta que es la visualización en todo tipo de dispositivos, punto también muy imporante.

11

Algolia tiene una ventaja frente a Doofinder que nos pareció muy interesante, y es que tras plantearles el problema de la actualización directa de infomación de Magento en la base de datos (algo que Doofinder no podía detectar al funcionar exclusivamente con el indexer de Magento) nos comentaron que el plugin de Algolia era capaz de detectar los cambios de datos en la BBDD de Magento a través de un campo de última actualización, lo cual solucionaba esa problemática.

El buscador SaaS más completo que hemos encontrado.

Algolia es enorme. Muy potente. Tiene una interfaz muy cuidada y da una sensación de robustez que es lo que necesita un cliente de eCommerce.

Gestión de índices, reglas, analítica, monitorización,… basta con verlo y probarlo. Puedes hacerlo durante 14 días.

12
Dashboard de Algolia

Instantsearch.js

Otra cosa muy chula que tiene Algolia es la librería instantsearch.js con la que podemos personalizar prácticamente al completo la experiéncia de usuario en las búsquedas en tiempo real. Algo que no encontramos en Doofinder y que es bastante más complejo y limitado en Elasticsearch. Incomparable, diría yo.

Conclusión

Aunque Algolia y Doofinder son bastante intuitivos, potentes y rápidos, al final nos decantamos por Elasticsearch. Nuestro caso era un poco peculiar porque teníamos más de 50.000 productos con previsión de llegar a 100.000, además de una actualización de precios constante y la necesidad de controlar de forma muy precisa el indexado y renderizado de resultados. Nuestros requisitos son de cambio constante, por eso necesitamos algo que podamos trastear, no un SaaS.

Por otra parte, sabemos que en un futuro es posible que debamos cambiar, así que aunque nos quedamos de momento con Elastic, estamos preparados para, si se da el caso, migrar rápidamente a uno tipo SaaS.

Si no tienes un eCommerce muy peculiar y personalizado como el nuestro, seguramente Algolia y Doofinder sean una gran opción a tener en cuenta. Como en todo, el producto ideal para todos los casos no existe.

La bala de plata no existe. Para cada proyecto nuevo que valoramos, volvemos a tener en cuenta todas estas opciones.

Presta también atención al precio porque son productos de pago por uso, y depende del número de productos y las llamadas a su API (entre otras cosas) el precio puede dispararse.

También hay que decir que detrás de estas dos empresas encontramos muy buenos profesionales técnicos que nos ayudaron en todo momento a implementar, probar y solucionar todo tipo de dudas. No te quedes con las ganas de probarlos.

Integrar Webpack 4 en un proyecto Django 3

1oLDVI S85Zs 59MJvcg6wA
webpack.base.config.js

En este post explicaré los pasos a seguir para integrar Webpack 4 en cualquier proyecto Django 3 con la ayuda de django-webpack-loader y webpack-bundle-tracker

¿Qué es y por qué necesitas Webpack?

Webpack es básicamente un empaquetador de módulos o module bundler que se encarga de generar gráficos de dependencias con todos ellos y crear assets estáticos a partir de los distintos módulos JavaScript o CSS.

En lugar de tener un montón librerías JavaScript (Bootstrap, jQuery, Colorpicker,…) y llamar los ficheros desde el código HTML, podemos obtener un único fichero bundle.js que los incluye todos. Lo mismo ocurre con los CSS.

No solo eso, Webpack es más que una simple utilidad. También tiene loaders y plugins que extienden sus funcionalidades, y permite automatizar tareas con una configuración bastante fácil y ordenada.

Webpack te será útil si desarrollas una aplicación mayormente JavaScript y con unos cuantos módulos. Si estás preparando una página o aplicación muy pequeña y que apenas tenga 2 o 3 componentes, quizá sea demasiado grande para ti. No hay que fliparse y utilizar todo tipo de tecnología moderna para estar a la última. Tenemos que ser ágiles y realistas.

Los módulos que ayudan a integrar Webpack en Django

Webpack se puede utilizar en prácticamente cualquier tipo de proyecto. En el fondo no necesitamos nada especial para que funcione con Django, pero sí existen dos componentes que ayudan en algunas cosas.

En primer lugar, podemos usar webpack-bundle-tracker, que se encarga de “emitir” información sobre el estado de la compilación de Webpack a un fichero JSON que será interpretado por django-webpack-loader, y este utilizará la información generada para integrarlo con Django.

Paso 1: Instalar webpack

El primer paso es generar un package.json y instalar los paquetes necesarios:

npm init

En el fichero package.json podemos añadir los siguientes scripts. Al final me decanté por crear dos webpack.config.js distintos, uno para desarrollo y otro para producción, así que quedaría de esta forma:

...
"main": "webpack.config.js",
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "watch": "webpack --watch --mode development",
    "start": "webpack-dev-server --open",
    "build": "webpack --config webpack.base.config.js --progress --colors",
    "build-production": "webpack --config webpack.production.config.js --progress --colors"
  }
...

Esto nos abre la posibilidad de ejecutar los siguientes comandos:

npm run test
npm run watch
npm run start
npm run build
npm run build-production

Paso 2: Crear el fichero webpack.config.js

Como comentaba, en mi caso creé uno para cada entorno.

webpack.base.config.js
webpack.production.config.js

Os voy a compartir el que creé para uno de mis proyectos. He eliminado algunas partes porque tiene varios ficheros css y js añadidos y he dejado dos o tres en cada bundle.

Añadí algunos extras como por ejemplo:

  • IgnorePlugin: Para ignorar ciertos ficheros.
  • ProvidePlugin: Para cargar módulos en lugar de importarlos.
  • ContextReplacementPlugin: Para reemplazar con expresiones regulares. Lo utilicé porque tenía problemas con los .js de la carpeta /locales de uno de los módulos, y con este plugin puedo substituirla con un módulo vacío.
  • En el output: path le indicamos la carpeta donde debe generar los bundles. En este caso: /assets/bundles/

Paso 3: server.js

Necesitamos un servidor node para que Webpack genere los bundles. Para ello necesitamos el fichero server.js, este es el mio:

Paso 4: Instalar django-webpack-loader

Basta con instalar el módulo de Django con pip

pip install django-webpack-loader

Y añadirlo en el fichero requirements.txt

django-webpack-loader==0.7.0

En mi caso he configurado el settings.py para añadir lo siguiente. Primero la carpeta /assets/, que es donde se generan los bundles, en la variable STATICFILES_DIRS

STATICFILES_DIRS = [
...
os.path.join(BASE_DIR, 'assets')
]

Luego la variable WEBPACK_LOADER indicando la carpeta “bundles/” donde se generan (recordamos que es: /assets/bundles), y en el STATS_FILE debemos indicarle el fichero generado por webpack-bundle-tracker, que en mi caso es el de desarrollo.

# Webpack
WEBPACK_LOADER = {
"DEFAULT": {
"CACHE": not DEBUG,
"BUNDLE_DIR_NAME": "bundles/",
"STATS_FILE": os.path.join(BASE_DIR, "webpack-stats.base.json"),
"POLL_INTERVAL": 0.1,
"TIMEOUT": None,
"IGNORE": [".*\.hot-update.js", ".+\.map"],
'LOADER_CLASS': 'webpack_loader.loader.WebpackLoader',
}
}

Paso 5: Indicar los bundles en las plantillas de Django

Nos queda indicarle a Django cómo cargar los bundles generados. En mi caso decidí crear los bundles vendor y main tanto para los ficheros CSS como los JS.

En primer lugar necesitamos cargar el render_bundle del módulo webpack_loader (línea 19)

Ahora ya podemos utilizarlos en la plantilla de Django de la siguiente forma:

<!-- Webpack bundles -->
{% render_bundle "vendor" "css" %}
{% render_bundle "main" "css" %}
....
<!-- Webpack bundles -->
{% render_bundle "vendor" "js" %}
{% render_bundle "main" "js" %}

Y de esta forma, podemos cargar los CSS dentro del <head> y los JS antes de cerrar el <body>

Ahora ya podemos utilizar collectstatic para copiar los ficheros generados en nuestra carpeta de estáticos en producción.

python manage.py collectstatic

Con esto debería ser suficiente para tener todo en funcionamiento. Si se os ocurre alguna forma mejor, será bienvenida.

Como implementar django-registration y personalizar sus plantillas

Quienes me conocen en el ámbito laboral, saben lo mucho que me gusta Django 😄

Hace años que muchos de los proyectos personales relacionados con aplicaciones web, los hago acompañados de este framework Python.

En este artículo daré 4 pistas sobre cómo implementar django-registration y poder personalizar las plantillas visuales y las que utiliza para enviar los correos de registro y validación.

El objetivo es tener una aplicación con un sistema de registro de usuarios que tenga todas las funcionalidades básicas cubiertas, y además, personalizadas. Todo está probado con Django 3.0.3 y django-registration 3.1.

No es un artículo que entre en detalle y en el que estén todas las líneas de código necesarias para que esto funcione. Es un pequeño resumen que creo que puede servir para sacar dudas que yo mismo me encontré a lo largo del desarrollo.

Vamos a ver los siguientes pasos.

  • Instalar y configurar django-registration
  • Registro de uno o de dos pasos?
  • Personalizar todas las plantillas y correos
  • Ejemplos de plantillas personalizadas

Instalar y configurar django-registration

No voy a detallar los pasos más fáciles de la instalación porque están mejor explicados en la documentación oficial. En lugar de esto, explicaré qué configuración he preparado yo para uno de mis proyectos, que en más de un caso ha sido fruto de un buen rato de I+D hasta conseguir el funcionamiento que quería.

Tras la instalación via requirements.txt o pip, el siguiente paso es configurarlo a través del fichero settings.py

# Django registration
ACCOUNT_ACTIVATION_DAYS = 7
REGISTRATION_OPEN = True
EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
EMAIL_FILE_PATH = os.path.join(BASE_DIR, 'tmp/email')

En mi caso he configurado 7 días de activación (hasta que caduca el enlace). Las otras 3 líneas las he utilizado en el entorno de desarrollo y personalizado en el fichero settings.py de producción. En este caso me interesa poder abrir o cerrar el registro a nuevos usuarios, y en el entorno de desarrollo desactivar el envío de mails, que en realidad se guardan dentro de un fichero en la carpeta /tmp/email y es mucho más fácil consultarlos de esta forma que montar un servidor de correo interno.

Después hay que configurar las URL’s para decirle a Django qué módulos cargar y bajo qué patrones.

from django.urls import include, path

urlpatterns = [
    ...
    path('accounts/', include('django_registration.backends.activation.urls')),
    path('accounts/', include('django.contrib.auth.urls')),
]

Ya que más adelante explicaré cómo personalizar todas las plantillas y URL’s, hay que tener en cuenta que en caso de querer hacerlo, las líneas anteriores deben ir al final de las que personalicemos.

Registro de uno o de dos pasos?

Hay dos formas de implementar el registro. Con el de un solo paso conseguimos que el usuario esté confirmado y sin necesidad de validar su cuenta de correo.

En cambio, el registro de dos pasos obliga al usuario a validar su dirección de correo. Hay pocas excusas para no usar este segundo método.

La diferencia en la configuración es que, si queréis utilizar el registro de un solo paso, en lugar de importar las URL de backend.activation.urls hay que importar:

path('accounts/', include('django_registration.backends.one_step.urls')),

Personalizar todas las plantillas y correos

Aquí viene lo divertido. En mi caso, que siempre me gusta tenerlo todo bien ordenado en una estructura de carpetas y ficheros lo más coherente posible, he personalizado la localización de todas las plantillas visuales y las que se utilizan para en envío de correos.

1 bf7tPArrqnPog0PEFdCvIA 1

Tengo una aplicación de Django llamada users que centraliza todo lo relacionado con los usuarios de la web.

Dentro de la carpeta /templates/registration tengo todas las relacionadas con el proceso de registro. Plantillas de la aplicación y de los correos. La de login.html dentro de templates pero fuera de registration.

Para que esto funcione, debemos personalizar las URL’s para que carguen las plantillas en estas rutas, que no son las que trae por defecto django-registration.

Registro y correo de activación

Este primer path es para crear la página de registro bajo la URL accounts/register. Aquí cargamos la plantilla registration_form.html y llamamos al RegistrationView pasándole también la ruta de las dos plantillas de correo que se utilizarán para generar el mail de activación.

1 mnNN CsCPnhN7fsDK074mg
path('accounts/register/',
RegistrationView.as_view(
form_class=CustomUserForm,
template_name="registration/registration_form.html",
email_body_template = 'registration/activation_email_body.txt',
email_subject_template = 'registration/activation_email_subject.txt'
),
name='django_registration_register',
),

En el fichero forms.py declaramos la clase CustomUserForm de la siguiente manera:

from django_registration.forms import RegistrationForm
class CustomUserForm(RegistrationForm):
username = forms.Field(
widget=forms.TextInput(
attrs={'placeholder': _('Username')}
)
)
email = forms.Field(
widget=forms.EmailInput(
attrs={'placeholder': _('Email')}
)
)
password1 = forms.Field(
widget=forms.PasswordInput(
attrs={'placeholder': _('Password')}
)
)
password2 = forms.Field(
widget=forms.PasswordInput(
attrs={'placeholder': _('Type your password again')}
)
)
class Meta(RegistrationForm.Meta):
model = get_user_model()
fields = ('username', 'email')

Registro cerrado

La que muestra el mensaje de error a los usuarios que intentan registrarse cuando tenemos el parámetro REGISTRATION_OPEN = False

path('accounts/register/closed/',
TemplateView.as_view(template_name='registration/registration_closed.html'),
name='registration_disallowed'
),

Registro completado

La plantilla que carga una vez el usuario finaliza el proceso de registro, pero todavía no ha activado la cuenta. Aquí podemos indicarle que revise su bandeja de correo para hacer click en el enlace de activación.

path('accounts/register/complete/',
RegistrationView.as_view(
form_class=CustomUserForm,
template_name="registration/registration_complete.html"
),
name="registration_complete",
),

Registro verificado

A diferencia de la anterior, esta es la página que verá el usuario tras hacer click en el enlace de validación.

path('accounts/activate/complete/',
RegistrationView.as_view(
template_name='registration/activation_complete.html'
),
name='django_registration_activation_complete'
),

Reset de contraseña

Que no se os olvide añadir la opción para que los usuarios puedan resetear su contraseña.

De esta forma, llamando al PasswordResetView, podemos personalizar el nombre de la plantilla en el template_name. Y además, necesitaremos personalizar la pantalla de resultado:

path('accounts/password/reset/',
auth_views.PasswordResetView.as_view(
template_name='registration/password_reset.html'
),
name='password_reset'
),
path('accounts/password_reset/done/',
auth_views.PasswordResetView.as_view(
template_name='registration/password_reset_done.html'
),
name='password_reset_done'
),

Fallo de validación

Los enlaces de activación tienen un formato concreto. Se genera una clave que se utiliza en la URL para que Django pueda verificar la acción. En caso de fallo, también podemos personalizar la plantilla con el mensaje que verá el usuario:

url(r'^accounts/activate/(?P<activation_key>[-:\w]+)/$',
    ActivationView.as_view(
        template_name = 'registration/activation_failed.html'
    ),
    name='django_registration_activate'
),

Ejemplos de plantillas personalizadas

Para terminar, os adjunto un par de plantillas de ejemplo personalizadas que he utilizado en uno de mis proyectos. Concretamente, la aplicación web StoryDevil

Así configuro el móvil para evitar distracciones y priorizar lo importante

0*mLtsmjiqj4kkdwVV
Photo by mnm.all on Unsplash

Quiero explicar cómo tengo configurado el móvil (un iPhone) para gestionar bien las distracciones del día a día y priorizar aquellas notificaciones, llamadas y demás, únicamente para las personas y el contenido que sean realmente importantes para mí. Estos cacharros nos molestan más de lo que deberían y nos hacen perder un tiempo muy valioso.

Siempre en silencio (salvo honradas excepciones)

Mi iPhone, por defecto, siempre está en silencio. Raramente escucharás uno de mis tonos, pero configuro excepciones (que explico más adelante). Nadie quiere escuchar sonidos de teléfonos ajenos. Gracias al Apple Watch me entero de mis notificaciones. Nadie más tiene porqué hacerlo.

WhatsApp

Esta aplicación nos “controla”, y no solo recogiendo y analizando todos los datos posibles (localización, contactos, mensajes, horas activas, etc) sino que también logra que nuestros amigos controlen nuestro tiempo.

Y tu tiempo es tuyo.

No estoy en grupos molestos ni llenos de gilipolleces. Si alguna vez me han añadido a alguno, salgo sin dar explicaciones. En los que estoy, todos están silenciados excepto dos, y ambos tienen solo 3 miembros.

Los contactos también, la mayoría en silencio. Solo 5 personas (y dos grupos) no lo están, y es porque cuando me hablan, quiero enterarme al momento. Al resto, les atenderé cuando pueda y cuando quiera. Si es realmente urgente, nadie manda un WhatsApp.

1

Lista de favoritos y llamadas

Una llamada suele ser importante, y si es de un amigo o familiar todavía más. Todas las llamadas de números que tengo en la agenda, llegan con una vibración constante del Apple Watch y la pantalla iluminada del iPhone.

En estos casos, el teléfono no suena. Con que vibre me es suficiente y no tengo porqué molestar a los demás.

Pero hago una excepción.

Tengo una lista de 3 contactos favoritos VIP. Configurados con la máxima prioridad de contacto para que puedan alcanzarme sea como sea. Si llaman, además de la vibración, y aunque el teléfono está en silencio, este sonará igualmente y al máximo volumen.

2 4

Además, iOS tiene una funcionalidad que le añade un extra a posibles llamadas y mensajes de contactos muy importantes, el Emergency Bypass. Con esta funcionalidad, cuando uno de estos contactos te llama o te manda un iMessage, iOS se salta incluso el modo “No molestar” y hace que el móvil suene y vibre.

3 5

Llamadas de números no reconocidos

Hoy en día es muy común recibir llamadas de números que no tenemos en la agenda y que casi siempre son de empresas de marketing que tratan de vendernos algo. He solucionado este tema de raíz. iOS tiene una opción para silenciar y bloquear todas las llamadas si el número entrante no está en tu propia agenda, y así lo hice.

Tiempo, cabreos, disgustos. Para mí, las llamadas de marketing pueden irse, con perdón, a tomar por el culo. Sean de quien sean. Incluso de la oficina del banco o del seguro que ya tengo contratado. Si es algo realmente interesante para ti, eres tu quien iniciará la llamada, no ellos.

4 7

Un correo electrónico tampoco es urgente

Si alguien te envía un mail, ya sea corporativo o personal, no es para avisarte sobre un tema de vital importancia que necesite ser atendido al instante. De ser así, te llamará.

En mi caso utilizo Outlook y lo tengo configurado para recibir notificaciones únicamente con la actualización del contador visible en el icono de la app. Si desbloqueo el móvil y veo que tengo correos pendientes, los revisaré si quiero dedicarle tiempo en ese momento. De lo contrario, no.

Incluso así, es importante ser ágil respondiendo y gestionando mails. Tampoco es cuestión de pasar de todo, sino simplemente gestionar las tareas eficientemente y a su debido tiempo.

El modo “No Molestar”

Este modo de iOS también es útil para activarlo puntualmente o programarlo a unas determinadas horas del día, como por ejemplo por las noches y/o cuando te vas a la cama.

En mi caso, lo activo siempre por las noches pero permitiendo llamadas de mis favoritos y, además, si alguien que no lo está insiste (Repeated Calls) sonará igual porque es posible que sea un tema urgente.

5 1

Con todo esto he conseguido que el móvil me moleste lo más mínimo y sea yo quien controle mi tiempo, no los demás lo hagan por mí.

Jugando con la Lente Anamórfica de Moment

Hace unos días compré la lente anamórfica de Moment para usarla con mi iPhone XS. Un gran juguete para los amantes del cine y la fotografía. Por poco más de 150 dólares puedes hacer fotos y vídeos con una lente emulando una cámara de cine de forma muy decente.

Nació como un proyecto de Kickstarter y lograron recaudar más de $800,000 de los $50,000 que necesitaban. No somos pocos los que queremos lograr ese look cinematográfico con lo que tenemos en casa. A ese precio es muy tentador, incluso ideal como simple hobby.

Es difícil conseguirla en alguna tienda española, yo la compré directamente en la tienda oficial de Moment, aunque también se puede conseguir a través de Amazon.com

1 1
Foto sin ningún retoque adicional y hecho con la app oficial de Moment. Mi bar de chinos favorito 😀

Básicamente es una lente anamórfica de 1.33x con un aspect ratio de 2.40:1. La lente comprime la imagen, y con la aplicación de grabación de Moment o la de FiLMiC, se “descomprime” para obtener la imagen correcta consiguiendo incluso efectos de Lens Flares a lo JJ. Abrams 🥳

La aplicación oficial de Moment para iOS tiene un precio de $5.99, pero fijaros bien al comprar la lente porque suelen regalar un código de descuento para poder bajarla gratis.

2
3
Los lens flares crearon un efecto curioso con la luz del semáforo.
4

Ponerla y quitarla es bastante fácil. Las carcasas de Moment están adaptadas para cada lente y basta con un simple giro de 90 grados para que quede perfectamente acoplada y alineada con la cámara del móvil.

La construcción de la lente es de muy buena calidad. Incluye una tapa frontal , pero no una trasera que pueda usarse para proteger la entrada de la lente. Para hacerlo y que quede bien protegida hay que guardarla dentro de la caja original, aunque también trae una pequeña bolsa para transportarlo.

5
6
7
8
9