Skip to content

Commit 021a772

Browse files
authored
Error signature refactoring (#6)
- Refactors to a `val, err := Get("ENV")` based signature - Changes most functions to a `val, err` signature to match this - Breaks code into functional files for sanity - Provides `Get` alias `GetString` for convention - Renames `GetSlice` to `GetStringSlice` and supports more types - Adds support for multiple `default` slice values through `default=[one,two,three]` - Does not require the brackets if there is only 1 default item.
1 parent 577c2ff commit 021a772

File tree

10 files changed

+1241
-684
lines changed

10 files changed

+1241
-684
lines changed

README.md

Lines changed: 124 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,24 @@
44
[![codecov](https://codecov.io/gh/syntaqx/env/graph/badge.svg?token=m4bBKy3UG3)](https://codecov.io/gh/syntaqx/env)
55
[![Go Report Card](https://goreportcard.com/badge/github.com/syntaqx/env)](https://goreportcard.com/report/github.com/syntaqx/env)
66

7-
`env` is an environment variable utility package for Go.
7+
`env` is an environment variable utility package for Go. It provides simple
8+
functions to get and set environment variables, including support for
9+
unmarshalling environment variables into structs with support for nested
10+
structures, default values, and required fields.
11+
12+
## Features
13+
14+
- __Basic Get/Set__: Simple functions to get, set, and unset environment variables.
15+
- __Type Conversion__: Functions to get environment variables as different types (int, bool, float).
16+
- __Fallback Values__: Support for fallback values if an environment variable is not set.
17+
- __Unmarshal__: Load environment variables into structs using struct tags.
18+
- __Nested Structs__: Support for nested struct prefixes to group environment variables.
19+
20+
## Installation
21+
22+
```sh
23+
go get github.com/syntaqx/env
24+
```
825

926
## Usage
1027

@@ -24,8 +41,12 @@ func main() {
2441

2542
// Assuming the value of HOSTS is a comma-separated list of strings
2643
// Example: some-host:8000,another-host:8000
27-
hosts := env.GetSliceWithFallback("HOSTS", []string{"fallback-host-1:8000", "fallback-host-2:8000"})
28-
fmt.Printf("Hosts: %v\n", hosts)
44+
hosts, err := env.GetStringSliceWithFallback("HOSTS", []string{"fallback-host-1:8000", "fallback-host-2:8000"})
45+
if err != nil {
46+
fmt.Printf("Error getting hosts: %v\n", err)
47+
} else {
48+
fmt.Printf("Hosts: %v\n", hosts)
49+
}
2950
}
3051
```
3152

@@ -39,51 +60,63 @@ and `required` to enforce that an environment variable must be set.
3960
package main
4061

4162
import (
42-
"fmt"
43-
"log"
63+
"fmt"
64+
"log"
4465

45-
"github.com/syntaqx/env"
66+
"github.com/syntaqx/env"
4667
)
4768

4869
type DatabaseConfig struct {
49-
Host string `env:"DATABASE_HOST,default=localhost"`
50-
Port int `env:"DATABASE_PORT|DB_PORT,fallback=3306"`
51-
Username string `env:"DATABASE_USERNAME,default=root"`
52-
Password string `env:"DATABASE_PASSWORD,required"`
53-
Database string `env:"DATABASE_NAME"`
70+
Host string `env:"DATABASE_HOST,default=localhost"`
71+
Port int `env:"DATABASE_PORT|DB_PORT,fallback=3306"`
72+
Username string `env:"DATABASE_USERNAME,default=root"`
73+
Password string `env:"DATABASE_PASSWORD,required"`
74+
Database string `env:"DATABASE_NAME"`
5475
}
5576

5677
type Config struct {
57-
Debug bool `env:"DEBUG"`
58-
Port string `env:"PORT,default=8080"`
78+
Debug bool `env:"DEBUG"`
79+
Port string `env:"PORT,default=8080"`
5980
Database DatabaseConfig
6081
}
6182

6283
func main() {
63-
var cfg Config
64-
65-
// Set example environment variables
66-
_ = env.Set("DEBUG", "true")
67-
_ = env.Set("PORT", "9090")
68-
_ = env.Set("DATABASE_HOST", "dbhost")
69-
_ = env.Set("DATABASE_PORT", "5432")
70-
_ = env.Set("DATABASE_USERNAME", "admin")
71-
_ = env.Set("DATABASE_PASSWORD", "secret")
72-
_ = env.Set("DATABASE_NAME", "mydb")
73-
74-
if err := env.Unmarshal(&cfg); err != nil {
75-
log.Fatalf("Error unmarshalling config: %v", err)
76-
}
77-
78-
fmt.Printf("Config: %+v\n", cfg)
84+
var cfg Config
85+
86+
// Set example environment variables
87+
_ = env.Set("DEBUG", "true")
88+
_ = env.Set("PORT", "9090")
89+
_ = env.Set("DATABASE_HOST", "dbhost")
90+
_ = env.Set("DATABASE_PORT", "5432")
91+
_ = env.Set("DATABASE_USERNAME", "admin")
92+
_ = env.Set("DATABASE_PASSWORD", "secret")
93+
_ = env.Set("DATABASE_NAME", "mydb")
94+
95+
if err := env.Unmarshal(&cfg); err != nil {
96+
log.Fatalf("Error unmarshalling config: %v", err)
97+
}
98+
99+
fmt.Printf("Config: %+v\n", cfg)
79100
}
80101
```
81102

82103
### Nested Struct Prefixes
83104

84-
You can use nested prefixes to group environment variables. For example, you can
105+
You can use nested prefixes to group environment variables. This allows you to
106+
reuse the same struct in multiple places without having to worry about
107+
conflicting environment variables.
108+
85109

86110
```go
111+
package main
112+
113+
import (
114+
"fmt"
115+
"log"
116+
117+
"github.com/syntaqx/env"
118+
)
119+
87120
type DatabaseConfig struct {
88121
Host string `env:"HOST,default=localhost"`
89122
Port int `env:"PORT,fallback=3306"`
@@ -93,20 +126,72 @@ type DatabaseConfig struct {
93126
}
94127

95128
type Config struct {
96-
Debug bool `env:"DEBUG"`
97-
Port string `env:"PORT,default=8080"`
98-
Database DatabaseConfig `env:"DATABASE"`
129+
Debug bool `env:"DEBUG"`
130+
Port string `env:"PORT,default=8080"`
131+
ReadDatabase DatabaseConfig `env:"READ_DATABASE"`
132+
WriteDatabase DatabaseConfig `env:"WRITE_DATABASE"`
133+
}
134+
135+
func main() {
136+
var cfg Config
137+
138+
// Set example environment variables
139+
_ = env.Set("DEBUG", "true")
140+
_ = env.Set("PORT", "9090")
141+
_ = env.Set("READ_DATABASE_HOST", "read-dbhost")
142+
_ = env.Set("READ_DATABASE_PORT", "5432")
143+
_ = env.Set("READ_DATABASE_USERNAME", "read-admin")
144+
_ = env.Set("READ_DATABASE_PASSWORD", "read-secret")
145+
_ = env.Set("READ_DATABASE_NAME", "read-mydb")
146+
_ = env.Set("WRITE_DATABASE_HOST", "write-dbhost")
147+
_ = env.Set("WRITE_DATABASE_PORT", "5432")
148+
_ = env.Set("WRITE_DATABASE_USERNAME", "write-admin")
149+
_ = env.Set("WRITE_DATABASE_PASSWORD", "write-secret")
150+
_ = env.Set("WRITE_DATABASE_NAME", "write-mydb")
151+
152+
if err := env.Unmarshal(&cfg); err != nil {
153+
log.Fatalf("Error unmarshalling config: %v", err)
154+
}
155+
156+
fmt.Printf("Config: %+v\n", cfg)
157+
}
158+
```
159+
160+
### Slice Types Defaults
161+
162+
When using slice types, if you are declaring a single value as the default you
163+
can use the `default` tag as normal:
164+
165+
```go
166+
type Config struct {
167+
Hosts []string `env:"HOSTS,default=localhost"`
99168
}
100169
```
101170

102-
While will prefix the environment variables in the `DatabaseConfig` struct
103-
with `DATABASE_` as they are looked for. This allows you to reuse the same
104-
struct in multiple places without having to worry about conflicting environment
105-
variables.
171+
However if you want to declare multiple values as the default, you must enclose
172+
the values in square brackets:
106173

107174
```go
108175
type Config struct {
109-
ReadDatabase DatabaseConfig `env:"WRITE_DATABASE"`
110-
WriteDatabase DatabaseConfig `env:"READ_DATABASE"`
176+
Hosts []string `env:"HOSTS,default=[localhost,localhost2]
111177
}
112178
```
179+
180+
This is necessary as the pacakge uses commas as a delimiter to split the struct
181+
tag options, and without the square brackets it would split the values into
182+
multiple tags.
183+
184+
```go
185+
type Config struct {
186+
Hosts []string `env:"HOSTS,default=[localhost,localhost2],required"
187+
}
188+
```
189+
190+
## Contributing
191+
192+
Feel free to open issues or contribute to the project. Contributions are always
193+
welcome!
194+
195+
## License
196+
197+
This project is licensed under the MIT license.

0 commit comments

Comments
 (0)