Skip to content

Commit c813d5f

Browse files
committed
docs: more information about rust and go usage
1 parent 0303c6e commit c813d5f

File tree

4 files changed

+344
-26
lines changed

4 files changed

+344
-26
lines changed

docs/.vuepress/config.js

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,7 @@ module.exports = {
4040
{
4141
title: 'Webpack',
4242
path: '/guide/webpack/',
43-
children: [
44-
'/guide/webpack/',
45-
'/guide/webpack/inject',
46-
'/guide/webpack/example',
47-
],
43+
children: ['/guide/webpack/', '/guide/webpack/inject', '/guide/webpack/example'],
4844
},
4945
{
5046
title: 'React Native',
@@ -59,16 +55,12 @@ module.exports = {
5955
{
6056
title: 'Specification',
6157
path: '/spec/',
62-
children: ['/spec/'],
58+
children: ['/spec/', '/spec/golang', '/spec/rust'],
6359
},
6460
{
6561
title: 'Releases',
6662
path: '/release-notes',
67-
children: [
68-
['/release-notes', 'Release Notes'],
69-
'/v2-announcement',
70-
'/v2-migration',
71-
],
63+
children: [['/release-notes', 'Release Notes'], '/v2-announcement', '/v2-migration'],
7264
},
7365
],
7466

@@ -79,12 +71,25 @@ module.exports = {
7971

8072
plugins: [
8173
['vuepress-plugin-mermaidjs', { theme: 'base' }],
82-
['vuepress-plugin-seo', {
83-
description: () => 'App Config is an Easy Configuration Loader with Strict Validation',
84-
author: () => 'Launchcode',
85-
image: () => 'https://app-config.dev/hero.png',
86-
tags: () => ['configuration', 'config', 'conf', 'app-config', 'launchcode', 'lcdev', 'node.js', 'javascript', 'typescript'],
87-
}],
74+
[
75+
'vuepress-plugin-seo',
76+
{
77+
description: () => 'App Config is an Easy Configuration Loader with Strict Validation',
78+
author: () => 'Launchcode',
79+
image: () => 'https://app-config.dev/hero.png',
80+
tags: () => [
81+
'configuration',
82+
'config',
83+
'conf',
84+
'app-config',
85+
'launchcode',
86+
'lcdev',
87+
'node.js',
88+
'javascript',
89+
'typescript',
90+
],
91+
},
92+
],
8893
],
8994

9095
host: '0.0.0.0',

docs/spec/README.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22
title: Specification
33
---
44

5+
## Specification
6+
57
This document defines the exact instructions required to be "App Config Compliant".
8+
69
What does that mean? App Config intends to be more than a library confined to the Node.js ecosystem.
7-
So in that spirit, we're providing instructions for language bindings to follow in order to interoperate.
10+
So in that spirit, we're providing instructions for **other programming languages** to follow in order to interoperate.
811

912
Does that mean we want N+1 ports of the App Config package? No, not really.
10-
This spec defines **minimal required support**, and App Config itself will be free to provide more features.
13+
This spec defines **minimal required support**, and App Config itself will be free to provide more features that are beyond that scope.
1114

1215
## High Level Overview
1316

@@ -22,15 +25,15 @@ So to be clear, **this spec will not define #1 or #4**. These are non-trivial
2225
parts of App Config, and would be a lot to replicate truthfully in every language.
2326

2427
Instead, we'll try to outline #2 and #3. These may not describe _every_ feature
25-
that the App Config library supports, but App Config should faithfully fulfil the requirements.
28+
that the App Config library supports, but App Config should faithfully fulfill the requirements.
2629

2730
## Loading App Config through an environment variable
2831

2932
App Config is defined as an environment variable. This variable is named `APP_CONFIG`.
3033
Libraries can support different names, but all should use `APP_CONFIG` by default.
3134

3235
This environment variable should be a string, containing text that can be parsed as JSON.
33-
This JSON value should an object. Libraries should reject invalid JSON strings or non-objects, if possible.
36+
This JSON value should an object. Libraries should reject invalid JSON strings or non-objects.
3437

3538
## JSON Schema Validation
3639

@@ -67,19 +70,18 @@ The App Config library intends to officially support as many of these libraries
6770
Primarily, we believe that we can leverage our existing tooling to "jump start" these efforts.
6871

6972
In many languages, it should be possible to dynamically **generate an App Config Compliant library for you**.
70-
This is especially easy in strongly typed languages, like golang, Rust or Java.
73+
This is especially easy in strongly typed languages, like Go, Rust or Java.
7174

72-
We're currently experimenting with:
75+
We're currently have built-in support for generating: **[Go](./golang.md)** and **[Rust](./rust.md)**.
7376

74-
- golang (using xeipuuv/gojsonschema)
75-
- rust (using valico)
77+
File a GitHub [issue](https://github.com/launchcodedev/app-config/issues/new) if you want support in your language of choice.
7678

7779
## Interoperation
7880

7981
We've defined a really small subset in this document. The last thing we want
8082
is to encourage not using the features of App Config. Instead, we want App Config
8183
to provide the tools you need for development. Features like `$extends` and `$env`
82-
are useful for developers, and be "erased" by the time your app goes to production.
84+
are useful for developers, and can be "erased" by the time your app goes to production.
8385
By not needing these features, language support can be simple.
8486

8587
The intention here, is for development to look like:

docs/spec/golang.md

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
---
2+
title: Go Support
3+
---
4+
5+
## App Config in Go
6+
7+
The Node.js `@lcdev/app-config` library has built-in support for generating go code.
8+
9+
1. Install it:
10+
11+
```sh
12+
npm i --save-dev @lcdev/app-config@2
13+
```
14+
15+
2. Add codegen instructions to the `.app-config.meta.yml` file:
16+
17+
```yaml
18+
generate:
19+
- file: ./pkg/app-config.go
20+
```
21+
22+
3. Run the code generation:
23+
24+
```sh
25+
npx @lcdev/app-config gen
26+
```
27+
28+
4. Use the config module!
29+
30+
```go
31+
port := GetConfig().Server.Port
32+
```
33+
34+
This will result in a type-safe struct that represents your config faithfully.
35+
It also validates the config against the App Config schema.
36+
37+
Typically, users will wrap usage of their app in the `@lcdev/app-config` CLI.
38+
For example:
39+
40+
```sh
41+
npx @lcdev/app-config -s -- go run .
42+
```
43+
44+
<br />
45+
46+
---
47+
48+
<br />
49+
50+
The generated code will look something like this:
51+
52+
```go
53+
// @generated by app-config
54+
55+
package main
56+
57+
import (
58+
"encoding/json"
59+
"errors"
60+
"fmt"
61+
"log"
62+
"os"
63+
64+
"github.com/xeipuuv/gojsonschema"
65+
)
66+
67+
var config Config
68+
69+
func init() {
70+
loadedConfig, err := LoadConfig()
71+
72+
if err != nil {
73+
log.Panic(err.Error())
74+
}
75+
76+
config = loadedConfig
77+
}
78+
79+
func GetConfig() Config {
80+
return config
81+
}
82+
83+
func LoadConfig() (Config, error) {
84+
var loadedConfig Config
85+
var loadedSchema map[string]interface{}
86+
var err error
87+
88+
configText := os.Getenv("APP_CONFIG")
89+
schemaText := os.Getenv("APP_CONFIG_SCHEMA")
90+
91+
if configText == "" {
92+
return loadedConfig, errors.New("The APP_CONFIG environment variable was not set")
93+
}
94+
95+
if schemaText == "" {
96+
return loadedConfig, errors.New("The APP_CONFIG_SCHEMA environment variable was not set")
97+
}
98+
99+
err = json.Unmarshal([]byte(schemaText), &loadedSchema)
100+
101+
if err != nil {
102+
return loadedConfig, fmt.Errorf("Could not parse APP_CONFIG_SCHEMA environment variable: %s", err.Error())
103+
}
104+
105+
err = json.Unmarshal([]byte(configText), &loadedConfig)
106+
107+
if err != nil {
108+
return loadedConfig, fmt.Errorf("Could not parse APP_CONFIG environment variable: %s", err.Error())
109+
}
110+
111+
schemaLoader := gojsonschema.NewGoLoader(loadedSchema)
112+
documentLoader := gojsonschema.NewGoLoader(loadedConfig)
113+
114+
result, err := gojsonschema.Validate(schemaLoader, documentLoader)
115+
116+
if err != nil {
117+
return loadedConfig, fmt.Errorf("Could not validate App Config: %s", err.Error())
118+
}
119+
120+
if !result.Valid() {
121+
errors := ""
122+
123+
for _, desc := range result.Errors() {
124+
if errors == "" {
125+
errors = fmt.Sprintf("%v", desc)
126+
} else {
127+
errors = fmt.Sprintf("%s, %v", errors, desc)
128+
}
129+
}
130+
131+
return loadedConfig, fmt.Errorf("The App Config value invalid: %s", errors)
132+
}
133+
134+
return loadedConfig, nil
135+
}
136+
137+
func UnmarshalConfig(data []byte) (Config, error) {
138+
var r Config
139+
err := json.Unmarshal(data, &r)
140+
return r, err
141+
}
142+
143+
func (r *Config) Marshal() ([]byte, error) {
144+
return json.Marshal(r)
145+
}
146+
147+
type Config struct {
148+
Jwt Jwt `json:"jwt"`
149+
Server Server `json:"server"`
150+
}
151+
152+
type Jwt struct {
153+
Secret string `json:"secret"`
154+
}
155+
156+
type Server struct {
157+
Port int64 `json:"port"`
158+
}
159+
```
160+
161+
You can specify the "no-singleton" option to avoid automatic (`init` function) config loading:
162+
163+
```yaml
164+
generate:
165+
- file: ./pkg/app-config.go
166+
rendererOptions:
167+
no-singleton: 'true'
168+
```
169+
170+
Note that code generation is not guaranteed to be deterministic between versions of app config.
171+
We'll do our best to be stable though, and output code that `gofmt` is happy with.

0 commit comments

Comments
 (0)