Skip to main content

Preprocessing functions

loadJsonFile

Commentary

added in 0.4.16

Special pre-processor function that loads JSON from other files. This is useful for splitting a large configuration into pieces so you can selectively pull in fragments, like constants or entire connection blocks.

This function can be used in one of two ways. First, you can use the file parameter to load a single file in place. 1 Second, you can use the files parameter to load a group of files and merge them together into a final map or array. 2

In either case, the paths listed must be fully-qualified to files inside the ShadowTraffic Docker container. So be sure to volume mount these files in addition to your base configuration.

You can also supply a data parameter to do simple primitive substitutions according to the Mustache spec. This is provided as a convenience. If you need something more sophisticated, use something like Jinja directly.

Note that pre-processing functions, like this one, don't evaluate function modifiers because they execute only once before runtime. So keys like elide and null are ignored.


Caveats

Static data

Note that the contents of data must either be static data or further preprocessor functions. Runtime functions won't be applied before data is passed into the loaded file. For example, in the configuration below, x will not receive the value 1, 2, or 3, but the raw oneOf map, which is probably not what you want.

{
"_gen": "loadJsonFile",
"file": "/data/subfile.json",
"data": {
"x": {
"_gen": "oneOf",
"choices": [1, 2, 3]
}
}
}

Instead, rewrite it so that the contents of subfile.json references a top-level variable.


Examples

Loading a file

Specify the file with a fully qualified path.

{
"topic": "sandbox",
"value": {
"_gen": "loadJsonFile",
"file": "/path/to/file.json"
}
}

When you load JSON files, you should see messages like the following on the console:

✝ ***
✝ Replacing JSON file /path/to/file.json at path [ "generators", 0, "value", "choices" ]
✝ ***

Merging files

Use files to merge multiple files together. All files must contain the same root types. This is useful if you want to break a generator or variables declaration into separate files, but ultimately use them all together.

  • If all files are maps, the maps are merged together, with latter maps taking priority over earlier maps.
  • If all files are arrays, the arrays are concatenated in the order listed.

For example, if file1.json contained:

{
"x": 1,
"y": 2
}

And file2.json contained:

{
"y": 3,
"z": 4
}

And you used the following load call:

{
"topic": "sandbox",
"value": {
"_gen": "loadJsonFile",
"files": [
"/path/to/file1.json",
"/path/to/file2.json"
]
}
}

The result would be:

{
"x": 1,
"y": 3,
"z": 4
}

When you merge JSON files, you should see messages like the following on the console:

✝ ***
✝ Merging JSON files [/path/to/file1.json, /path/to/file2.json] at path [ "generators", 0, "value", "choices" ]
✝ ***

Substitute fields

Use data to substitute primitives into the target file where names are denoted with {{ name }} expressions.

For example, /path/to/file.json should contain {{ variable }} and {{ expresssion }}, and will have "foo" and 42 substituted respectively.

{
"topic": "sandbox",
"value": {
"_gen": "loadJsonFile",
"file": "/path/to/file.json",
"data": {
"variable": "foo",
"expression": 42
}
}
}

Env variables as data

Before loadJsonFile runs, all other preprocessors run. In this example, the environment variable PORT is evaluated as data before it loads the secondary JSON file.

{
"topic": "sandbox",
"value": {
"_gen": "loadJsonFile",
"file": "/path/to/file.json",
"data": {
"port": {
"_gen": "env",
"var": "PORT"
}
}
}
}

Specification

JSON schema

{
"type": "object",
"properties": {
"file": {
"type": "string"
},
"files": {
"type": "array",
"items": {
"type": "string"
}
}
},
"oneOf": [
{
"required": [
"file"
]
},
{
"required": [
"files"
]
}
]
}