Right now caddy2 has two config adapters: Caddyfile and JSON.
I have to admit, that I am not a big fan of json, because it's not possible to insert comments and it's difficult to write manual.
JSON is a format that should be used only from one computer to another.
I know that there is caddyfile config support, but the documentation says that the caddyfile support is not complete (there are certain options that will be only configurable via JSON).
So how to resolve this problem?
The answer for this could be the CUE language. CUE is a superset of JSON, can be transformed into JSON, and brings certain other benefits like validation with schemes (could be very useful for config files).
CUE would make the configuration a lot easier. People would be able to use all features in the json config adapter and the config file would still be readable + it would be possible to insert comments.
The project would benefit of CUE in other parts as well (validation with schemes and fixed datatypes could be a lot more easier with CUE).
I really recommend this short CUE tutorial:
https://cuelang.org/docs/tutorials/tour/
I can imagine this as third-party config adapter package. CUE is a superset of json, therefore somebody could just parse CUE and pipe all the output into the caddy2 JSON config adapter and this should be fine. (Although the best part is the validation via schemes in CUE etc).
Here is a short example from YAML to CUE with a kubernetes deployment file:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-kubernetes
spec:
replicas: 3
selector:
matchLabels:
app: hello-kubernetes
template:
metadata:
labels:
app: hello-kubernetes
spec:
containers:
- name: hello-kubernetes
image: paulbouwer/hello-kubernetes:1.5
ports:
- containerPort: 8080
Same in JSON:
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": "hello-kubernetes"
},
"spec": {
"replicas": 3,
"selector": {
"matchLabels": {
"app": "hello-kubernetes"
}
},
"template": {
"metadata": {
"labels": {
"app": "hello-kubernetes"
}
},
"spec": {
"containers": [
{
"name": "hello-kubernetes",
"image": "paulbouwer/hello-kubernetes:1.5",
"ports": [
{
"containerPort": 8080
}
]
}
]
}
}
}
}
Here is the equivalent in CUE:
// This is a comment
apiVersion: "apps/v1"
kind: "Deployment"
metadata name: "hello-kubernetes"
spec: {
replicas: 3
selector matchLabels app: "hello-kubernetes"
template: {
metadata labels app: "hello-kubernetes"
spec containers: [{
name: "hello-kubernetes"
image: "paulbouwer/hello-kubernetes:1.5"
ports: [{
containerPort: 8080
}]
}]
}
}
A CUE config adapter would certainly be welcome, but probably not as a standard module, like you said (also see https://github.com/caddyserver/caddy/issues/2780).
If you or somebody builds a CUE adapter for Caddy, please link to it here and when our new website is up we'll be sure to add it! Shouldn't be too hard to build this, I figure.
@shibumi FYI json5 and jsonc are also supported, which address some of the complaints you have about json. See here in the codebase: https://github.com/caddyserver/caddy/tree/v2/caddyconfig
I could see a couple of different approaches:
Thanks for the input @rudolph9 !
Cue is a superset of json so any raw json object can be dumped into a cue file and it works swell so existing json config would accepted without breaking anything.
That's really cool. Just to be sure it's clear, though, users would write a cue file and then we'd have to convert it to JSON which Caddy accepts as input.
A much less heavy handed approach that would let you dip your toes in cue without having to mess with the internals of caddy would be to use a cue tool script. Using this approach your existing json data model could be defined via cue, user can write a minimal config in JSON (or YAML cue supports import of either), and execution of the cue tool script spits out a json config.
Ah this sounds much more like what we need. I commented on the linked issue in the cue repo, maybe evaluating a cue file and then calling Value() and then Marshal() is what we need.
@mholt Glad I was able to help. Check out the cue slack channel if you have any more questions it's pretty active :+1: https://github.com/cuelang/cue#contact
Well that was easy:
var rt cue.Runtime
inst, err := rt.Compile("testing.cue", body)
if err != nil {
return nil, nil, err
}
jsonResult, err := inst.Value().MarshalJSON()
if err != nil {
return nil, nil, err
}
return jsonResult, nil, nil
It's spikey (needs some polish) but it works.
All done -- here you go! https://github.com/caddyserver/cue-adapter
Most helpful comment
@shibumi FYI
json5andjsoncare also supported, which address some of the complaints you have aboutjson. See here in the codebase: https://github.com/caddyserver/caddy/tree/v2/caddyconfig