React Workshop

Workshop - Paso 3

Usando Netlify para nuestro proyecto

Bueno, como algunos habrán visto, casi todos mis slides y proyectos los tengo subidos a Netlify, es (más que) un hosting bastante copado y facilita mucho el subir proyectos hechos por ejemplo con create-react-app. También tienen algo que se llama Netlify CLI (Command Line Interface) y Netlify Functions. Es decir, vamos a usar varias cosas del paquete de Netlify 😎

Antes que nada, vamos a usar una lambda function (en inglés) para mantener a salvo nuestra API key que tenemos en nuestro archivo .env.development.local! Para los que hicieron la versión anterior de este workshop, es parecido a lo que hacíamos antes, pero los amigotes de webtask parece que no aceptan nuevos registros... 🙄 (Gracias Iván Meyer por avisarme)

Empecemos por crear una carpeta en la raíz de nuestro proyecto que se llame functions, debería quedar a la misma altura que nuestro package.json y demás carpetas. Dentro de esa carpeta creamos un archivo con extensión js cuyo nombre va a definir la url después a donde tengamos que hacer nuestro fetch, por ejemplo le ponemos de nombre getWeather.js.

Ahora todo lo que tengamos ahí adentro de nuestra lambda function va a funcionar como un estilo de backend para nosotros. Lo que vamos a hacer básicamente para pedir la data del clima sería algo así:

Frontend usando fetch -> Lambda Function usando request -> Apixu

Explicado en palabras, desde nuestro frontend usando fetch, hacemos una petición a una URL que apunta a nuestra Lambda Function, desde la cual usando request hacemos la petición a Apixu. Luego la data fluye al revés con la respuesta de lo que nos retorne el servicio de Apixu. Si todavía no se entiende (es muy probable, porque no explico muy bien 😅), este link puede ser de gran ayuda.

Una vez adentro del archivo getWeather.js, vamos a crear un endpoint nuevo, el cual debe quedar así:

exports.handler = (event, context, callback) => {
  //Acá va nuestro código
}

Wow, y qué es eso? 🤪 Esto se parece un poco más a cómo sería código en NodeJS (un poco nomás), pero a no asustarse que hay que modificar un par de cosas y ya lo sacamos andando 😉 Vamos de a poco: exports.handler representa nuestra función y es el punto de entrada cuando hagan una petición a nuestro endpoint, la cual recibe por parámetros un evento, un contexto y un(a) callback. Donde event es un objeto donde vamos a tener datos de la petición que recibimos del Frontend (tipo de petición HTTP, ya sea GET, POST, etc., datos recibidos del Frontend si es una petición POST; digamos que es donde pasa toda la magia), context pensé que iba a tener un contexto desde dónde se hacía la petición o algo así pero parece que no, entonces no le encuentro mucha utilidad 🤷‍♂️ y callback es una función que utilizamos para retornar data procesada al frontend o avisamos que hubo un error.

Empecemos por chequear qué tipo de petición nos estarían haciendo, nosotros desde el Frontend vamos a hacer una petición de tipo GET utilizando fetch() como ya hicimos. La información de la petición la encontramos en event.httpMethod, así que dentro de nuestra función hacemos:

exports.handler = (event, context, callback) => {
  //Chequeamos el tipo de petición HTTP, puede ser GET, POST...
  if (event.httpMethod === 'GET') {
    //Acá tenemos que ir a buscar la data a Weatherbit y retornarla en el
    //body de un objeto usando la función callback
  }
}

Bien, ahora tenemos que traernos la dirección de la API que nos la traemos del Frontend y necesitamos una forma de traernos la data porque fetch() no nos sirve acá (en el "backend"). Empecemos por tener la URL de la API a mano así después la usamos para ir a buscar la data, en el renglón siguiente al exports.handler y afuera del if nos guardamos la URL de la petición a Weatherbit en una constante:

const request_url = `https://api.weatherbit.io/v2.0/forecast/daily?city=Buenos+Aires,Argentina&key=${process.env.REACT_APP_API_KEY}&days=7`

Por el momento vamos a dejar así como está la constante ya que la vamos a configurar más adelante de forma súper fácil 😉

Buenísimo, ya tenemos la URL para buscar la data y sabemos que nuestra API key va a estar a salvo. Ahora tenemos que ir a buscar la data a nuestra request_url y retornarla en la respuesta de la función callback. Para hacer esto tenemos un paquete llamado request que es bastante intuitivo y copado, vamos a agregarlo a nuestro proyecto y luego lo incorporamos en la Lambda Function.

En la terminal, en la raíz de nuestro proyecto corremos el siguiente comando:

npm install request --save

Y una vez que se instala ya podemos usarlo en getWeather.js, primero lo importamos (afuera de exports.handler, arriba de todo):

const request = require('request')

Un momento, que importar no se hace con import? No me mientas, Agustin! 🤬 Bueno, no, no les miento 😅 como dijimos que esto funcionaría como un backend, así es como se importan paquetes en NodeJS por ejemplo.

Ahora que ya lo tenemos importado, vamos a usarlo! Agregamos esto adentro de nuestro if:

if (event.httpMethod === 'GET') {
  request.get(request_url, function(error, res, body) {
    if (error) {
      callback(null, {
        statusCode: 500,
        body: error,
      })
    } else {
      callback(null, {
        statusCode: 200,
        body: body,
      })
    }
  })
}

Pero esto cada vez se complica más! 🤬🤬🤬 Bueno, parece complejo pero yo creo que explicando cada parte se entiende bien lo que estamos haciendo: Con request.get vamos a ir a buscar a nuestra URL la data de Weatherbit, luego esa data que se consiga, se recibe en la función que está como segundo parámetro de get, en la cual tendremos en error el objeto de error si llegase a haber alguno (crucemos los deditos para que no 🤞), en res tendremos otro objeto de respuesta de esta función y en body vamos a tener la data que recibamos de hacer el request.get a la API de Weatherbit, es decir, el JSON que antes obteníamos al hacer el fetch() en el Frontend. Luego chequeamos si hay un error, y si lo hay retornamos en la función callback dos parámetros: el primero se utiliza para informar errores, pero vamos a enviar null para luego poder enviar al Frontend un objeto (como segundo parámetro) informando el código de estado 500 (código de error) y un body con los detalles del error. Lo mismo hacemos después, en el caso que no haya habido fallo, informamos un código de estado 200 (todo ok ✅) y en body mandamos lo que nos retorna el resultado de la API de Weatherbit.

Con esto podríamos decir que ya estaría hecha la Lambda Function de manera básica para hacer lo que necesitamos: No exponer nuestra API key y que nos busque la data que necesitamos. Nos debería haber quedado algo así:

Para ver la solución de cada archivo hacé click en las pestañas 👆
const request = require('request')

exports.handler = (event, context, callback) => {
  const request_url = `https://api.weatherbit.io/v2.0/forecast/daily?city=Buenos+Aires,Argentina&key=${process.env.REACT_APP_API_KEY}&days=7`
  if (event.httpMethod === 'GET') {
    request.get(request_url, function(error, res, body) {
      if (error) {
        callback(null, {
          statusCode: 500,
          body: error,
        })
      } else {
        callback(null, {
          statusCode: 200,
          body: body,
        })
      }
    })
  }
}

Ahora nos falta conectar el Frontend a nuestro endpoint! Esto nos lo simplifica bastante Netlify, nuestra función va a estar en: /.netlify/functions/NOMBRE_DE_FUNCION, en nuestro caso va a ser /.netlify/functions/getWeather. Copiamos el texto y vamos al Frontend de nuestra app, donde hicimos el fetch() y pegamos la URL nueva adentro. Guardamos el archivo y seguimos, vamos a probar si todo funciona!

Para ver la solución de cada archivo hacé click en las pestañas 👆
componentDidMount() {
  fetch(
    `/.netlify/functions/getWeather`
  )
  .then(result => result.json())
  .then(jsonData => {
    const current = jsonData.data.shift()
    const forecast = jsonData.data
    const location = {
      city_name: jsonData.city_name,
      country_code: jsonData.country_code,
      state_code: jsonData.state_code,
    }
    this.setState({ current, forecast, location, isLoaded: true })
  })
}

Haciendo deploy de nuestra app

Antes que nada, al haber hecho nuestra función, debemos indicarle a Netlify en qué carpeta de nuestro proyecto tiene que buscarla, así que creamos un archivo en la raíz de nuestro proyecto y le ponemos de nombre netlify.toml, adentro escribimos lo siguiente:

[build]
functions = './functions'

Como sé que hay personas que no confían en los permisos de third parties sobre código de Github, vamos a ver dos formas de hacerlo:

Vinculando nuestro Github

Si vinculamos nuestra cuenta de Github, para subir nuestro proyecto es tan simple como entrar a nuestro usuario en Netlify y decirle cuál es el proyecto del que queremos que haga el deploy, pero para eso primero tenemos que subir nuestra app del clima a un repo nuestro, no? Pequeño detalle 😜 Comencemos por entrar a nuestro usuario de Github, a la parte de repositorios y creemos uno nuevo con el botón verde New que está a la derecha, o entrando en este link. Luego escribimos un nombre para nuestro repositorio (por ejemplo "ClimaApp") y no hace falta que pongamos descripción ni que lo inicialicemos con un README. Vamos al botón de abajo de todo y terminamos de crear nuestro repositorio. Se nos va a crear un repositorio vacío y el mismo Github que es re copado nos va a decir cómo subir nuestro proyecto donde dice …or push an existing repository from the command line. Entonces abrimos una terminal y vamos hasta la carpeta raíz de nuestra app, luego ahí hacemos lo que nos dice Github:

git remote add origin https://github.com/agustinmulet/ClimaApp.git
git push -u origin master

Es probable que nos pida nuestro usuario y constraseña de Github, en ese caso ingresamos nuestras credenciales y si todo salió bien, ya tenemos nuestra app subida a un repo propio!

Ahora resta hacer lo que dije antes, entrar con nuestro usuario a Netlify, hacer click en el botón verde de arriba a la derecha que dice New site from Git e indicarle cuál es el repositorio con nuestra app (ClimaApp si le pusieron el mismo nombre que yo), esperamos un poco que haga el deploy y ya (casi) está! Lo que sí, Netlify nos da un nombre raro para nuestro sitio, así que podemos ir a Cambiando la URL.

Sin vincular nuestro Github

Si no te gusta andar vinculando tu Github con cualquier cosa, o si no usás o no tenés Github, no te preocupes, se puede subir nuestro proyecto igual 😊

Empecemos por instalarnos la CLI de Netlify de forma global, en la terminal corremos:

npm i -g netlify-cli

Y luego nos hacemos cuenta en Netlify y logueamos con nuestra cuenta de Netlify (en la terminal):

netlify login

Para hacer el deploy, necesitamos nuestra app lista para producción, la generamos corriendo el siguiente comando:

npm run build

Y vamos a ver que se crea una carpeta build con nuestra app lista para hacer el deploy, pero usamos la CLI para hacer esto así se sube la función que hicimos y dejamos que Netlify haga un poquito de su magia.

⚠️ Niñas y niños, no intenten esto en sus casas ⚠️ 🤣🤣

Vamos entonces con el deploy a producción, en la terminal:

netlify deploy --prod

Esto nos va a indicar que no tenemos nuestro proyecto vinculado a ningún sitio existente en Netlify, pero nosotros queremos hacer uno nuevo, así que con las flechitas seleccionamos Create & configure a new site y luego nos pregunta un nombre para nuestro sitio (podemos hacerlo ahora o luego en Cambiando la URL). Lo siguiente que consulta es en qué "Team" queremos agregar nuestro proyecto, si no les pregunta esto seguramente les pida usuario y contraseña porque no se loguearon antes, no pasa nada.

Luego crea nuestro sitio, nos informa URL de Admin, URL donde va a estar alojada nuestra app y un ID de sitio (el cual va a estar en un archivo /.netlify/state.json de configuración en nuestro proyecto) y nos pide luego el path donde está nuestra app preparada para hacer deploy, que es la carpeta build que generamos antes, entonces escribimos build y apretamos enter y ya (casi) está! Si no pudimos generar la url que queríamos o queremos cambiarla, en la siguiente sección podremos hacerlo.

Cambiando la URL

Para cambiar el nombre al que querramos (nombredeapp.netlify.com), tenemos que (si es que estamos en el Dashboard principal de Netlify) hacer click en nuestra app recién subida con nombre raro, hacer click en el botón ⚙ Site Settings y en la parte de Site Information vamos a ver otro botón Change site name, donde podemos definir el nombre que querramos. Es probable que algún nombre como ClimaApp esté utilizado, pero podemos inventar algo usando nuestro nombre, o algún nombre raro que se les ocurra (climarino, weatherapp, miappdelclima, loquesea jaja).

Agregando nuestra variable de entorno el proyecto

Lo último que tenemos que hacer para que nuestra app funcione bien! Hayas elegido vincular con Github o no, la verdad que esta es la única forma que encontré que realmente funciona para crear variables de entorno, porque supuestamente al agregarla en el archivo netlify.toml se puede probar todo de manera local usando Netlify Dev, pero al estar en Beta parece que faltan ajustar algunos tornillos. (O soy yo que no tengo idea de cómo usarlo bien, si alguien sabe que me avise este es mi Twitter)

Bueno basta de cháchara, la variable! Para esto vamos a ⚙ Site Settings de nuestro proyecto y ahí dentro a Build & deploy, Environment y creamos una nueva haciendo click en el botón Edit variables. Nos pide Clave / Valor, por practicidad vamos a poner como clave el nombre que venimos usando REACT_APP_API_KEYy como valor ponemos nuestra API key c4321dd709e94986a41d00XXXXXXXXXX todo así sin comillas, solamente el texto.

Guardamos, es posible que tengamos que repetir el tema del deploy, pero bueno, no es óptimo pero es la forma que encontré que funciona...

Listo! Espero que hayan disfrutado este workshop y cualquier cosa que les parezca mejorable o que no esté claramente explicada, manden PR para poder hacer un buen workshop de React desde cero y que más gente pueda aprender.

Además, si tienen ganas, pongan una foto en Twitter de su app funcionando, para contagiar a que más personas lo hagan :) y pueden alterar el CSS, lo que quieran!

Cómo seguir desde acá?

Ahora la idea es ir mejorando lo que tenemos, les tiro un par de ideas de cosas que se pueden hacer:

  • Mostrar más datos
  • Reacomodar cosas en el layout
  • Agregar un input y buscar el clima en distintas ciudades

Mil cosas más se pueden hacer, pero esas me parecen copadas. Y si te animás a agregar el input para buscar en distintas ciudades, me gustaría verlo! 😄😄

© 2021 - MIT License