Hof Schemas are CUE values and serve as the contract between
you, the generator writer, and your users.
Your schemas capture the essence of the problem or application.
They provide the constraints for users developing with your generator
and ensure input to your generator is valid.
A Schema in Hof
A Hof Schema is a CUE value.
schema/myschema.cue
packageschema// A schema is any valueSchema: {// with any fields you want}
A Minimal REST Schema
Let’s start by sketching out the minimal definition for a server.
We put this in the schema/ directory and thus CUE package.
schema/server.cue
packageschemaHttpMethod: "OPTIONS"|"HEAD"|"GET"|"POST"|"PATCH"|"PUT"|"DELETE"|"CONNECT"|"TRACE"Server: {// schemas typically have a name field// the user sets this for each instance Name: string// Some more common "optional" fields// we use defaults rather than CUE optional syntax Description: string|*"" Help: string|*""// the REST routes Routes: Routes}
Routes and Handlers
Routes are a main focal point of REST servers.
When we generate the code, we will need handlers for each.
Here is the schema for a Route that will have a handler generated.
schema/server.cue
Routes: [...Route] |*[]Route: { Name: string Path: string Method: HttpMethod// Route and Query params Params: [...string] |*[] Query: [...string] |*[]// Fields which allow the user to write// handler bodies directly in CUE Body?: string Imports: [...string] |*[]// Allows subroutes for routes Routes: [...Route]}
Extra Features
These are features you may want to provide to your server users.
While the user only has to set a boolean or flag,
they can get advanced capabilities which are the consistent
for every generated server.
schema/server.cue
Server: {// ...// list of file globs to be embedded into the server when built EmbedGlobs: [...string]// enable prometheus metrics Prometheus: bool// auth settings (optional) Auth?: { apikey: bool|*false basic: bool|*false }}
Calculated Fields
These are fields and values you can infer from a user’s input that they do not need to set.
They are often for making template writing easier by formatting or collecting values.
You can also transform or enrich user input using CUE here as well as in generators.
Later, we will use this technique to define the CRUD routes for a resource based on the user’s data model.
schema/server.cue
import"strings"Server: {// ...// various casings of the resource Name serverName: strings.ToCamel(Name) ServerName: strings.ToTitle(Name) SERVER_NAME: strings.ToUpper(Name)}
Language and Tool Fields
There are typically language or tools specifics which may need to be configured.
Often, you will want to make some of these accessible to your users.
You can even create generators which are multilingual or lets your
user select their preferred technologies.
schema/server.cue
Server: {// ...// The project's git repo GitRepo: string// We need to know the module for Go// we can default to another field GoModule: string|*GitRepo}
Final Schema
This is our final schema after combining all the parts above.
schema/server.cue
packageschemaimport"strings"HttpMethod: "OPTIONS"|"HEAD"|"GET"|"POST"|"PATCH"|"PUT"|"DELETE"|"CONNECT"|"TRACE"Server: {// Most schemas have a name field Name: string// Some more common "optional" fields// we use defaults rather than CUE optional syntax Description: string|*"" Help: string|*""// The project's git repo GitRepo: string|*""// language fields GoModule: string// The server routes Routes: Routes// list of file globs to be embedded into the server when built EmbedGlobs: [...string]// enable prometheus metrics Prometheus: bool// auth settings (optional) Auth?: { apikey: bool|*false basic: bool|*false }// various casings of the server Name serverName: strings.ToCamel(Name) ServerName: strings.ToTitle(Name) SERVER_NAME: strings.ToUpper(Name)}Routes: [...Route] |*[]Route: { Name: string Path: string Method: HttpMethod// Route and Query params Params: [...string] |*[] Query: [...string] |*[]// Fields which allow the user to write// handler bodies directly in CUE Body?: string Imports: [...string] |*[]// Allows subroutes for routes Routes: [...Route]}