Introducing Kogito API Incubation

Would you like to be able to evaluate a process in Kogito with a simple Java API like this?

var id = appRoot.get(ProcessIds.class).get("hello-world");
// wrap the Map in a data context
var ctx = MapDataContext.create();
ctx.set("name", "Paul");
// evaluate the process and get the result as a map-like 
var res = processSvc.evaluate(id, ctx).as(MapDataContext.class);
System.out.println(res.get("message")); // "hello, Paul!"

What about invoking a specific subcomponent of a DMN, such as a decision service ?

MapDataContext ctx = MapDataContext.create();
// construct the path to a DMN decision service 
var id = appRoot
            .get(DecisionIds.class)
            .get("https://github.com/evacchi/my-namespace",
                  "Traffic Violation")
             .services()
             .get("my-service-id");
// evaluate the decision and return the result
var res = dmnSvc.evaluate(id, ctx);

Or maybe you do not want the flexibility of a Map. Maybe you just want to use a simple data object. Is a Java record concise enough for you?

public record 
    LinearRegParams(
        float fld1, float fld2, String fld3) 
        implements DataContext, DefaultCastable {}

public record 
        LinearRegResult(
            float fld4) 
            implements DataContext, DefaultCastable {}

// construct the path to a PMML predictive model
var id = appRoot
            .get(PredictionIds.class)
            .get("LinReg");

// create the context object
var ctx = new LinearRegParams(...);
// evaluate
var res = svc.evaluate(id, ctx);
// map the result to the record
var rec = pmmlSvc.as(LinearRegResult.class);

What if you could just use that record in your REST endpoint?

@POST
@Consumes(MediaType.APPLICATION_JSON)
// take the custom data context as a parameter, 
// get JSON conversion automatically
public Float hello(LinearRegParams payload) {
    var id = appRoot
                .get(PredictionIds.class)
                .get("LinReg");

    var res = pmmlSvc.evaluate(id, payload);
    // extract the float result and return it
    var rec = res.as(LinearRegResult.class);
    return rec.fld4();
}

Or maybe evaluate a Drools query and get a stream of typed results?

public record 
    MyQueryResult(
        String contents) 
        implements DataContext, DefaultCastable {}

@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Stream<MyQueryResult> hello(MapDataContext ctx) {
    var queryId = appRoot.get(RuleUnitIds.class)
        .get(Hello.class)
        .queries()
        .get("hello");
    // evaluate the query
    return svc.evaluate(queryId, ctx)
                map(ctx -> ctx.as(MyQueryResult.class)); // map each result to a typed value 
}

You have learned to love the powerful Kogito codegen capabilities. You just drop your asset to your source directory (or you feed it to the powerful operator) and you get a fully-functional REST endpoint for free.

However, from day one we understood that automated code-generation would bring you only to a certain point. That is why we wanted to provide a great programmatic API. Yet, so far we were not confident enough to open up the internal API that we were using as our code generation target. The reason is that we wanted to get it right first.

We are now happy to release a first version of our new public API in incubation state starting from version1.13 1.12!

What does incubation mean?

Incubation means that this API is a first approximation of what we will deliver in the end. It is made available early in the spirit of release early, release often, with no guarantees that it will not change. However, you are welcome to try it and give us feedback on it, because once released we will not be able to make any more changes to it.

When can I get my hands on this?

We plan to roll out a first version of this for the 1.13 1.12 release. However, until this is incubating then we will not commit to long-term stability. Breakage may occur; you have been warned: use it at your risk!

When are you delivering the final version of this API ?

We plan to roll this out in stages. As you know our platform contains multiple components (DMN, PMML, Processes, Severless Workflows, Drools rules), and it is possible that each one of those will reach maturity at a different moment in time.

Moreover, every component has a different set of capabilities. So we may decide to roll out features instead of full components. For instance, we may declare that the API for evaluating a DMN model has reached maturity stage, but keep the listener API still in incubation.

Shall I wait for it to be final?

Well that depends on you, really. Do you like living on the bleeding edge? If you picked Kogito we may assume that you do! Even if we make some changes, we don’t think they will be revolutionary. Indeed, you will certainly have to rename your imports from org.kie.kogito.api.incubation. toorg.kie.kogito.api. at some point. Maybe update your dependencies. But the structure will probably be pretty similar to what we will deliver now. So don’t be too scared.

OK, sure but this looks pretty vanilla. Is there something else to it?

Indeed. What if I told you that every identifier is really translated into path?

//     /predictions/LinReg
appRoot.get(PredictionIds.class).get("LinReg"); 

//     /rule-units/org.kie.kogito.examples.Hello/queries/hello
appRoot.get(RuleUnitIds.class)
       .get(Hello.class)
       .queries()
       .get("hello");

//     /decisions/https%3A%2F%2Fgithub.com%2Fevacchi%2Fmy-namespace%23Traffic%20Violation
var id = appRoot
            .get(DecisionIds.class)
            .get("https://github.com/evacchi/my-namespace",
                 "Traffic Violation")

//     /processes/hello-world
var id = appRoot.get(ProcessIds.class).get("hello-world");

What if I told you that paths could be mounted onto URIs ?

kogito://my-app-1@my.host1.name:54321/predictions/LinReg
kogito://my-app-2@my.host2.name:54321/rule-units/org.kie.kogito.examples.Hello/queries/hello
kogito://my-app-3@my.host3.name:54321/decisions/https%3A%2F%2Fgithub.com%2Fevacchi%2Fmy-namespace%23Traffic%20Violation
kogito://my-app-4@my.host4.name:54321/rules/processes/hello-world

What if you could use one unified way to send commands across the network between Kogito applications? What if those same IDs and commands were easily mapped onto HTTP commands?

POST https://my.host1.name:54321/my-app-1/predictions/LinReg { "json" : "data" }

or would you rather prefer Cloud Events ?

POST https://my.host1.name:54321
{
    "specversion" : "1.0",
    "type" : "org.kie.kogito.predictions.evaluate",
    "source" : "/some/sender/id",
    "org.kie.kogito.target" : "/predictions/LinReg",
    "id" : "...",
    "time" : "2021-04-05T17:31:00Z",
    "datacontenttype" : "text/json",
    "data" : {
         "fld1" : 3.0,
         "fld2" : 2.0,
         "fld3" : "y"
    }
}

Wait, are you saying this is already available? That’s awes–

No, it’s not, sorry to burst that bubble. We are still working on it. But really, that is where we would like to end up. For now, just enjoy this new way to develop your own REST endpoints! But stay tuned: easy serialization and distribution are the main drivers of this redesign.

Alright, alright. That still looks pretty cool. Where do I get it?

Wait for the1.13 1.12 release next week! You will find the examples at the usual place. But if you are curious, look here.

OK cool

Wait, wait wouldn’t you like to learn more about how this was designed?

Not really, but if you insist

Well I do. In the next post I’ll explain the design rationale for this API. You may also join us on October 2nd at our KIE Live; yours truly will deliver a presentation and will give a live coding demo. Ain’t that cool?

Update Sept.30th: Instead of 1.13 we will release 1.12 everything still applies!

5 1 vote
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments