build your own deno-dotenv module
Mohamed Amine Griche
Posted on June 24, 2020
Hello DEV,
In the last post we have seen how we can create a REST API
using Deno
with oak
.
Here is the post Simple REST API with Deno if you want to take a look at it.
Today we are going to build a deno-dotenv
module inspired from the node dotenv module
What is the node dotenv
module ?
Dotenv is a zero-dependency module that loads environment variables from a
.env
file intoprocess.env
. Storing configuration in the environment separate from code is based on The Twelve-Factor App methodology.
for more information: check it's page on npm and it's repository on github.
what is a .env file ?
.env
is the file that contains the environment variables you want to load to your application, each line of the .env file has this formatKEY=VALUE
example:
HOST=https://www.example.com
PORT=7700
KEY=J46Sq8r4s5d9
With that out of the way, let's get started by defining the steps to create this module:
The main steps
These are the main steps to build this module:
- Read the content from the
.env
. - Parse the environment variables from the content.
- Set environment variables in
Deno.env
.
1. Read the content from the .env
:
Let's start by creating the mod.ts
file and add this function to it
const readFileToStrSync = (filePath: string): string => {
const bytes = Deno.readFileSync(filePath)
const fileContent = new TextDecoder("utf-8").decode(bytes)
return fileContent
}
NOTE: You can name the file however you want, but as a best practice we are going to stick to mod.ts
What does this function do is:
- Synchronously reads and returns the entire content of a file as an array of bytes. using the
Deno.readFileSync(filePath)
function. - Convert the array of bytes to a string using the
new TextDecoder("utf-8").decode(bytes)
method. - return the content of the file a string.
Now that we have the .env
file content let's parse the environment variables in it.
2. Parse the environment variables:
To do that let's add the parse
function to the mod.ts
file
const LINE_BREAK: RegExp = /\r\n?|\n/
const parse = (envContent: string): string[][] => {
const envList = envContent.split(LINE_BREAK)
let parsedContent: string[][] = []
for ( let i = 0; i < envList.length; i++) {
parsedContent.push(envList[i].split("="))
}
return parsedContent
}
what does this code do is:
- The
LINE_BREAK
is a regular expression that matches the line break. - The
parse
function takes the content of the.env
file as a parameter of type string ( the string returned from the previous functionreadFileStrSync
), split the content into separate lines ( because each line contain one environment variable with the structureKEY=VALUE
) using thesplit
function withLINE_BREAK
RegExp as a parameter, then loop throw all the lines and retrieve theKEY
and theVALUE
in a form of an array of strings[KEY, VALUE]
and push it to the two-dimensional arrayparsedContent
which will be returned when the loop is completed.
Now we have the environment variables in a form of a two-dimensional array, all we have left to do is to set it to the Deno.env
so it will be accessible in all the application.
3. Set the environment variables in Deno.env
:
Now, let's add the setEnv
function to the mod.ts
file
const setEnv = (parsedEnv: string[][]): void => {
for (let i = 0; i < parsedEnv.length; i++) {
Deno.env.set(parsedEnv[i][0], parsedEnv[i][1])
}
}
This function takes the environment variables in a form of a two-dimensional array ( returned from the parse
function ) and add them to the Deno.env
object with the Deno.env.set()
function.
Now we have all the functions we need created, but they are not doing anything yet, they have to collaborate with each other to provide the functionality we are looking for. So let's just create a function to do that let's give a name of dotenv
const dotenv = (envFilePath?:string) => {
const filePath: string = envFilePath || ".env"
const fileContent = readFileToStrSync(filePath)
const parsedEnv = parse(fileContent)
setEnv(parsedEnv)
}
This function take an optional parameter envFilePath
which is the path to the .env
file ( if it's provided the function will use it, if not the function will use '.env' as a path value ), then using this path filePath
to read the content of the .env
file synchronously using the readFileToStrSync(filePath)
, then parse the result using the parse(fileContent)
function, then uses the parsed result in the setEnv(parsedEnv)
function to set the environment variables in the Deno.env
object.
4. Finally export
Now that we have the functionality create and ready, we need just to export the dotenv
function so the users can use it in their apps.
export default dotenv
# Let's test the module
First create a .env
file and add some KEY=VALUE
pairs, something like:
PASSWORD=1234567
KEY=12T1S654Ts6sc5fsd4Q6np9dx2A
Then create a typescript file, call it test.ts
or however you want, import the dotenv
function from the dotenv
module we just created, and execute it, so that the environment variables will be available to use from the Deno.env
object
import dotenv from "./mod.ts"
// or you can use import if from this URL
// import dotenv from "https://raw.githubusercontent.com/AM-77/deno-dotenv/master/mod.ts"
dotenv()
now create a snapshot of the environment variables from the Deno.env
using the Deno.env.toObject()
function and just use it:
const env = Deno.env.toObject()
console.log("PASSWORD: ", env.PASSWORD)
console.log("KEY: ", env.KEY)
Run your test.ts
using the flags --allow-read
--allow-env
$ deno run --allow-read --allow-env test.ts
PASSWORD: 1234567
KEY: 12T1S654Ts6sc5fsd4Q6np9dx2A
And that's all, we are finished. Thank you.
Here is the source code (I re-factored it a little bit).
Posted on June 24, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.