Knotx / knotx-fragments

Fragments map-reduce processing using Graph flows, supplier and assembler.
https://knotx.io
Apache License 2.0
3 stars 5 forks source link

Params JsonObject #49

Open zajcu opened 5 years ago

zajcu commented 5 years ago

Is your feature request related to a problem? Please describe. In databridge 1.5.0 version there was a awesome feature: params https://github.com/Knotx/knotx-data-bridge/tree/1.5.0 What is missed in current 2.0 version

Describe the solution you'd like We need similar feature in 2.x version. For example to cover example code: `

{{item._result.book.name}}

{{item2._result.user.name}}

...`

I supposed the simple solution will be extend fragments model to have additional JsonObject property, and later in processing consume it for example in HttpAction like it was in old implementation in HttpClientFacade (1.5.0 version).

Potentialy this object can be reused in other places.

What do you think?

Additional context We have used it a lot in our current project, we need this to start migrate !X to the last version.

tomaszmichalak commented 5 years ago

Hi @zajcu, thanks for the issue. In Knot.x 1.5.0 it was possible to specify the params attribute that overrode the one from the [dataDefinitions[namespace].params] configuration attribute, see the example. So it was easy to specify the new path for the named HTTP data source (REST endpoint). Please note that in Knot.x 1.5.0 it was possible to define many data sources per fragment.

In Knot.x 2.0.0 we introduced a task concept where you can define only one task per fragment.

<knotx:snippet data-knotx-task="booklist"
</knotx:snippet>

Then in the configuration we have:

tasks {
    booklist {
        actions = [
            { action = books }
            { action = authors }
        ]
        onTransitions {
            _success {
                action = template-engine-handlebars
            }
        }
    }
}

Task can specify one and more actions to execute, in this example we have two actions: books and authors. Our actions call REST endpoints and fill the payload. Every action gets Fragment, do some transformation and responds with the new Fragment. In Fragment there is the configuration attribute, it is a JSON object. For HTML markup, it contains all knotx:snippet tag attributes. So it is not required to extend Fragments model with extra attribute. When you check the Http Action documentation you will find that you can parametrize your action with:

You can check available placeholders here. Maybe it is worth to add the example for configuration attributes, like {config.books-query}. This attribute can be specified with:

<knotx:snippet data-knotx-task="booklist" books-query="java"
</knotx:snippet>

So then in the action configuration, you will have:

book {
  factory = http
  config {
    endpointOptions {
      path = /service/mock/book.json?q={config.books-query}
      domain = localhost
      port = 3000
      allowedRequestHeaders = ["Content-Type"]
    }
  }
}

Can you please verify if it works for you? Our intention was to simply tag attributes.

tomaszmichalak commented 5 years ago

Thank you @zajcu for your input. As we discussed this solution works as expected. However, we discovered new requirements. Let me explain it with the example below:

ZG Bridge integrates with Knot.x to deliver dynamic data to templates coming from AEM. ZG Bridge defines collections and collections items that can be easily used during AEM authoring.

So, let's imagine that we have two independent collections: authors and books. Both authors and books are JSON objects coming from REST API. JSON is a contract, REST API is a data source. There are two REST endpoints for authors:

/authors?filter="first name"
/author/{id}

and books:

/books?filter="title"
/book/{id}

Then in ZG Bridge you can specify what items are used to fill a template from AEM. In this way, we can specify two books at a single page (first - the primary one, second - the recommended one). So we have book-1 and book-2. This data must be configured something in HTML, then Knot.x can use it and fill the template.

The example HTML markup can look like:

<knotx:snippet task="product-details-component"> 
{{book.1.title}}
<h1>Recommended products</h1>
{{book.2.title}}
</knotx:snippet>

In Knot.x there is the product-details-component task defined. In the standard approach, we would define it as:

tasks {
    product-details-component {
        actions = [
            { action = book1 }
            { action = book2 }
        ]
        onTransitions {
            _success {
                action = template-engine-handlebars
            }
        }
    }
}

and specify two actions. But as you see this solution is not very flexible. So we need some configuration to make those task definitions more dynamic.

Let's change the task configuration to:

tasks {
    product-details-component {
        actions = @book
        onTransitions {
            _success {
                action = template-engine-handlebars
            }
        }
    }
}

Then we can configure @book with some parameter in HTML

<knotx:snippet task="product-details-component" task-actions="@books-configuration"> 
{{book.1.title}}
<h1>Recommended products</h1>
{{book.2.title}}
</knotx:snippet>

, where the @books-configuration structure is:

{
  "book": [
    {
      "namespace": 1,
      "config": {
        "id": 1
      }
    },
    {
      "namespace": 2,
      "config": {
        "id": 2
      }
    }
  ]
}

With this solution we specify Action once:

actions {
  book {
    factory = http
    config {
      endpointOptions {
        path = /book/{config.id}
        ...
      }
    }
  }
}

Then we can specify the dynamic task provider implementation that would transform the task-actions attribute to Task.

zajcu commented 5 years ago

Thank you @tomaszmichalak this is exactly what we need to cover our requirements. By the way very nice explanation.

tomaszmichalak commented 5 years ago

Hi, we had a design session, those are outputs: