---
title: Tech Forum ytt schema Annotations Scratchpad
tags: ytt
---
Existing annotations
--
`@overlay`
- `@overlay/match-child-defaults`
- `@overlay/merge`
- `@overlay/remove`
- `@overlay/replace`
- `@overlay/insert`
- `@overlay/append`
- `@overlay/assert`
- `@overlay/match by="x"`
- `@overlay/match missing_ok=True`
- `@overlay/match expects=2`
- `@overlay/match when=2`
-
`@schema`
- `@schema/type any=True`
- `@schema/nullable`
- (future)
- (future) `@schema/default value`
- (future) `@schema/key [allowed=Regexp] [(expects=Int|String|List|Function | missing_ok=Bool)]`
- (future) `@schema/validate func()`
- (future) `@schema/title "string"`
- (future) `@schema/doc "string"`
- (future) `@schema/example example`
- (future) `@schema/examples [examples]`
- (future) `@schema/deprecated "string"`
- (future) `@schema/removed`
`@data`
- `@data/values`
`@library`
- `@library/ref "@app"`
- `#@library/ref "@lib1@~foo"`
`@ load("x.star", "x")`
Considerations
---
* We want to avoid breaking changes
* We want a simple UX
* Can we utilize patterns in our current annotations?
* Does it make sense to have one schema definition for inputs _and_ outputs?
Current schema example
---
```yaml
#@schema/match data_values=True
---
#@schema/nullable
nothing:
string: ""
#@schema/type any=True
any:
```
Alternatives
---
```yaml
#@schema/match "data_values"
---
#@schema/nullable
nothing:
string: ""
#@schema/type any=True
any:
```
```yaml
#@schema/data_values
---
#@schema/nullable
nothing:
string: ""
#@schema/type any=True
any:
```
```yaml
#@data/values
#@schema/values
#@schema/k8s
#@schema/concourse
#@schema/definition name="data/values"
#@schema/def name="data/values"
#@schema/def data_values=True
#@schema/
#@data/schema
#@template/schema
#@output/schema
```
```yaml=
#@data/schema
#@library/ref "@libby"
---
#@schema/validate min=1
bananas: 1
#@data/schema name="schema2"
---
#@schema/validate min=1
bananas: 1
```
```yaml=
#@template/schema name=""
---
```
```yaml
#@schema/use name="schema1"
---
bananas: "wrong"
```
1. in input bananas is an int and >0
2. in output
```yaml
#@schema/use name=""
---
a:
somevalue: #@ data.values.bananas
```
:banana:
:banana:
:banana:
:monkey:
## Schema functions?
```
# current data module function:
vals = data.list()
# future schema functions
template.validate()
data.validate()
#@ s = schema.get("schema.yml")
#@ violations = s.check(yaml_docset)
#@ violations = s.validate(yaml_docset)
```
Schema and template in the same file
```
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 1
#@schema/def
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: default-deployment
labels:
app: default
spec:
replicas: 3
selector:
matchLabels:
app: default
template:
metadata:
labels:
app: default
spec:
containers:
- name: default
image: default:1.14.2
ports:
- containerPort: 80
```
```
#@schema/values
#@schema/def name="k8s"
#@schema/def name="concourse"
#@schema/def name="deployment" group="apps" version="v1"
#@schema/def name="" match_by=matcher_func()
```
Future state?
---
`schema.yml`
```yaml=
#@schema/def name="k8/deployment"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: default-deployment
labels:
app: default
spec:
replicas: 3
selector:
matchLabels:
app: default
template:
metadata:
labels:
app: default
spec:
containers:
- name: default
image: default:1.14.2
ports:
- containerPort: 80
```
`config.yml`
```yaml=
#@schema/use name="k8/deployment" version="v1"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 1
```
## Additional Context
- the "Data module" while serving lots of value has room to grow:
- today there are two channels of inputs: Data Values and Data files.
- e.g. perhaps having other named sources of data (like some subset of Kubernetes Cluster state)
In terms of considering different syntax
- practical test: how likely will the user remember one syntax over another?
- what are the range of mental models (low fidelity ~ copy-and-paste <=== ===> high fidelity ~ deep conceptual understanding of individual features)
We'd maximize value/flexibility if we solve for as much of that range as we can.
### Additional Option: `@data/values-schema`
```yaml=
#@data/values-schema
---
#@schema/nullable
optional_bits:
```
- if we look deeper at it, `@data/values` is actually an overlay... one could say the full name of that annotation is `@data/values-overlay`
- today, there's only one schema, but given notes above about potential future growth, it's not a limitation we'd be wise to commit to (which makes `@data/schema` a bit "too" terse)
- we've got what seems to be a conceptually balanced thing going with `@(module-name)/(annotation-name)`, so adding another `/` into the mix seems like its going to make that whole thing more complicated.
- the schema we're declaring is specifically for Data's Values. So, `values-schema` seems like a fitting noun.
### Exploring a Programmatic API for Schema
- draws in bottom-up design forces: what _ought_ to be fundamentally true about a given concept (like schemas)?
- can help maintain orthogonality between features (the stronger the identity/definition/set of responsibilities, the less likely we'll accidentally misplace one)
sketching...
```
#@ blah = library.get("blah")
#@ child_schema = blah.data_values_schema()
#@ blah = blah.with_data_values_schema(my_add_ons())
#@ s = schema.get("data_values")
#@ schema.get_data_values()
#@ s.check(doc|docset)
#@ s.validate(config_map)
```
... also, if we build up programmatic primitives, we might be able to realize higher-level features through composition.
For example, what if schema could be `load()`'ed and then applied via an overlay?
```
#@overlay/match by=overlay.all
#@overlay/assert via=lambda left, right : k8s_schema.find(left).validate(left)
---
```
or used directly in a template?
```
#@ load("k8s_schemas", "k8s")
#@schema/type via=k8s.apps.v1.Deployment
#@schema/type k8s.apps.v1.Deployment
---
foo : #@ ...
spec:
#@schema/type k8s.core.v1.PodSpec
template:
containers:
#@schema/type k8s.core.v1.PodSpec.Container, default_omitted=True
- name:
image:
```