Freitag, 6. Mai 2016

A JSON to JSON Template Engine

I came across a feature request, where it was needed to have a command line tool that is able to send variours JSON messages over the wire. Think of a JSON structure that represents the message template and that must be filled with different data values every time you want to send a message. Because the message template and the data are passed as JSON strings to the command line tool, all of this is not strongly typed but rather JSON strings.

So I thought of having a JSON structure that is a template having placeholders. These placeholders need to be filled with concrete values from a second JSON object. I thouht of a format for the placeholders and decided that it would be best if the placeholders are defined as valid JSON as well, so I can parse them easily.

Think of the following example:

{
    "Salution": <Fill from data field Contact.Salutation, if this is not present leave it null>,
    "FirstName": <Fill from data field Contact.FirstName>,
    "LastName": <Fill from data field Contact.LastName>,
    "Sex": <Fill from data filed Contact.Sex, if this is not present fill with value 'No information'>,
    "IsConfirmed": <Fill from data field IsConfirmed>
    "MessageType":"NewContactAdded",
    "Metadata" :
    {
        "CreatedOn": <Generate DateTime.Now>,
        "CreatedBy": <Fill from data field User>,
        "CorrelationId": <Generate Guid.NewGuid()>
    }
}

As a template this looks like this:

{
    "Salution":{ "Path":"Contact.Salutation", "Optional":"true" },
    "FirstName": { "Path":"Contact.FirstName" },
    "LastName": { "Path":"Contact.LastName" },
    "Sex": { "Path":"Contact.Sex", "Or":{ "Expression":"No information" } },
    "IsConfirmed": { "Path":"IsConfirmed" }
    "MessageType":"NewContactAdded",
    "Metadata" :
    {
        "CreatedOn": { "Expression":"DateTime.Now" },
        "CreatedBy": { "Path":"User" },
        "CorrelationId": { "Expression":"Guid.NewGuid()" }
    }
}

Given the following data

{
    "User":"trichling",
    "IsConfirmed":"true",
    "Contact":
    {
        "FirstName":"Peter",
        "LastName":"Pingel"
    }
}

will expand to

{
  "Salution": null,
  "FirstName": "Peter",
  "LastName": "Pingel",
  "Sex": "No information",
  "IsConfirmed": "true",
  "MessageType": "NewContactAdded",
  "Metadata": {
    "CreatedOn": "2016-05-06T12:17:17.9187797+02:00",
    "CreatedBy": "trichling",
    "CorrelationId": "2c59a1ee-be98-43b8-a046-d9ecb20a33aa"
  }
}

The Salutation was omitted in the data, but it is marked as optional, so a missing value will be ignored. First- and LastName are filled from a nested object in the data structure. The property Sex is also omitted, hence the default expression defined in the Or-part of the placeholder is used. The MessageType is a constant string, so it will be added as is to the output. The Metadata complex property is made up of a timestamp which is generated via an expression placeholder, as well as the CorrelationId.

Is this even useful? Can anyone think of different / broader use cases for this? Does anyone know a solution to the problem that already exists? I have searched the web but i could not find anything. That made me wonder: am I really the first person who thought about this (which I consider very unlikely), or does the whole use case make no sense?

I implemented a working solution that at least served my needs. Might anyone else feel this is useful? Please enlight me :)

If someone is interested, I am happy to share the source code - if not, I will hide in shame :)