New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: std/env
with assertEnvSet()
and setEnvDefault()
#3874
Conversation
I think the name import { setDefault, assert } from "https://deno.land/std@$STD_VERSION/dotenv/mod.ts";
// sets a default value in Deno.env if the key does not already exist.
setDefault("foo", "bar")
// throws an error if value does not exist in Deno.env
assert("foo") |
Yeah, fair points. I wasn't certain about the name either. I very much like the idea of splitting this up into 2 separate functions too. How about the names |
Is the Maybe instead of But assuming the import is done like this: import * as env from "https://deno.land/std@$STD_VERSION/dotenv/mod.ts";
// sets a default value in Deno.env if the key does not already exist.
env.setDefault("foo", "bar")
// throws an error if value does not exist in Deno.env
env.assertExists("foo") seems pretty clear to me. |
I'm thinking the same now too. These functions would probably best done in a new
But that's not always how the functions will be imported. They may get imported from an intermediary For now, I've gone ahead with |
prepare()
std/env
with assertEnvSet()
and setEnvDefault()
ref emplace at stage 2. |
I'm -1 to this.
I don't think these can replace Also if (!Deno.env.has("FOO")) Deno.env.set("FOO", "BAR"); is clearer in my view than: import { setEnvDefault } from "std/env/mod.ts";
setEnvDefault("FOO", "BAR") |
Apologies for the mixup. To clarify, I hope for Perhaps, take a second look at I no longer argue triviality as a reason against adding something to the Standard Library. There are plenty of examples of trivial yet very useful APIs in the Standard Library. E.g. some functions in Instead, we should perhaps use usefulness (the chance that someone will need said functionality) as a metric. Seeing that people do in fact use This PR provides a more straightforward approach to satisfying these requirements. If triviality is still a concern, I was thinking of adding a |
From my observation, the features of checking required and supplying defaults are not essential part of I don't think providing these 2 APIs help people migrating from
To my understanding of the discussion in #3604, some people are in favor of keeping to use |
PTAL @timreichen, @jsejcksn, @cknight, @andrewthauer and @Leokuma. I'd like to hear what you guys think about this. |
I am unbiased about this. We also could just add a warning message in |
At a minimum, I would like to see both As for |
My understanding is that there is a continuum of use cases when working with plaintext files which consist of key-values pairs. At one end: a user wants as little configuration and as much "magic" as possible — they expect the offered API to figure out where their ".env" file is (maybe some cascade of expected locations) and load the pairs into the runtime environment variable dictionary/map/etc. At the opposite end: a user will somehow obtain a string of such data at some point during the program's lifecycle (or need to generate one!), and they need a clearly defined specification for the serialization/deserialization of the data, along with composable functional primitives to help with manually completing tasks which deal with key-value pairs and this format. It appears that Deno's For us: a clear challenge is to define exactly which combinations of primitives provide utility to users on the continuum, but I expect that the standard library will continue to offer primitives — and perhaps in the future: a de-/serialization specification so that (especially new) users can have confidence in the format of their env files without needing to fully review the source code of the module. The spec that I'm describing would exhaustively answer questions that many users have about the format, such as:
|
I'm going to close this PR for now. It seems as though we need a bit more discussion.
For future reference, let's try to stay on track with the issue at hand. While this is an interesting idea, it's best discussed in a new issue 🙂 |
This PR adds a new
std/env
sub-module withassertEnvSet()
andsetEnvDefault()
that, if accepted, replacesstd/dotenv
'sload()
, when used with the new--env
CLI argument.load()
does quite a bit. In short, it reads and parses a.env
file, ensures that it contains required environment variables as defined by a.env.example
, and sets any default environment variable values as defined by a.env.defaults
. Once done, it sets these environment variables in the current process. There's more to it than that, but that's the gist. Documentation here.assertEnvSet()
andsetEnvDefault()
perform a subset of this functionality, but in a fundamentally different and simpler way - by directly interacting withDeno.env
and defining required and default environment variable information in-code instead of in.env.*
files.It allows the Deno runtime to take care of actually loading the
.env
file, using the--env
CLI argument, and instead just checks the current processes environment variables set. In other words, these functions skip reading and parsing of.env
.Required environment variables and default environment variables are defined in-code instead of obscure
.env.*
. Previously,.env.*
files were saved to repos anyway. This is safe to do, as these specific values (required and defined env. vars.) are not confidential.One of the nice things about
load()
's approach is that by having environment variables in.env.*
files, one can copy and paste the keys to the actual.env
file in the correct format. WhenassertEnvSet()
throws because of a missing required environment variable, it also prints the error in the.env
format, reducing any possible guesswork regarding the environment variable the error refers to.I understand this differs from the
dotenv
convention, but I think it's a far simpler and cleaner way of ensuring environment variables are set up correctly.If accepted in favour of
load()
:load.ts
andmod.ts
when used together withrun --watch=
#2490