node.js - tutorial - node js rest api mysql
¿Cómo almacenar la configuración de despliegue de Node.js/archivos de configuración? (23)
He estado trabajando en algunas aplicaciones de Node y he estado buscando un buen patrón de almacenamiento de configuraciones relacionadas con la implementación. En el mundo Django (de donde vengo), la práctica común sería tener un archivo settings.py
que contenga la configuración estándar (zona horaria, etc.) y luego una local_settings.py
específica para la implementación, es decir. con qué base de datos hablar, con qué memcache socket, dirección de correo electrónico para los administradores, etc.
He estado buscando patrones similares para Node. Solo un archivo de configuración sería bueno, por lo que no tiene que estar atascado con todo lo demás en app.js
, pero me parece importante tener una forma de tener una configuración específica del servidor en un archivo que no esté en control de código fuente. La misma aplicación podría implementarse en diferentes servidores con configuraciones muy diferentes, y tener que lidiar con conflictos de combinación y todo eso no es mi idea de diversión.
Entonces, ¿hay algún tipo de marco / herramienta para esto, o todos simplemente hackean algo juntos?
¿Están usando npm para iniciar sus scripts (env etc)?
Si usa archivos .env
, puede incluirlos en su package.json
y usar npm para crearlos / iniciarlos.
Ejemplo:
{
"name": "server",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node test.js",
"start-dev": "source dev.env; node test.js",
"start-prod": "source prod.env; node test.js"
},
"dependencies": {
"mysql": "*"
}
}
a continuación, ejecute los scripts npm:
$ npm start-dev
Se describe aquí https://gist.github.com/ericelliott/4152984 Todo el crédito a Eric Elliot
Además del nconf mencionado en esta respuesta , y node-config mencionado en esta respuesta , también hay node-iniparser e IniReader , que parecen ser analizadores de archivos de configuración .ini más simples.
Es mejor separar las configuraciones de ''desarrollo'' y ''producción'' .
Uso de la siguiente manera: Aquí está mi archivo config / index.js :
const config = {
dev : {
ip_address : ''0.0.0.0'',
port : 8080,
mongo :{
url : "mongodb://localhost:27017/story_box_dev",
options : ""
}
},
prod : {
ip_address : ''0.0.0.0'',
port : 3000,
mongo :{
url : "mongodb://localhost:27017/story_box_prod",
options : ""
}
}
}
Para requerir la siguiente configuración de uso:
const config = require(''../config'')[process.env.NODE_ENV];
Que puedes usar tu objeto de configuración:
const ip_address = config.ip_address;
const port = config.port;
Estoy un poco atrasado en el juego, pero no pude encontrar lo que necesitaba aquí ni en ningún otro lugar, así que escribí algo yo mismo.
Mis requisitos para un mecanismo de configuración son los siguientes:
- Apoyo front-end. ¿Cuál es el punto si el front-end no puede usar la configuración?
- Support
settings-overrides.js
- que se ve igual pero permite anulaciones de configuración ensettings.js
. La idea aquí es modificar la configuración fácilmente sin cambiar el código. Me parece útil para saas.
Aunque me importa menos los entornos de soporte, le explicarán cómo agregarlo fácilmente a mi solución
var publicConfiguration = {
"title" : "Hello World"
"demoAuthToken" : undefined,
"demoUserId" : undefined,
"errorEmail" : null // if null we will not send emails on errors.
};
var privateConfiguration = {
"port":9040,
"adminAuthToken":undefined,
"adminUserId":undefined
}
var meConf = null;
try{
meConf = require("../conf/dev/meConf");
}catch( e ) { console.log("meConf does not exist. ignoring.. ")}
var publicConfigurationInitialized = false;
var privateConfigurationInitialized = false;
function getPublicConfiguration(){
if (!publicConfigurationInitialized) {
publicConfigurationInitialized = true;
if (meConf != null) {
for (var i in publicConfiguration) {
if (meConf.hasOwnProperty(i)) {
publicConfiguration[i] = meConf[i];
}
}
}
}
return publicConfiguration;
}
function getPrivateConfiguration(){
if ( !privateConfigurationInitialized ) {
privateConfigurationInitialized = true;
var pubConf = getPublicConfiguration();
if ( pubConf != null ){
for ( var j in pubConf ){
privateConfiguration[j] = pubConf[j];
}
}
if ( meConf != null ){
for ( var i in meConf ){
privateConfiguration[i] = meConf[i];
}
}
}
return privateConfiguration;
}
exports.sendPublicConfiguration = function( req, res ){
var name = req.param("name") || "conf";
res.send( "window." + name + " = " + JSON.stringify(getPublicConfiguration()) + ";");
};
var prConf = getPrivateConfiguration();
if ( prConf != null ){
for ( var i in prConf ){
if ( prConf[i] === undefined ){
throw new Error("undefined configuration [" + i + "]");
}
exports[i] = prConf[i];
}
}
return exports;
Explicación
-
undefined
significa que esta propiedad es requerida -
null
significa que es opcional -
meConf
- actualmente el código es destino a un archivo en laapp
.meConf
son los archivos de anulación que están dirigidos aconf/dev
, que mis vcs ignoran. -
publicConfiguration
- será visible desde el front-end y el back-end. -
privateConfiguration
: solo será visible desde el back-end. sendPublicConfiguration
: una ruta que expondrá la configuración pública y la asignará a una variable global. Por ejemplo, el siguiente código expondrá la configuración pública como variable global myConf en el front-end. Por defecto usará el nombre de variable globalconf
.app.get ("/ backend / conf", require ("conf"). sendPublicConfiguration);
Lógica de anulaciones
- privateConfiguration se fusiona con publicConfiguration y luego meConf.
- publicConfiguration verifica cada clave si tiene un reemplazo, y usa ese reemplazo. De esta manera no estamos exponiendo nada privado.
Añadiendo soporte de entorno
Aunque no encuentro útil el "soporte para el medio ambiente", tal vez alguien lo haga.
Para agregar soporte de entorno, necesita cambiar la declaración de meConf require a algo como esto (pseudocódigo)
if (environment == "production") {meConf = require ("../ conf / dev / meConf"). production; }
if (environment == "development") {meConf = require ("../ conf / dev / meConf"). development; }
Igualmente puedes tener un archivo por entorno.
meConf.development.js
meConf.production.js
e importar el correcto. El resto de la lógica permanece igual.
Intenté algunas de las soluciones sugeridas aquí, pero no estaba satisfecho con ellas, así que creé mi propio módulo. Se llama mikro-config
y la principal diferencia es que respeta la convención sobre la configuración, por lo que solo puede requerir el módulo y comenzar a usarlo.
Almacena tu configuración en archivos plain js o json de la carpeta /config
. Primero carga el archivo default.js
, luego todos los demás archivos del directorio /config
, luego carga la configuración específica del entorno basada en la variable $NODE_ENV
.
También permite anular esta configuración para el desarrollo local con local.js
o con el entorno específico /config/env/$NODE_ENV.local.js
.
Puedes echarle un vistazo aquí:
Mi solución es bastante simple:
Cargue la configuración del entorno en ./config/index.js
var env = process.env.NODE_ENV || ''development''
, cfg = require(''./config.''+env);
module.exports = cfg;
Defina algunos valores predeterminados en ./config/config.global.js
var config = module.exports = {};
config.env = ''development'';
config.hostname = ''dev.example.com'';
//mongo database
config.mongo = {};
config.mongo.uri = process.env.MONGO_URI || ''localhost'';
config.mongo.db = ''example_dev'';
Anule los valores predeterminados en ./config/config.test.js
var config = require(''./config.global'');
config.env = ''test'';
config.hostname = ''test.example'';
config.mongo.db = ''example_test'';
module.exports = config;
Usándolo en ./models/user.js:
var mongoose = require(''mongoose'')
, cfg = require(''../config'')
, db = mongoose.createConnection(cfg.mongo.uri, cfg.mongo.db);
Ejecutando su aplicación en entorno de prueba:
NODE_ENV=test node ./app.js
Esto se explica con mayor detalle aquí: http://www.chovy.com/node-js/managing-config-variables-inside-a-node-js-application/
Mucho más tarde, encontré un módulo Node.js bastante bueno para administrar la configuración: nconf .
Un ejemplo simple:
var nconf = require(''nconf'');
// First consider commandline arguments and environment variables, respectively.
nconf.argv().env();
// Then load configuration from a designated file.
nconf.file({ file: ''config.json'' });
// Provide default values for settings not provided above.
nconf.defaults({
''http'': {
''port'': 1337
}
});
// Once this is in place, you can just use nconf.get to get your settings.
// So this would configure `myApp` to listen on port 1337 if the port
// has not been overridden by any of the three configuration inputs
// mentioned above.
myApp.listen(nconf.get(''http:port''));
También admite el almacenamiento de configuraciones en Redis , la escritura de archivos de configuración, y tiene una API bastante sólida, y también está respaldada por una de las tiendas Node.js más respetadas, Nodejitsu , como parte de la iniciativa del marco Flatiron , por lo que debería ser bastante a prueba de futuro.
Echa un vistazo a nconf .
Para aquellos que están visitando este viejo hilo, aquí hay un paquete que me parece bueno.
Por mucho tiempo, solía usar el enfoque mencionado en la solución aquí. Sin embargo, existe una preocupación acerca de la seguridad de los secretos en texto claro. Puede usar otro paquete en la parte superior de la config
para que los bits de seguridad sean resueltos.
Vea esto: https://www.attosol.com/secure-application-secrets-using-masterkey-in-azure-key-vault/
Puede requerir archivos JSON a partir del Nodo v0.5.x (haciendo referencia a esta respuesta )
config.json:
{
"username" : "root",
"password" : "foot"
}
app.js:
var config = require(''./config.json'');
log_in(config.username, config.password);
Puede usar pconf: https://www.npmjs.com/package/pconf
Ejemplo:
var Config = require("pconf");
var testConfig = new Config("testConfig");
testConfig.onload = function(){
testConfig.setValue("test", 1);
testConfig.getValue("test");
//testConfig.saveConfig(); Not needed
}
Puede utilizar Konfig para archivos de configuración específicos del entorno. Carga los archivos de configuración json o yaml automáticamente, tiene valores predeterminados y funciones de configuración dinámica.
Un ejemplo de Konfig repo:
File: config/app.json
----------------------------
{
"default": {
"port": 3000,
"cache_assets": true,
"secret_key": "7EHDWHD9W9UW9FBFB949394BWYFG8WE78F"
},
"development": {
"cache_assets": false
},
"test": {
"port": 3001
},
"staging": {
"port": #{process.env.PORT},
"secret_key": "3F8RRJR30UHERGUH8UERHGIUERHG3987GH8"
},
"production": {
"port": #{process.env.PORT},
"secret_key": "3F8RRJR30UHERGUH8UERHGIUERHG3987GH8"
}
}
En desarrollo:
> config.app.port
3000
En producción, supongamos que iniciamos la aplicación con $ NODE_ENV=production PORT=4567 node app.js
> config.app.port
4567
Más detalles: Konfig
Recientemente lancé un pequeño módulo para cargar cualquier tipo de archivos de configuración. Es bastante sencillo, puede consultarlo en https://github.com/flesler/config-node
Sé que este es un post muy viejo. Pero quiero compartir mi módulo para configurar variables de entorno, creo que es una solución muy flexible. Aquí está el módulo json-configurator
var configJson = {
''baseUrl'': ''http://test.com'',
''$prod_baseUrl'': ''https://prod.com'',
''endpoints'': {
''users'': ''<%= baseUrl %>/users'',
''accounts'': ''<%= baseUrl %>/accounts''
},
foo: ''bar'',
foobar: ''foobar'',
$prod_foo: ''foo in prod'',
$test_foo: ''foo in test'',
deep:{
veryDeep: {
publicKey: ''abc'',
secret: ''secret'',
$prod_secret: ''super secret''
}
}
};
var config = require(''json-configurator'')(configJson, ''prod'');
console.log(config.deep.veryDeep.secret)
// super secret
console.log(config.endpoints.users)
// https://prod.com/users
Luego puede usar process.env.NODE_ENV
para obtener todas las variables para su entorno.
Simplemente use la npm
módulo npm
(más de 300000 descargas)
https://www.npmjs.com/package/config
Node-config organiza configuraciones jerárquicas para los despliegues de su aplicación.
Le permite definir un conjunto de parámetros predeterminados y ampliarlos para diferentes entornos de implementación (desarrollo, qa, organización de etapas, producción, etc.).
$ npm install config
$ mkdir config
$ vi config/default.json
{
// Customer module configs
"Customer": {
"dbConfig": {
"host": "localhost",
"port": 5984,
"dbName": "customers"
},
"credit": {
"initialLimit": 100,
// Set low for development
"initialDays": 1
}
}
}
$ vi config/production.json
{
"Customer": {
"dbConfig": {
"host": "prod-db-server"
},
"credit": {
"initialDays": 30
}
}
}
$ vi index.js
var config = require(''config'');
//...
var dbConfig = config.get(''Customer.dbConfig'');
db.connect(dbConfig, ...);
if (config.has(''optionalFeature.detail'')) {
var detail = config.get(''optionalFeature.detail'');
//...
}
$ export NODE_ENV=production
$ node index.js
Solo haz un settings.js
simple con las exports
:
exports.my_password = ''value''
Luego, en su guión, haga un require
:
var settings = require(''./settings.js'');
Todas sus configuraciones ahora estarán disponibles a través de la variable de settings
:
settings.my_password // ''value''
También puede buscar el punto dotenv que sigue los principios de una aplicación de doce factores .
Solía usar node-config, pero creé dotenv por esa razón. Fue completamente inspirado en la biblioteca dotenv de ruby.
El uso es bastante fácil:
var dotenv = require(''dotenv'');
dotenv.load();
Luego simplemente crea un archivo .env y coloca sus configuraciones allí, así:
S3_BUCKET=YOURS3BUCKET
SECRET_KEY=YOURSECRETKEYGOESHERE
OTHER_SECRET_STUFF=my_cats_middle_name
Eso es dotenv para nodejs.
También puede buscar en node-config que carga el archivo de configuración en función de la variable $ HOST y $ NODE_ENV (un poco como RoR): documentation .
Esto puede ser muy útil para diferentes configuraciones de implementación ( development
, test
o production
).
Un ejemplo alternativo que acabo de usar porque quería más flexibilidad que un archivo .json típico, pero no quería que se abstrajera en una biblioteca que requeriría una dependencia es algo como esto. Básicamente, la exportación de una función invocada inmediatamente devolvió un objeto con los valores que quería establecer. Da mucha flexibilidad.
module.exports = function(){
switch(node_env){
case ''dev'':
return
{ var1 = ''development''};
}
}();
Hay una explicación mucho mejor con el ejemplo completo aquí. Usando archivos de configuración en Node.js
Uso un package.json
para mis paquetes y un config.js
para mi configuración, que se ve así:
var config = {};
config.twitter = {};
config.redis = {};
config.web = {};
config.default_stuff = [''red'',''green'',''blue'',''apple'',''yellow'',''orange'',''politics''];
config.twitter.user_name = process.env.TWITTER_USER || ''username'';
config.twitter.password= process.env.TWITTER_PASSWORD || ''password'';
config.redis.uri = process.env.DUOSTACK_DB_REDIS;
config.redis.host = ''hostname'';
config.redis.port = 6379;
config.web.port = process.env.WEB_PORT || 9980;
module.exports = config;
Cargo la configuración de mi proyecto:
var config = require(''./config'');
y luego puedo acceder a mis cosas desde config.db_host
, config.db_port
, etc ... Esto me permite usar parámetros codificados o parámetros almacenados en variables de entorno si no quiero almacenar contraseñas en el control de fuente.
También genero un package.json
e inserto una sección de dependencias:
"dependencies": {
"cradle": "0.5.5",
"jade": "0.10.4",
"redis": "0.5.11",
"socket.io": "0.6.16",
"twitter-node": "0.0.2",
"express": "2.2.0"
}
Cuando cloné el proyecto en mi máquina local, npm install
para instalar los paquetes. Más información sobre eso here .
El proyecto se almacena en GitHub, con controles remotos agregados para mi servidor de producción.
Voy a lanzar mi sombrero al ring aquí porque ninguna de estas respuestas aborda todos los componentes críticos que prácticamente cualquier sistema necesita. Consideraciones:
- Configuración pública (que se puede ver en el frontend) vs configuración privada (guy mograbi acertó en esto). Y asegurando que estos se mantengan separados.
- Secretos como llaves
- Anulaciones predeterminadas vs específicas del entorno
- Paquetes Frontend
Así es como hago mi configuración:
-
config.default.private.js
: en el control de versiones, estas son opciones de configuración predeterminadas que solo puede ver su servidor. -
config.default.public.js
- En el control de versiones, estas son opciones de configuración predeterminadas que se pueden ver por el backend y el frontend -
config.dev.private.js
- Si necesita diferentes valores predeterminados privados para dev. -
config.dev.public.js
- Si necesita diferentes valores predeterminados públicos para dev. -
config.private.js
: no en el control de versiones, estas son opciones específicas del entorno que anulanconfig.default.private.js
-
config.public.js
: no en el control de versiones, estas son opciones específicas del entorno que anulanconfig.default.public.js
-
keys/
- Una carpeta donde cada archivo almacena un secreto diferente de algún tipo. Esto tampoco está bajo el control de versiones (las claves nunca deben estar bajo el control de versiones).
Utilizo los archivos javascript sin formato para la configuración, por lo que tengo toda la potencia del lenguaje javascript (incluidos los comentarios y la capacidad de hacer cosas como cargar el archivo de configuración predeterminado en el archivo específico del entorno para que puedan ser anulados). Si desea usar variables de entorno, puede cargarlas dentro de esos archivos de configuración (aunque recomiendo no usar env vars por la misma razón que no recomiendo usar archivos json; no tiene el poder de un lenguaje de programación para construir). su configuración).
La razón por la que cada clave está en un archivo separado es para el uso del instalador. Esto le permite tener un instalador que crea claves en la máquina y las almacena en la carpeta de claves. Sin esto, su instalador puede fallar cuando carga su archivo de configuración que no puede acceder a sus claves. De esta manera, puede atravesar el directorio y cargar cualquier archivo clave que se encuentre en esa carpeta sin tener que preocuparse por lo que existe y lo que no existe en ninguna versión dada de su código.
Como es probable que tenga las claves cargadas en su configuración privada, definitivamente no desea cargar su configuración privada en ningún código de frontend. Si bien es probable que sea estrictamente más ideal separar por completo el código base de tu interfaz de usuario, muchas veces, PITA es una barrera lo suficientemente grande como para evitar que las personas lo hagan, por lo tanto, configuración privada frente a pública. Pero hay dos cosas que hago para evitar que la configuración privada se cargue en la interfaz:
- Tengo una prueba de unidad que garantiza que mis paquetes frontend no contengan una de las claves secretas que tengo en la configuración privada.
- Tengo mi código de frontend en una carpeta diferente a mi código de backend, y tengo dos archivos diferentes llamados "config.js", uno para cada extremo. Para backend, config.js carga la configuración privada, para frontend, carga la configuración pública. Entonces, siempre solo necesita (''config'') y no se preocupe por su origen.
Una última cosa: su configuración debe cargarse en el navegador a través de un archivo completamente independiente de cualquiera de sus otros códigos frontend. Si agrupa su código de frontend, la configuración pública debe construirse como un paquete completamente separado. De lo contrario, su configuración ya no es realmente una configuración, solo es parte de su código. Config necesita poder ser diferente en diferentes máquinas.
Convict es otra opción que agrega un esquema para la validación. Al igual que nconf, admite la carga de configuraciones desde cualquier combinación de variables de entorno, argumentos, archivos y objetos json.
Ejemplo desde el README:
var convict = require(''convict'');
var conf = convict({
env: {
doc: "The applicaton environment.",
format: ["production", "development", "test"],
default: "development",
env: "NODE_ENV"
},
ip: {
doc: "The IP address to bind.",
format: "ipaddress",
default: "127.0.0.1",
env: "IP_ADDRESS",
},
port: {
doc: "The port to bind.",
format: "port",
default: 0,
env: "PORT"
}
});
Artículo de introducción : Taming Configurations with node-convicto
config.js
una carpeta como config un nombre de archivo como config.js
y luego config.js
este archivo donde sea necesario como se config.js
continuación
Ejemplo de config.js
module.exports = {
proxyURL: ''http://url:port'',
TWITTER: {
consumerkey: ''yourconsumerkey'',
consumerSecrete: ''yourconsumersecrete''
},
GOOGLE: {
consumerkey: ''yourconsumerkey'',
consumerSecrete: ''yourconsumersecrete''
},
FACEBOOK: {
consumerkey: ''yourconsumerkey'',
consumerSecrete: ''yourconsumersecrete''
}
}
Entonces si quiero usar este archivo de configuración en algún lugar
Primero voy a importar como abajo
var config = require(''./config'');
y puedo acceder a los valores de la siguiente manera
const oauth = OAuth({
consumer: {
key: config.TWITTER.consumerkey,
secret: config.TWITTER.consumerSecrete
},
signature_method: ''HMAC-SHA1'',
hash_function(base_string, key) {
return crypto.createHmac(''sha1'', key).update(base_string).digest(''base64'');
}
});