进程- env- parser
直取和型式安全环境变量验证、解析和
调试 node 应用.
const result = parseEnvironmentVariables({
API_KEY: { mask: true, default: null },
DATABASE_URL: { parser: s => new URL(s), mask: Mask.url("password") },
LISTEN_PORT: { parser: parseInt, default: 3000 },
SERVICE_NAME: {}
});
if (result.success) {
// Sample success output
console.table(result.envPrintable);
// ┌──────────────┬─────────────────────────────────────────────────────┐
// │ (index) │ Values │
// ├──────────────┼─────────────────────────────────────────────────────┤
// │ API_KEY │ '<masked>' │
// │ DATABASE_URL │ '<masked: "mysql://user:*****@localhost:3306/app">' │
// │ LISTEN_PORT │ '8080' │
// │ SERVICE_NAME │ '"app"' │
// └──────────────┴─────────────────────────────────────────────────────┘
// Inferred type for successfully parsed environment
// {
// API_KEY: string | null
// DATABASE_URL: URL
// LISTEN_PORT: number
// SERVICE_NAME: string
// }
return result.env;
} else {
// Sample formatted output
console.log(Formatter.multiLine(result));
// API_KEY = <masked>
// DATABASE_URL = <parser: "Invalid URL: localhost">
// LISTEN_PORT = 3000 (default)
// SERVICE_NAME = <missing>
throw new Error("Could not parse environment variables");
}
理由
在每个进程开始时,有两个投入来源可以影响 进程执行:程序参数,以及环境变量.
$ ENV_VAR_A=Hello ENV_VAR_B=World node app.js arg1 arg2 --arg3
为了建立可靠的软件, 并尽量减少运行时间惊喜,你会 想跟随 故障快速设计 财务报告和审定财务报表 确保您的程序输入尽早正确。 。 。 . 程序之后所做的一切都是基于这些投入.
例如,确保所需的数据库 URL 正确传递到 程序一开始就会提醒用户注意可能的问题, 而不是30分钟后应用程序在数据库连接时崩溃 这是第一次.
此库试图为处理环境提供有用的工具 启动的可变部分.
安装和使用
$ npm install --save @absxn/process-env-parser
import {
parseEnvironmentVariables,
requireEnvironmentVariables
} from "@absxn/process-env-parser";
两个功能都一样 Success | Fail 对象 :
// Types roughly as follows, read code and inline documentation for details
type Success = {
success: true;
env: {
[variableName: string]:
| InferredParserFunctionReturnType // If `parser` option used
| InferredDefaultValueType // If `default` option used
| string; // No options used
};
envPrintable: {
// Human readable results for logging and debugging
// E.g. `ENV_VAR_A=<missing>, ENV_VAR_B="World", PASSWORD=<masked>`
[variableName: string]: string;
};
};
type Fail = {
success: false;
// Same as for Success
envPrintable: { [variableName: string]: string };
};
实例
成功:带有强制变量的简单使用
最容易读取变量的方法是使用
requireEnvironmentVariables(...variableNames: string[])。读取给
变量,必须找到全部变量,并返回它们的值作为字符串.
要取得成功,所有列出的变量必须存在于环境中
进程启动
$ A=hello B=world node app
代码
// Type: Success | Fail
const result = requireEnvironmentVariables("A", "B");
if (result.success) {
console.table(result.envPrintable);
// ┌─────────┬───────────┐
// │ (index) │ Values │
// ├─────────┼───────────┤
// │ A │ '"hello"' │
// │ B │ '"world"' │
// └─────────┴───────────┘
// Type: { A: string, B: string }
// Value: { A: "hello", B: "world" }
return result.env;
} else {
// Wont get here since we gave both A and B in the startup
}
成功:可选和解析的变量
如果您的变量设置更为复杂, 您可以使用
parseEnvironmentVariables(config: Config)。这使您可以处理每个
具有额外功能的变量.
这个 config 对象以可变名称为按键,该值为对象
指定如何处理该变量.
现有备选办法如下:
interface Config {
[variableName: string]: {
// If variable is not found, use this as its value. If `default` not
// given, variable is mandatory, in which case, a missing variable leads
// to Fail being returned. If default value was used, envPrintable will
// have " (default)" appended to the printable value.
default?: any;
// When variable is read, its value is passed first to the parser
// function. Return value of the parser is used as the variable value in
// the output. If the parser throws, the function will return a Fail
// object.
parser?: (value: string) => any;
// If `true`, the value of the variable is never shown in plain text in
// the `envPrintable` fields of the return object. Value is indicated as
// `<masked>`. If function, the argument is 1) return value of parser 2)
// environment variable value. Default value bypasses the function and gets
// displayed as `<masked> (default)`. Return value of the function is the
// value to be shown in `envPrintable`, formatted as <masked: "value">.
mask?: boolean | (value: any) => string;
};
}
要取得成功:
- 所有变种没有
default必须在环境中存在- 空字符串
""被认为是不存在的!
- 空字符串
- 没有
parser可能抛出- 解析器例外变为结果
Fail而例外消息为 被俘虏envPrintable字段。 见下文实例.
- 解析器例外变为结果
默认值用于当前, 当 parser 给出时也是如此, 即默认值是 使用时未传递到解析器.
进程启动
$ REQUIRED=value PARSED=12345 node app
代码
// Ensure we return only valid numbers
function parser(s: string): number {
const p = parseInt(s);
if (isNaN(p)) {
throw new Error("Not a number");
} else {
return p;
}
}
const result = parseEnvironmentVariables({
REQUIRED: {},
PARSED: { parser },
OPTIONAL: { default: "OPTIONAL" }
});
if (result.success) {
console.table(result.envPrintable);
// ┌──────────┬────────────────────────┐
// │ (index) │ Values │
// ├──────────┼────────────────────────┤
// │ REQUIRED │ '"value"' │
// │ PARSED │ '1234' │
// │ OPTIONAL │ '"OPTIONAL" (default)' │
// └──────────┴────────────────────────┘
// Type: { REQUIRED: string, PARSER: number, OPTIONAL: "OPTIONAL" | string }
// Value: { REQUIRED: "value", PARSED: 1234, OPTIONAL: "OPTIONAL" }
return result.env;
} else {
// Will not get here
}
失败: 变量缺失
进程启动
$ VAR_A=value VAR_B= VAR_C="${X} ${Y} ${Z}" node app
警告 — “ 无意义” 字符串的特殊情况 :
- 空字符串 :
VAR_B也被视为失踪。 I.e. (英语).process.env.VAR_B但解析器认为""等于未设置. - 空白字符串 :
VAR_C也被视为没有设定。 在这种情况下,X, (中文(简体) ),Y, (中文(简体) ),Z这些都是"",因此产生的值为VAR_C两个空间," "如果值被空格所包围,例如:." A ",空间是 保存在解析器中.
代码
const result = requireEnvironmentVariables("VAR_A", "VAR_B", "VAR_C", "VAR_D");
if (result.success) {
// Won't get there
} else {
console.table(result.envPrintable);
// ┌─────────┬─────────────┐
// │ (index) │ Values │
// ├─────────┼─────────────┤
// │ VAR_A │ '"value"' │
// │ VAR_B │ '<missing>' │
// │ VAR_C │ '<missing>' │
// │ VAR_D │ '<missing>' │
// └─────────┴─────────────┘
}
失败: 解析器投掷
进程启动
$ NOT_ACTUAL_NUMBER=xyz node app
代码
function parser(s: string): number {
const p = parseInt(s);
if (isNaN(p)) {
throw new Error("Not a number");
} else {
return p;
}
}
const result = parseEnvironmentVariables({
NOT_ACTUAL_NUMBER: { parser }
});
if (result.success) {
// Won't get there
} else {
console.table(result.envPrintable);
// ┌───────────────────┬────────────────────────────┐
// │ (index) │ Values │
// ├───────────────────┼────────────────────────────┤
// │ NOT_ACTUAL_NUMBER │ '<parser: "Not a number">' │
// └───────────────────┴────────────────────────────┘
}
口罩
用于隐藏输出变量部分的帮助工具.
import { Mask } from "@absxn/process-env-parser";
url()
返回将遮盖应用到给定的 URL 部件的函数 .
有效的 URL 部件为 "hash", (中文(简体) ), "hostname", (中文(简体) ), "password", (中文(简体) ), "pathname", (中文(简体) ),
"port", (中文(简体) ), "protocol", (中文(简体) ), "search",以及 "username"。可以处理两个 URL
字符串和 URL 对象(来自 parser 或者说 default) (中文(简体) ).
const result = parseEnvironmentVariables({
API_URL: { parser: s => new URL(s), mask: Mask.url("password", "path") }
});
对于 API_URL=https://user:[email protected]/api/path,则 envPrintable 将
包含 { API_URL: "https://user:*****@1.2.3.4/*****" }。 。 。 .
urlPassword()
与 url("password"),导致
"protocol://user:*****@hostname/api/path"
urlUsernameAndPassword()
与 url("username", "password"),导致
"protocol://*****:*****@hostname/api/path"。 。 。 .
组合
操作解析结果的助手 .
import { Combine } from "@absxn/process-env-parser";
非无核
如果有一组环境变量互相依赖,即:. 您或需要全部,或不需要,此功能有助于确保 那个.
“ Nullable” 这里由 TypeScript 定义 NonNullable<T>也就是说, null 或者说
undefined。 。 。 .
假设我们有这样的设置:
function getConfig() {
// For parsing purposes, both USERNAME and PASSWORD are optional...
const result = parseEnvironmentVariables({
DATABASE: {},
USERNAME: { default: null },
PASSWORD: { default: null }
});
if (!result.success) {
return null;
}
const { DATABASE, USERNAME, PASSWORD } = result.env;
return {
// ... but for actual authentication, you need both
auth: Combine.nonNullable({ USERNAME, PASSWORD }),
db: DATABASE
};
}
使用特定启动参数,我们会得到以下结果:
$ DATABASE=db USERNAME=user PASSWORD=pass node app
getConfig() -> { auth: { USERNAME: "user", PASSWORD: "pass" }, db: "db" }
$ DATABASE=db node app
getConfig() -> { auth: null, db: "db" }
$ DATABASE=db USERNAME=user node app
getConfig() -> new Error("Mix of non-nullable (USERNAME) and nullable (PASSWORD) values")
$ node app
getConfig() -> null
如果对象被返回, 返回类型会从每个对象中移除无效性 值 :
// Type before: { a: string | null, b: number | undefined }
const nullableValues = {
a: Math.random() > 0.5 ? "X" : null,
b: Math.random() > 0.5 ? 1 : undefined
};
// Type after: {a: string, b: number} | null
const nonNullableValues = Combine.nonNullable(nullableTypes);
主题
库包含打印解析器的额外帮助功能 结果。 这些可以用于将启动配置存储到日志中 或打印出启动失败的原因.
导入 Formatter 从软件包中:
import { Formatter } from "@absxn/process-env-parser";
console.table()
作为一个内在的, console.table() 是最容易从中获取可读垃圾的方法
解析结果.
const result = requireEnvironmentVariables("VARIABLE"/*, ...*/);
console.table(result.envPrintable);
// ┌──────────┬─────────┐
// │ (index) │ Values │
// ├──────────┼─────────┤
// │ VARIABLE │ 'value' │
// │ ... │ ... │
// └──────────┴─────────┘
单词
使用第一个示例的数据:
const result = parseEnvironmentVariables({
API_KEY: { mask: true, default: null },
DATABASE_URL: { parser: s => new URL(s).toString() },
LISTEN_PORT: { parser: parseInt, default: 3000 },
SERVICE_NAME: {}
});
console.log(Formatter.oneliner(result));
// if (result.success === true):
// > API_KEY=<masked>, DATABASE_URL="mysql://localhost:3306/app", LISTEN_PORT=8080, SERVICE_NAME="app"
// else:
// > API_KEY=<masked>, DATABASE_URL=<parser: "Invalid URL: localhost">, LISTEN_PORT=3000, SERVICE_NAME=<missing>
多线
使用上述数据输出:
console.log(Formatter.multiLine(result));
// if (result.success === true):
// > API_KEY = <masked>
// DATABASE_URL = "mysql://localhost:3306/app"
// LISTEN_PORT = 8080
// SERVICE_NAME = "app"
// else:
// > API_KEY = <masked> (default)
// DATABASE_URL = <parser: "Invalid URL: localhost">
// LISTEN_PORT = 3000 (default)
// SERVICE_NAME = <missing>