-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Templating System Design Context
So, let's start capturing some thoughts about how the Templating System within dobby should be set out.
So to state an end goal and justification for the existence of a templating system:
The end goal is having an HTML templating service, that's compatible and easy to pipe into the PDF generation service.
The PDF generation service could get its raw HTML from another service in the given project's ecosystem, but it would be great if we could have a complimentary system within dobby that can easily bind and validate models to template strings to produce HTML that can be piped into the PDF generation service to pop out a PDF.
A few questions pop out from this:
- Should the templating system only process raw HTML?
- What templating syntax should we use? There's tonnes of good ones.
- Should it be HTML specific? e.g. It would be useful to have a simple string templater for the use case of translating error messages into different locales.
- Other formats, such as markdown, can also make sense to be converted into a PDF document (with some kind of middleware to convert it to HTML first)
Proposal
I propose a very simple arbitrary string templater package to be at the core of the templating system. Let's call it TemplaterCore for now until we come up with a better naming convention for these core utility packages. It should have a single method, with the following signature: .bind(template, model, schema)
The template would be the string template that the model properties are bound to, once validated by the schema.
Dobby has the space to be opinionated, so I think we can impose some sensible ideas on what is considered a template, a model, and a schema. Discussed below.
This TemplaterCore package could then be imported independently into another project that's looking to use the "useful bits" from dobby, or be imported into the next layer of debby; something like a simple string templating API, say TemplaterAPI for now. It's still early days, but this templater api would essentially wrap up the calls to TemplaterCore. TemplaterAPI could then be enhanced with plugins and adaptors to provide different transport mechanisms (REST, SOAP, GraphQL etc.), and provide certain storage opportunities such as a plugin to add persistance of template strings and schemas for a given domain.
Getting towards our end goal, another conceptual plugin could be an HTML validator (after hook middleware).
In the next layer of dobby, this TemplaterAPI could be bundled into a variety of different pre-packaged docker images with different plugins configured to different specialisations on the general concept of binding a model to a template string.
In the outer most layer, a simple CRUD admin portal could be build on top of one of the transport layers (REST probably) to provide simple backend administration of the templates and schemas in the templating API. I think that React Admin is a good candidate for this, but it's a long way away still.
TemplaterCore
A template
I think it makes sense to use a widely used template syntax that will be accessible to most most developers such as Moustache or Handlebars. Whilst templating engines like Razor are very powerful, fast, and feature rich, the knowledge (or up skilling) required to use them is heavily tied into the rest of the tech stack (i.e. .Net).
Whilst a high performance string templater for dobby would be great, it's a secondary concern to accessibility and ease of use in context of the objectives of dobby.
Handlebars gives some nice benefits around the concept of pre-compling a template, but that may dilute the simplicity of the interface. I don't want to discard this idea, but for now, I want to try keep things simple as possible.
So, I suggest simple Moustache template strings. e.g.
const template = "Hello {{name}}";
A model
Quite simply, this is an arbitrary object. e.g.
const model = { name: "bob" };
A future enhancement on the '.bind()' method could be to allow for both objects and a string as the model argument, and then internally attempt to parse it into an object with JSON.parse(model). However, we then need to consider the error handling for model parsing failure over and above schema failure discussed below.
A schema
This is where I think we can add a bit of a safety net to the templater, and justify its existence wrapping what is essentially moustache.js. Essentially dobby's templater could perform model validation.
We could consider making the schema argument optional, in which case the validation step is bypassed, but I think there is some value in forcing some validation?
For the actual schema definitions, I suggest JSON Schema, because when paired with a solid underlying validator like ajv we can get consistent and rich error messages that can still be user defined to a degree.
So, for example:
const schema = {
"$id": "http://example.com/schemas/schema.json",
"type": "object",
"properties": {
"name": { "$ref": "defs.json#/definitions/str" }
}
};
Example usage of templaterCore
An example of usage could be:
import {templaterCore} from "dobby";
const template = "Hello {{name}}";
const model = { name: "bob" };
const schema = {
"$id": "http://example.com/schemas/schema.json",
"type": "object",
"properties": {
"name": { "$ref": "defs.json#/definitions/str" }
}
};
const stringResult = templaterCore.bind(template, model, schema);
TemplaterAPI
todo
Templater Plugins
todo
Templater Admin Portal
todo