X

Technical Articles relating to Oracle Development Tools and Frameworks

Web Component Techniques - Integrating Components with VBCS Service Endpoints

Duncan Mills
Architect

Introduction

In this article in the Web Components Techniques series I'm going to look at a fairly specialised topic, that of creating components that can call into VBCS Service Endpoints (REST Services managed by Oracle Visual Builder Cloud Service).

Now as a matter of course we try and build components which are totally agnostic of where they will be used, I should be able to use that component both within JET or any JET based UI, including VBCS of course.  As such we might define our component API with properties which work with generic data-types such as Array or the JET DataProvider interface. However, there are cases where this is really not sufficient.  For example, you are building a complex CRUD (CReate Update Delete) screen as a re-usable component.  This will need to keep communicating with the appropriate REST endpoints within the context of the component, rather than just manipulating a set of data and allowing the hosting application to take care of the REST part (Note: this is just a pattern, not the pattern there are various ways for components to behave in these scenarios, there is no one-size fits all approach). 

So how could we accomplish this? Well of course you could have the component take a URL to the endpoint as a property and then it can make the XMLHTTP requests internally, but the problem with that approach is that your component becomes responsible for managing any headers and security tokens that might be required, and, as it will be making a direct connection to the endpoints there may be more CORS configuration to be done on the server end to allow that communication. We also have to consider little inconveniences such as the fact that the endpoints may move between testing and production.  In this article, however, we'll be looking at a more satisfactory approach where we get all the flexibility of being able to re-use existing REST endpoints that VBCS has defined already, combined with the ability to make as many calls as required to those endpoints throughout the components operational lifecycle. Because the REST service definition and communication is managed by VBCS we can safely ignore security and endpoint relocation issues because VBCS will be handling all that for us. 

The REST Helper API

So in this article I'll be using the VBCS REST Helper API.  Internally this is the same API that the VBCS runtime uses for it's REST calling actions and the Service Data Provider variable types.  It provides a simple way to call a REST service using the abstract service and endpoint name to reference it.  The precise details of the authentication and actual URL of the endpoint are hidden from us behind that service definition so the code can remain clean and does not have to be cluttered up with concerns such as setting security tokens or having URLs move over time. 

The illustrate this I'll use a very simple REST API provided by GITHub - https://api.github.com/licenses/{license} (you can try this in your browser using this to see what it returns). What I'll do is create a simple component that makes a call to this API to get the license text detail for a given license name. 

Step 1 - Define the Service in VBCS

The first thing that we have to do of course is to define the above endpoint. I've chosen a service here that you'll all be able to get to and one which does not require any API Keys or other authorisation, just to keep things simple and easy for you to have a go at. 

We start by defining a new Service Connection:

Create service defintion in VBCS

Choose Define By Endpoint:

Define by endpointAnd define the service + endpoint:

Defining the endpointAnd press Next:

Endpoint DetailHere of course we would usually define the authentication as well, however, in this simple example we can skip that.  However, do pay attention to the Service ID field. You will need this ID later when you come to call the service. You can change the value of you wish or use the default ID as generated.  I'll use the default value of apiGithubCom here.

Next we go the the Test tab and make sure that we're getting the data we expect with an example license e.g. MIT:

Testing the endpointAt this point we press the Copy to Response Body button to describe the basic shape of the response payload and we're done so we can press the Create button.

Once the create is done, re-select the service and endpoint and make a note of the Endpoint ID as shown here. Again you can change this if you wish and I've updated mine from the default value of "getLicensesLicense" to the more readable value of getLicense.

Confirm the endpoint id

Step 2 - Make Sure the Service is Consumed

This is the step that developers often forget and in doing so spend a lot of time trying to work out why the REST Helper is not working.  In Step 1, I just defined the service and the endpoint that I needed.  I did not, however, associate it with the application that I want to use it from.  Remember that in a VBCS project you might have several Web and Mobile applications, so there is no assumption that every service will be used in every project.  Now normally, if you are using a given endpoint in the default manner, e.g. you create a Service Data Provider that uses it, or you create an Action Chain that calls it, then VBCS design time will automatically map the service as being used in the process.  However, if you're only using this endpoint programatically then you have to ensure this mapping yourself.  There are two ways of doing this:

  1. Create, and then delete, a dummy action chain that calls a REST action that uses the service endpoint that you've created 
  2. Manually edit the app-flow.json file with the correct attributes

If in doubt, use the first technique, you only have to do it once for a project to get the mapping defined. The result (and the information that you would add manually if taking approach 2) is:


  "services": {
    "apiGithubCom": {
      "path": "../../services/apiGithubCom/service.json"
    }
  },

Notice how the Service ID we noted earlier is mapped to its underlying definition.

Step 3 - Using the REST Helper API

Now all that pre-amble is complete I can actually get to some code.  At this point I'm assuming that you have a component already and as part of that component implementation you want to call the endpoint defined earlier.  Let's break this down into sub-steps:

Step 3.1 Define your Component API

You might not choose to do this, but I'd never want to hard-code any kind of connection information into my component so I'll add some properties with defaults to define the name of the service and endpoints that are going to be used:


{
    "name": "demo-license-viewer",
    "displayName": "View License",
    "description": "Allows the user to select a license and view the full text for it",
    "version": "1.0.0",
    "jetVersion": ">=5.2.0 < 7.0.0",
    "properties": {
      "license":{
        "displayName":"License",
        "description":"Short code for the license to display",
        "type":"string"
       },
      "serviceId":{
        "displayName":"Service ID",
        "type":"string",
        "value":"apiGithubCom"
       },
      "endpointId":{
        "displayName":"Endpoint ID",
        "type":"string",
        "value":"getLicense"
       }       
     }
}

Step 3.2 Consume the Helper API

Next we need to make the helper code available in the component viewModel. To do this you import the vb/helpers/rest module via the define() block of your component viewModel:


define([
    'knockout',
    'ojs/ojcore',
    'vb/helpers/rest'
], function (
    ko,
    oj, 
    RestHelper
) {

In this case, the module has been made available via the RestHelper argument to the module function, making it available throughout the component. This is the point of no-return, your component can only ever be loaded in VBCS now (unless you mock that module).

Step 3.3 Get the Endpoint

In order to start to configure and call the required endpoint we need to call the get() static function on the REST Helper passing the IDs of the service and endpoint concatenated together as a string using '/'. e.g. my endpoint would ultimately be apiGithubCom/getLicense.

In my sample here, I'm going to use the properties that I configured on the API to construct this:


  self.endpointAddress = self.properties.serviceId + '/' + self.properties.endpointId;
  var ep = RestHelper.get(self.endpointAddress);

Step 3.4 Set Parameters

In this sample we are just doing a simple GET request, but we will still need to pass one parameter, that of the license code that is being looked up, e.g. MIT. If you recall from Step 1, where I defined the endpoint, in this case this was a path parameter called license (as defined by the token in curly braces in license/{license}. However, we do the same thing with query parameters as well, which is to construct an object with the required attributes matching the parameter names and pass those to the parameters() function on the endpoint object that was received from the helper.


  ep.parameters({"license":self.properties.license});

This call to parameters() can of course include as many attributes as are required to configure the call

Step 3.5 Invoke the Endpoint

Everything is now set and you just need to call the fetch() method on the endpoint to execute it. This will return a promise that will be resolved once the REST call is complete and the response is passed back as an object for you to parse. This returned object contains a body attribute and a response attribute which includes the following key attributes:

bodyUsed Simple boolean flag to indicate if there is a body payload or not
ok Boolean flag to indicate the overall state of the call
status HTTP response code for the call
statusText HTTP response text for the call
redirected Boolean to indicate if the request was redirected

So, in my example, the text of the license is returned by the GITHub API in an attribute called body within the response body (a little confusing but that's just that particular API):


  ep.fetch().then(function(result){
    if (result.response.ok){
      //update the observable that is bound in the UI
      self.licenseText(result.body.body);
    }
    else {
      //report the error!
    }
  });

More Than Just GET Requests

In the simple example I used here, I used a GET endpoint.  However, we can use the REST Helper API with other endpoint types just as POST and DELETE as well. Everything is handled in the same way, and the fetch() method call is used to "execute" the REST call.  The main addition that you'll need to know about for POSTs in particular, is how to set the body of the request. Well, not surprisingly, you call a function called body() in the endpoint, passing it an object which defines the payload you need to send.

There are some more advanced parts of the API for dealing with transformations, but those are for discussion in a further article.

Conclusion

The VBCS REST Helper API, as we've seen;  is a powerful, simple to use and all-in-all valuable tool for the custom component developer, but should only be selected if you're sure it's the only way and / or your component will only be ever used from within VBCS where the API is available.


JET Custom Component Series

If you've just arrived at Custom JET Components and would like to learn more, then you can access the whole series of articles on the topic from the Custom JET Component Architecture Learning Path

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.