Knotx / knotx

Knot.x is a highly-efficient and scalable integration framework designed to build backend APIs
https://knotx.io
Apache License 2.0
126 stars 26 forks source link

Implement custom Knot.x tag `<knotx:router>` #78

Closed malaskowski closed 8 years ago

malaskowski commented 8 years ago

Implement custom Knot.x tag <knotx:router> that will enable routing control inside snippets. Inside the tag developer may put json configuration that defines routing basing on adapter services responses. Hierarchy of json configuration properties is the same as in response and handlebars values. E.g.

 <script data-api-type="templating"
    type="text/x-handlebars-template"
    data-uri-post-formA="/service/mock/step1.json"
    data-uri-all-labelsRepository="/service/mock/labelsRepository.json"
    data-id="step1">
  <knotx:router>
    {
      _default._response.statusCode: {
        "5*": "/error" //when any _response (formA or labelsRepository in this case) status code would be 5XX, Knot.x will redirect user to '/error' page
      },
      formA.success: {
        true: "/step2"  //when formA responses with `success: true`, Knot.x will redirect user to `/step2` page
        //false: validation failed - we stay where we are
      }
    }
  </knotx:router>  
  <div id="login-form-wrapper">
    <h1>{{labelsRepository.loginHello}}</h1>
    {{#if formA && !formA.success}}
      <p>{{labelsRepository.validationError}}</p>
    {{/if}}
    <form method="post" class="form-inline" id="formA">
      <div class="form-group">
        <label for="email">Email</label>
        <input type="email" name="email" id="email" value="{{_request.email}}"/>
        <label for="birthDate">Date of birth</label>
        <input type="text" name="birthDate" id="birthDate" value="{{_request.birthDate}}"/>
      </div>
      <button type="submit" class="btn btn-default">Submit</button>
      <input type="hidden" name="_id" value="step1"/>
    </form>
  </div>
</script>
tomaszmichalak commented 8 years ago

If service returns error code and there is no routing defined Knot.x should return error code without any processing.

Are you agree?

tomaszmichalak commented 8 years ago

Knotx tags modify general Knot.x response. They can modify HTTP headers, set cookies or initialize custom redirections.

If there is more than one knotx tag in template all knotx tags handlers will be called in chain in order they appear in script. Every handler calls chain.next() to let next one to process. If handler does not call chain.next it means that no more knotx tag handler will be invoked for particular script tag. Next template processing will invoke next bunch of knotx tag handlers.
Response can be returned to end user immediately by calling: chain.response().end().

As asynchronous service calls mechanism does not care about script tags order, it is script creator responsibility to prevent response randomness.

If there is no chain().response().end() call knot.x will wait for other templates processing.

Notes: Generally we need to redirect for POST requests. For most GET requests we can handle them with handlebars mechanism or general error codes. Knot.x tries to not overcomplicate the flow. Exception from this rule are multi-level forms and step validation while GET service call. In this situation correct service implementation should handle this corner case.

malaskowski commented 8 years ago

Very good idea with chain processing. However, I would stay with processing all <knotx> tags after full markup is ready. It allows to predicate in what order chain is processed. I understand, that we need some way to tell, that one redirect is more important than another - e.g. when we process form post and it says that submit was successful but some another snippet broke because e.g. temporary 503. In such case from the business logic point of view we should continue and redirect user to /landingPage or because his data was successfully saved and service that returned 503 does not matter since we redirect to another page. How about adding these 3 rules:

Priority should be considered globally in whole template. Thanks to that, developer may say, that processing a POST redirect is more important than handling error from another, minor component on the page.

tomaszmichalak commented 8 years ago

I really like the idea <knotx:router priority=10>. It will be very elastic we should not face namy problems with multiple forms on the same page.

I think we can update issue and start development.

mmajchrzak commented 8 years ago

The router thing is very elastic and allows you to do everything with the application flow. But I'm not convinced if this is really what knot.x should be all about. I always thought knot.x is simple and should not perform much of a business logic. The router however allows developers to code the application flow within frontend scripts. And it still makes me think if this is a good idea... I'm afraid that the solutions created based on the router will be complicated, not clear and hard to maintain. The main reason for the router solution is to support forms, so maybe it would be better to simplify it a bit by putting some constraints and make it kind of an extension for knot.x rather than a core solution?

tomaszmichalak commented 8 years ago

@mmajchrzak yes, we will schedule design session next week where we will talk about knotx core and knotx extension modules

tomaszmichalak commented 8 years ago

This issue is suspended. Currently we are working on different solution to decrease script tag complexity.

marcinczeczko commented 8 years ago

Closing as we will go towards different approach