No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Aprende todo un fin de semana sin pagar una suscripci贸n 馃敟

Aprende todo un fin de semana sin pagar una suscripci贸n 馃敟

Reg铆strate

Comienza en:

3D
11H
7M
15S

Variables de ambiente en Node.js

8/27
Recursos

Aportes 19

Preguntas 17

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

Unit Test

馃挕Es el proceso de ejecutar un programa con la meta de encontrar errores. Si la 鈥減rueba鈥 es exitosa, entonces podemos asegurar que, alguna caracter铆stica o funcionalidad, fue cubierta.

.
Para este caso, sugiero que implementen sus pruebas ya sea de unit test (funci贸n o m贸dulo) y/o end-to-end (integraci贸n).
.

Configuraci贸n

鈩癸笍Repositorio: link
.
Para adicionar pruebas a nuestro c贸digo utilizamos:

  • jest. Engine de pruebas para JavaScript
  • supertes. Handler Process para peticiones HTTP.

.
鉁–omo retornamos un arreglo como data para validar el cambio de pool podemos definir el siguiente bloque:

import supertest from 'supertest';
import app from '../src/index';

const request = supertest(app);

/**
 * @description colleciton of test cases on task request
 * @param {string} - case name
 */
describe('routes', () => {
    describe('GET /task', () => {
        it('should respond with a json', async () => {
            const { status, body: response } = await request.get('/task');
            expect(status).toBe(200);
            expect(Array.isArray(response.data)).toBeTruthy();
        });
    });
});

鈾伙笍Ambas librer铆as para pruebas, necesitamos obtener un servidor http y express no los retorna cuando utilizamos express().

import express from 'express';
import task from './routes/api/task';

// code
const app = express();

// code
app.use('/task', task);

// code
if (mode !== 'test')
    app.listen(port, () => listen(`猬 Server Thingst - ${mode}`));
export default app;

馃敟Evitamos que en test no levante el servidor, ya que supertest lo har谩 por nosotros.
.
鈾伙笍Actualizamos nuestro script para leer nuestros test:

"test": "NODE_ENV=test jest test/index.test.js --forceExit",

Variables de ambiente en Node.js

Las variables de entorno se utilizan para contener contenido sensible

Instalamos el siguiente paquete

Esto nos sirve para tener las variables de entorno corriendo en el proceso de node

npm i dotenv

Creamos nuestro archivo de configuracion

config>config.js

require('dotenv').config();

const config = {
  env: process.env.NODE_ENV || 'dev',
  port: process.env.PORT || 3000,
  dbUser: process.env.DB_USER,
  dbPassword: process.env.DB_PASSWORD,
  dbHost: process.env.DB_HOST,
  dbName: process.env.DB_NAME,
  dbPort: process.env.DB_PORT,
};

module.exports = { config };

Adaptamos nuestro pool

Archivo anterior

const { Pool } = require('pg');

const pool = new Pool({
  host: 'localhost',
  port: 5432,
  user: 'kevin',
  password: 'admin123',
  database: 'my_store',
});

module.exports = pool;

Archivo usando las variables de entorno

La URI se conforma por 鈥protocolo馃槙/USUARIO:CONTRASE脩A@HOST:PUERTO/NOMBREDB

El encodeURI es una manera de proteger estos datos tan sensibles, lo mismo cuando ya tenemos la URI armada

const { Pool } = require('pg');
const { config } = require('../config/config');

const USER = encodeURIComponent(config.dbUser);
const PASSWORD = encodeURIComponent(config.dbPassword);
const URI = `postgres://${USER}:${PASSWORD}@${config.dbHost}:${config.dbPort}/${config.dbName}`;

const pool = new Pool({ connectionString: URI });

module.exports = pool;

Archivo .env

	PORT=3000
  DB_USER='kevin'
  DB_PASSWORD='admin123'
  DB_HOST='localhost'
  DB_NAME='my_store'
  DB_PORT='5432'

Archivo .env.example

	PORT='',
  DB_USER='',
  DB_PASSWORD'',
  DB_HOST'',
  DB_NAME='',
  DB_PORT='',

驴Recuerdan el documento docker-compose.yml?
Pues resulta que tambi茅n le podemos colocar las variables de entorno de la siguiente manera, sin configuraciones o paquetes adicionales:

version: "3.3"

services:
  postgres:
    image: postgres:13
    environment:
      - POSTGRES_DB=${DB_NAME}
      - POSTGRES_USER=${DB_USER}
      - POSTGRES_PASSWORD=${DB_PASSWORD}
    ports:
      - ${DB_PORT}:${DB_PORT}
    volumes:
      - /postgres_data:/var/lib/postgresql/data

  pgadmin:
    image: dpage/pgadmin4
    environment:
      - PGADMIN_DEFAULT_EMAIL=${PG_EMAIL}
      - PGADMIN_DEFAULT_PASSWORD=${PG_PASSWORD}
    ports:
      - ${PG_PORT}:${PG_REFPORT}

Hagan la prueba y me cuentan si funciona. 馃槈

Aplicando desestructuraci贸n de objetos podemos evitar repetir c贸digo.

const URI = `postgres://${USER}:${PASSWORD}@${config.dbHost}:${config.dbPort}/${config.dbName}`;

Les dejo el archivo config.js por si no quieren escribir 馃槂


const config = {
	env: process.env.NODE_ENV || 'dev',
	port: process.env.PORT || 3000,
	dbUser: process.env.DB_USER,
	dbPassword: process.env.DB_PASSWORD,
	dbHost: process.env.DB_HOST,
	dbPort: process.env.DB_PORT,
	dbName: process.env.DB_NAME,
};

module.exports = { config };

utilize esta extension para que se vea bonito el archivo .env
DotENV

Me siento como si estuviese construyendo Laravel desde cero pero con JavaScript. Un Taylor Otwell.

Este man sabe mucho

En config.js se tiene la configuraci贸n base para leer las variables de entorno.

En node se leen las variables de entorno con process.env.NODE_ENV seguido del entorno process.env.NODE_ENV || 鈥榙ev鈥.

require('dotenv').config();

const config = {
  env: process.env.NODE_ENV || 'dev',
  port: process.env.PORT || 3000,
  dbUser: process.env.DB_USER,
  dbPassword: process.env.DB_PASSWORD,
  dbHost: process.env.DB_HOST,
  dbName: process.env.DB_NAME,
  dbPort: process.env.DB_PORT,
};

module.exports = { config };

En el archivo postgres.pool.js se trae la configuraci贸n, una configuraci贸n es no enviar variable por variable, m谩s bien, protegerlas un poco usando encodeURIComponent() y mandar una URI con todo el esquema de conexi贸n.

const { Pool } = require('pg');
const { config } = require('../config/config');

const USER = encodeURIComponent(config.dbUser);
const PASSWORD = encodeURIComponent(config.dbPassword);
const URI = `postgres://${USER}:${PASSWORD}@${config.dbHost}:${config.dbPort}/${config.dbName}`;

const pool = new Pool({ connectionString: URI });

module.exports = pool;

En el ambiente de desarrollo, se crea un archivo de variables de entorno .env (archivo delicado, no se sube a github), ah铆 se indican los datos sensibles de la BD u otras configuraciones de ejecuci贸n. Una buena practica es tener un archivo .env.example el cual indica un ejemplo de c贸mo deber铆an ir las variables de entorno.

La librer铆a dotenv nos ayuda a leer el archivo .env . Para usarla, primero se requiere en el archivo config.js y lo que hace por defecto es leer el archivo .env y cargarlas al proceso de node.

lo m谩s recomendado es que a su archivo postgres.js tambi茅n utilicen las variables de entorno, les dejo la forma en que yo lo hice:

const { Client } = require('pg');
const { config } = require('./../config/config');

const USER = encodeURIComponent(config.dbUser);
const PASSWORD = encodeURIComponent(config.dbPassword);
const HOST = encodeURIComponent(config.dbHost);
const DATABASE = encodeURIComponent(config.dbName);
const PORT = encodeURIComponent(config.dbPort);
const URI = `postgres://${USER}:${PASSWORD}@${HOST}:${PORT}/${DATABASE}`;

async function getConnection() {
    const client = new Client({ connectionString: URI});
    await client.connect();
    return client;
}

module.exports = getConnection;

un peque帽o aporte que quizas le sirva a alguno, en las variables de entorno, en el archivo .env, no se debe poner coma al final. La coma hace que node tome la variable como si la coma fuera parte de la asignaci贸n y claramente genera error

<code> 
PORT = 3000
DB_USER='juan'
DB_PASSWORD='admin123'
DB_HOST='localhost'
DB_NAME='my_store'
DB_PORT='5432'

La encodeURIComponent()funci贸n codifica un URI reemplazando cada instancia de ciertos caracteres por una, dos, tres o cuatro secuencias de escape que representan la codificaci贸n UTF-8 del car谩cter (solo habr谩 cuatro secuencias de escape para caracteres compuestos por dos caracteres 鈥渟ustitutos鈥).

Si alguien movio su archivo .env de la carpeta raiz es posible que les tire este error al momento de hacer peticiones:

node:internal/process/promises:279
            triggerUncaughtException(err, true /* fromPromise */);
            ^

Error: getaddrinfo ENOTFOUND undefined
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:109:26) {
  errno: -3008,
  code: 'ENOTFOUND',
  syscall: 'getaddrinfo',
  hostname: 'undefined'
}

De ser asi, con regresar el archivo .env a la carpeta raiz debe volver a funcionarles correctamente.

Por si alguien no lo sabe, para que las variables de entorno tengan efecto en el c贸digo, es necesario reiniciar el servidor de node.js.

Les recomiendo que si tienen mucho problema con el docker, es decir, con los errores es mejor utilizar el mismo PostgreSQL instalado en el sistema, crear una base de datos y conectarse a ella de forma local para no estar como yo que en 3dias estuve buscando un error para solucionarlo y no tener lograr solucionar

instalamos dependencias

npm install dotenv 

creamos variables de ambiente y variables de ambiente de ejemplo
.env:

PORT=3000
DB_USER='jclentino'
DB_PASSWORD='toor'
DB_HOST='localhost'
DB_NAME='my-store'
DB_PORT='5432'

.env.example:

PORT=3000
DB_USER=''
DB_PASSWORD=''
DB_HOST=''
DB_NAME=''
DB_PORT=''

creamos un objeto de configuraci贸n con las variables de entorno
config/config.js:

require('dotenv').config()

const config = {
  env: process.env.NODE_ENV || 'dev',
  port: process.env.PORT,
  dbUser: process.env.DB_USER,
  dbPassword: process.env.DB_PASSWORD,
  dbHost: process.env.DB_HOST,
  dbName: process.env.DB_NAME,
  dbPort: process.env.DB_PORT,
}

module.exports = { config }

importamos el objeto de configuraci贸n en el archivo que contiene el pool de conexiones y reemplazamos la conexi贸n por un string de conexi贸n
libs/postgres.pool.js:

const { Pool } = require('pg')
const { config } = require('../config/config')

const USER = encodeURIComponent(config.dbUser)
const PASSWORD = encodeURIComponent(config.dbPassword)
const URI = `postgres://${USER}:${PASSWORD}@${config.dbHost}:${config.dbPort}/${config.dbName}`

const pool = new Pool({ connectionString: URI })

module.exports = pool

corremos el proyecto

npm run dev 

si visitamos la url localhost:3000/api/v1/products/ veremos como respuesta los registros en la tabla tasks

[
  {
    "id": 1,
    "title": "Terminar curso de postgres ",
    "completed": false
  },
  {
    "id": 2,
    "title": "Limpiar ",
    "completed": false
  }
]

hola, si a alguien le aparece un error Error: getaddrinfo ENOTFOUND traten de revisar la URI o la sintaxis de nuevo
o f铆jense de que {config} este desestructurado XD

Solo como comentario, crear un carpeta para un solo archivo se me hace algo innecesario, de igual forma al crearla me parece ser铆a mejor nombrar el archivo como index.js asi los imports quedan de la misma maneta que si solo crearas el archivo config.js en ra铆z y son igualmente legibles y ordenados.