Data Sources: $file, $ref and $api
A value in data, in the json section or in the mapping file does not have to be written out. Three special keys take it from somewhere else: $file from another file, $ref from another part of the same document, and $api from a web address.
Reading other files: $file
data can load another file's content as a variable:
"js/entities.js": [
{
target: "entities.js",
data: { entities: { "$file": "target://entities.json5" } },
},
],
The file is parsed as JSON5 and the parsed value is injected, so the file has to be JSON or JSON5. It works
at any depth inside data.
| Prefix | Reads from |
|---|---|
target:// (default) | the folder you generate into, including files this very run has just produced |
template:// | the template folder |
project:// | the project root |
A file that is missing, blank or cannot be parsed gives an empty list ([]), with at most a warning in the
generation log, not an error. If a loop over it renders nothing, check the path and the file's syntax.
Reuse and fetch data: $ref and $api
Two special keys can stand in for a value. Both work in the json section (the JSON area of the first wizard step) and anywhere in codebaker.advanced.json5. They are resolved in step 2 of the dialog, under "Resolving JSON References and APIs". $api is resolved first, so a $ref can point into data that $api has fetched.
$ref: reuse a block
$ref is replaced by another part of the same document, so a block is written once:
json: {
defaults: { type: "text", required: false },
fields: [
{ "$ref": "#/defaults", name: "title" },
{ "$ref": "#/defaults", name: "notes", hint: "optional" },
],
}
Both fields get type and required from defaults, plus their own keys.
- The value is a JSON Pointer that starts with
#.#/defaultsis thedefaultskey at the top,#/fields/0/namegoes into a list by index, and#alone is the whole document. In a key that contains/or~, write~1for/and~0for~. - The pointer starts from the top of the document the
$refis in: the whole JSON area, or the whole advanced file. A$refin the mapping file cannot point into the JSON area. Other kinds of reference, such as a file name or a URL, are not supported and give an error. - If the target is an object, it is merged with the other keys written next to the
$ref. If the target is a list or a single value, it replaces the entry and the other keys are dropped. - A
$refmay point at another$ref. A pointer that is missing, or a reference that ends up pointing back to itself, stops with an error that names it.
When the referenced object and the entry have the same key, the value from the referenced object is used, not the one next to the $ref. So { "$ref": "#/defaults", required: true } stays required: false. To let an entry override a default, keep that key out of the referenced block.
$api: fetch JSON from a web address
$api is replaced by the JSON that a web address returns:
json: {
// Short form: a GET request
countries: { "$api": "https://example.com/api/countries" },
// Full form, with headers
posts: {
"$api": {
method: "POST",
url: "https://example.com/api/query",
headers: { "X-Api-Key": "..." },
},
},
// Full form, with Basic authentication
orders: {
"$api": {
url: "https://example.com/api/orders",
auth: { type: "basic", user: "alex", password: "{{ apiPassword }}" },
},
},
}
- The short form is a GET. In the full form
urlis required,methodisGET(the default) orPOST, andheadersis an object of strings. A POST sends no body. authwithtype: "basic"sends anAuthorization: Basic ...header built fromuserandpassword(UTF-8, so non-English characters work; a missingpasswordmeans an empty one). A header you write out inheaders, includingAuthorization, wins overauth.basicis the only type for now. For a token, use a header:headers: { Authorization: "Bearer ..." }.- The response must be JSON. It replaces the whole entry: other keys written next to
$apiare dropped. A list response becomes a list. - The address must be
http://orhttps://. The request waits at most 5 seconds. A failure (an HTTP status of 400 or more, a timeout, a response that is not JSON) stops the generation with an error message in step 2. - In the mapping file the address can contain variables, for example
"https://example.com/api/{{ kind }}", because that file is rendered before it is read. The same goes for the JSON area. - The request is made every time the step runs, so the result can change between runs.
A template is committed to Git and shared, so a password written in codebaker.config.json5 or codebaker.advanced.json5 is visible to everyone who has the repository. Put the secret in a field instead: declare apiPassword: "" under vars, use {{ apiPassword }} as above, and each user types it in the dialog.
The history stores what you type. CodeBaker remembers the values entered in the dialog, in the template's .history folder inside the project, and does not encrypt them. Add .history to your .gitignore so a secret typed there is never committed.
The generation log hides secrets: an Authorization header is shown as Basic ****, headers whose name contains key, token, secret or password as ****, and a user:password@ part or a secret-looking query value in the address is masked too. The request itself is sent as written.
And as with any template, be careful with ones you did not write: $api makes a request to whatever address the template names.
Next
- JSON Upsert: a file that another entry reads with
$file. - Security: what a template can and cannot do, including what
$apican reach. - Configuration Reference: the
jsonsection.