Ficheros de configuración

Una configuración la leen la persona que la ajusta y el programa que la carga. Con una plantilla, un error se detecta en el editor y no en producción.

La configuración de un servicio

Server Config (com.acme.server):
	Name: api-gateway
	Environment: production

	Network:
		Host: 0.0.0.0
		Port: 8080
		Public url: https://api.acme.com

	# El límite de 5000 ms viene del SLA con el proveedor de pagos
	Timeouts:
		Read ms: 5000
		Write ms: 5000

	Logging:
		Level: INFO
		Format: json

	Features:
		Feature: experimental-cache
			Enabled: false
		Feature: audit-logging
			Enabled: true

	Notes >>
		Configuración principal del gateway de APIs. Se versiona con la aplicación
		y se despliega con ella.

		Los cambios en Network y Timeouts pasan por revisión de Reliability.

En este ejemplo tenemos:

  • Grupos: Network, Timeouts, Logging y Features. Son nodos sin valor, que agrupan a sus hijos.
  • Ajustes: Host, Port, Level... Son nodos con valor.
  • Feature flags: el valor del nodo Feature es el nombre, y su hijo Enabled es el estado.
  • Explicaciones: un comentario para una nota corta, o un nodo block como Notes para un texto largo. La diferencia es que Notes forma parte del documento, y un programa puede mostrarlo.

La plantilla

Template (@stxt.template): com.acme.server
	Structure >>
		Server Config:
			Name: (1)
			Environment: (1) ENUM [dev, staging, production]
			Network: (1)
				Host: (1)
				Port: (1) NATURAL
				Public url: (?) URL
			Timeouts: (?)
				Read ms: (?) NATURAL
				Write ms: (?) NATURAL
			Logging: (?)
				Level: (1) ENUM [DEBUG, INFO, WARN, ERROR]
				Format: (?) ENUM [text, json]
			Features: (?)
				Feature: (*)
					Enabled: (1) BOOLEAN
			Notes: (?) TEXT

Una configuración que no valida

Muchos cargadores de configuración ignoran una clave mal escrita y aplican el valor por defecto. Con la plantilla, estos errores dejan de ser silenciosos:

# ERROR: este documento no valida
Server Config (com.acme.server):
	Name: api-gateway
	Environment: production
	Network:
		Host: 0.0.0.0
		# `Ports` no existe, es `Port`
		Ports: 8080
	Logging:
		# `info` en minúsculas no es `INFO`
		Level: info
	Features:
		Feature: audit-logging
			# Un BOOLEAN es `true` o `false`
			Enabled: yes

Y esto es lo que responde stxt validate:

/home/ana/gateway/config/server.stxt:8: [NODE_NOT_DEFINED_IN_SCHEMA] NOT EXIST NODE ports for namespace com.acme.server (error)
/home/ana/gateway/config/server.stxt:8: [CHILD_NOT_DECLARED] Child 'com.acme.server:ports' not declared in node 'com.acme.server:network' (error)
/home/ana/gateway/config/server.stxt:5: [TOO_FEW_CHILDREN] 0 nodes of 'com.acme.server:port' and min is 1 (error)
/home/ana/gateway/config/server.stxt:11: [INVALID_VALUE] The value 'info' is not one of the allowed values of Level (error)
/home/ana/gateway/config/server.stxt:15: [INVALID_VALUE] Enabled: Invalid boolean (yes) (error)
5 error(s), 0 warning(s)

La extensión de VS Code marca los mismos errores al escribir. En integración continua, stxt validate --recursive config/ detiene el despliegue de una configuración inválida (La línea de comandos).

Varios entornos, una estructura

Un solo documento puede tener un nodo por entorno, y la plantilla garantiza que todos declaran lo mismo:

Application Config (com.acme.app):
	App name: Billing

	Environments:
		Environment: dev
			Database:
				Url: jdbc:postgresql://localhost/dev
				Max connections: 5
			Debug: true
		Environment: staging
			Database:
				Url: jdbc:postgresql://staging/db
				Max connections: 10
			Debug: false
		Environment: production
			Database:
				Url: jdbc:postgresql://prod/db
				Max connections: 30
			Debug: false

Y su plantilla:

Template (@stxt.template): com.acme.app
	Structure >>
		Application Config:
			App name: (1)
			Environments: (1)
				Environment: (+)
					Database: (1)
						Url: (1)
						Max connections: (1) NATURAL
					Debug: (1) BOOLEAN

Un entorno al que le falte Database no valida. Si se prefiere un fichero por entorno, el documento se parte en tres con el mismo namespace y la misma plantilla.

Cómo lo lee el programa

El programa recibe un árbol ya validado. Recorre los nodos por su nombre canónico (port, max-connections) y convierte los valores. Las guías de TypeScript, Java y Python muestran cómo.

La plantilla se busca en los directorios .stxt/ (STXT-DISCOVERY-SPEC), igual que en el editor. Así, el editor y el programa aplican la misma definición.

Límites

En STXT un valor es el texto que está escrito. No hay:

  • Variables ni referencias a otros valores
  • Inclusión de otros ficheros
  • Expresiones
  • Valores por defecto en la plantilla: si un nodo opcional falta, el programa decide qué vale

Es una decisión de diseño: un fichero de configuración no puede ejecutar nada ni depender de otro. Si hace falta componer un fichero base con uno por entorno, lo hace la aplicación al cargar.

Para comparar con otros formatos de configuración, ver STXT frente a YAML, que incluye TOML, y STXT frente a JSON.