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.
- Docu de Lambda Functions de AWS (son las que usamos con Netlify)
- Docu de NodeJS para leer más sobre transacciones HTTP (en inglés)
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í:
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!
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_KEY
y 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! 😄😄