Building Advance Pattern

Building Advance Pattern

In this topic we will cover how to build advance Patterns by adding few lines of Javascript. This tutorial assumes that you are already familiar with basics of how the pattern is built, if not it is recommended to get familiar with Building Your First Pattern .

NOTE: As we are mostly dealing with HTML and Javascript code in this tutorial, it is required for users to have a basic knowledge of jQuery and HTML.


Use Case :-
Lets create a HTTP requester processor pattern that allows the use to select a RAML API from exchange as part of pattern UI configuration.
As part of project generation the selected RAML will be copied to resources directory and the same will be referred from HTTP request component.

We will be creating a custom HTML page using the "Advance Form Builder" section and add custom Javascript code to get list of RAML APis from exchange and display it to the user

  1. Basic Details

1. Navigate to " Pattern Builder" menu of IZ Accelerators.
2. Click on " Create New" option 
3. Create a new Pattern called " HTTP Requester", Version " 1.0.0", System Type " 3.8.x", select Pattern Type as " Processor Pattern" and click on Next to move on to "Pattern Implementation"

  1. Configuring Template 

Let's configure our pattern  (Logger -> DW -> HTTP -> DW -> Logger). 

1: Edit the default template's name " template" to " http_requester"
2: Delete the default configuration & add the below Mule xml configuration 


 <logger level="INFO" doc:name="Log Processing Start"/>
        <dw:transform-message doc:name="Prepare HTTP Request">
            <dw:set-payload><![CDATA[%dw 1.0
%output application/java
---
{
}]]></dw:set-payload>
        </dw:transform-message>
        <http:request config-ref="" path="" method="" doc:name="Invoke Service"/>
        <dw:transform-message doc:name="Transform HTTP Response">
            <dw:set-payload><![CDATA[%dw 1.0
%output application/java
---
{
}]]></dw:set-payload>
        </dw:transform-message>
        <logger level="INFO" doc:name="Log Processing End"/>

3. Add a new template called " http_config", which is basically our HTTP connector configuration
4.  Delete the default configuration & add the below Mule xml configuration 


 <http:request-config name="HTTP_Request_Configuration" doc:name="HTTP Request Configuration">
        <http:raml-api-configuration location="{{details.apiName}}/{{details.rootRaml}}"/>
    </http:request-config>
  1. Configuring User Interface 
Lets create a search box where users can search for APIs while configuring the pattern

1.  Click on the " UI Configuration " tab
2: In the " Advance Form Builder" section, replace the default content with following HTML code. 


<div class="modal-content">
    <div class="modal-body">
        <div class="rendered-form">
                
              <h5>Enter the search keyword and click on the search button to search for a REST API </h5>
              <div class="row">
                    <div class="col-md-9">
                        <input type="text" class="form-control" id="http_requester_exchange_search_term" placeholder="Search for an API" name="search" value="">
                    </div>
                    <div class="col-md-2">
                        <button type="button" class="btn btn-primary" id="http_requester_search_raml_apis">Search</button>
                    </div>
                </div>
                <div class="row mt-5">
                    <div class="col-md-12">
                        <table class="table" id="http_requester_api_list_table">
                            <thead>
                            <tr>
                                <th>Name</th>
                                <th>Created By</th>
                                <th>Version</th>
                            </tr>
                            </thead>
                            <tbody id="http_requester_api_list" >
                            </tbody>
                        </table>
                    </div>
                </div>
        </div>
    </div>
    <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> <button type="button" class="btn btn-primary select_{{nodeId}}" data-dismiss="modal">Submit</button>
    </div>
</div> 

3. Focus out of the editor and you should be able to see the preview similar to below screen shot.



4. Click on "Use custom javascript" 



5. Paste the below javascript code in the JS editor.  Follow the comments in HTML for more info

/**
 * Get access token from exchange using AJAX call.
 * Q library is used here for better handling of Async calls 
 **/
 function getAccessTokenFromExchange() {
     return Q($.ajax({
type: 'get',
cache: false,
headers: {
'accept':'application/json'
}
}));
 }

/**
 * Code to search for RAML APIs from exchange based on the search criteria 
 * Q library is used here for better handling of Async calls 
 **/
 function getExchangeAPIs(searchTerm) {
     // Utility function from IZ to display loading icon 
      Util.loadStart();
      return getAccessTokenFromExchange()
                .then(function(accessTokenResponse){
                    // Access token to access Anypoint APIs 
                    var accessToken = 'bearer ' + accessTokenResponse.accessToken;
                    
                    /**
                     * Invoke Anypoint API to get the list of RAML APIs based on seach criteria 
                     **/
                     var exchangeRequest = {
                        "query": "{ assets(query: {searchTerm: \""+searchTerm+"\", type: \"rest-api\"},latestVersionsOnly: true)  {   groupId, version, name, assetId, createdBy { firstName, lastName },updatedAt,files { classifier, packaging,externalLink },tags {value},organizationId  } }",
                        "variables": {
                            "accessToken": accessTokenResponse.accessToken
                        }
                    };  

                    /**
                     * Invoke Anypoint API to get the list of RAML APIs based on seach criteria 
                     **/
                    return Q($.ajax({
                        url: 'https://anypoint.mulesoft.com/graph/api/v1/graphql',
                        type: 'post',
                        contentType: "application/json",
                        data: JSON.stringify(exchangeRequest)
                    }));
                })
                .then(function(apisList) {
                    /**
                    * Parse the received assets details and populate the html table
                    * Sample Response Structure
                    *{
                    *  "data": {
                    *    "assets": [
                    *      {
                    *        "organizationId": "52fe2647-1153-46b7-8725-33430cd480ba",
                    *        "groupId": "52fe2647-1153-46b7-8725-33430cd480ba",
                    *        "assetId": "iz-starter-kit",
                    *        "version": "1.0.0",
                    *        "createdBy": {
                    *            "firstName": "Msch022019",
                    *            "lastName": "Msch022019"
                    *         },
                    *        "files": [
                    *          {
                    *            "classifier": "raml",
                    *            "packaging": "zip",
                    *            "externalLink": "..."
                    *          },
                    *          {
                    *            "classifier": "fat-raml",
                    *            "packaging": "zip",
                    *            "externalLink": "..."
                    *          }
                    *        ],
                    *        "type": "rest-api"
                    *      },
                    *     {
                    *      ...   
                    *     }
                    *    ]
                    *  }
                    *} 
                    **/
                    var assetHtml = '';
                    $.each(apisList.data.assets, function(index, asset) {
                        /**
                         * Get the asset download link for type fat-raml
                         * */
                        var assetUrl = $.grep(asset.files, function (e) {
                            return e.classifier == 'fat-raml';
                        })[0];
                    
                        assetHtml += '<tr>' +
                                        '<td> <input type="radio" name="http_requester_selected_api" asset-name="'+asset.name+'" value="'+assetUrl.externalLink+'" '+(index === 0 ? 'checked': '')+'> '+asset.name+'</td>' +
                                        '<td>'+asset.createdBy.firstName+'</td>' +
                                        '<td>'+asset.version+'</td>' +
                                    '</tr>';
                    });
                    console.log(assetHtml);
                    
                    $('#http_requester_api_list').html(assetHtml);
                    
                })
                .catch(function (error) {
                    console.log(error);
                    return Util.loadEndWithError('Error fetching RAML APIs', error);
                })
                .done(function() {
                    // Utility function from IZ to stop displaying loading icon
                    Util.loadEnd();
                });
 }


/**
 * Listener for API search button  
 **/
$(document).off("click","#http_requester_search_raml_apis"); 
$(document).on("click","#http_requester_search_raml_apis",function() { 
    // Retrieve the enterd search criteria and get the RAML APIs 
    getExchangeAPIs($('#http_requester_exchange_search_term').val());
});

/**
 * Listener listening on final submit click
 **/
$(document).off("click",".select_{{nodeId}}"); 
$(document).on("click",".select_{{nodeId}}",function() { 
  var componentId = "{{nodeId}}"; 
   
  var selectedAsset = $('input[name="http_requester_selected_api"]:checked').val();
  var assetName = $('input[name="http_requester_selected_api"]:checked').attr('asset-name');
  assetName = assetName.trim().replace(new RegExp(' ', 'g'), '_').toLowerCase();
   
  Util.loadStart();
  // Utility function from IZ to download binary file
  // We are downloading the raml api zip file here to find out the root raml name, which in turn will be used in HTTP connector
  Q(Asset.downloadBinaryFile(selectedAsset))
      .then(function (zipFile) {
                return JSZip.loadAsync(zipFile);
        })
        .then(function(ramlContents) {
            return ramlContents.file("exchange.json").async("string");
        })
        .then(function(exchangeJson) {
             exchangeJson = JSON.parse(exchangeJson);
             console.log(exchangeJson);
             
          FlowEditor.componentEditDetails[componentId] = {
        rootRaml: exchangeJson.main,
        assetUrl: selectedAsset,
        apiName: assetName
        };
         
        console.log(FlowEditor.componentEditDetails[componentId]);
        return '';
        })
        .catch(function (error) {
            console.log(error);
            return Util.loadEndWithError('Error fetching root RAML name', error);
        })
        .done(function() {
            // Utility function from IZ to stop displaying loading icon
            Util.loadEnd();
        });
 }); 


  1. Main Configuration
1. Configuring " Namespace" action. Namespace action adds the namespace to Mule configuration file.
Drag & Drop " Namespace" action from the "Action Types" section to "Action Sequence"

Target Folder: {{{flowDetails.targetFolder}}}   - Target folder of the configuration file
Target File Name: {{{flowDetails.targetFileName}}}   - Target file to add the namespace
Namespace Prefix: xmlns:dw

Click on "Add Another Action" and add the following properties

Target Folder: {{{flowDetails.targetFolder}}}   - Target folder of the configuration file
Target File Name: {{{flowDetails.targetFileName}}}   - Target file to add the namespace
Namespace Prefix: xmlns:http

Click on "Add Another Action" and add the following properties

Target Folder: src/main/app  - Target folder of the configuration file
Target File Name: global.xml  - Target file to add the namespace
Namespace Prefix: xmlns:http

Preview should look similar to below screenshot


2. Configure Copy RAML action
Drag & Drop " Copy RAML " action from the "Action Types" section to "Action Sequence"

Target Folder Path src/main/resources/{{details.apiName}}

Preview should look similar to below screenshot

3.  Configuring " Global Config " action. Adds the contents of "sfdcconfig.mst" to global.xml Mule configuration.
Drag & Drop " Global Config" action from the "Action Types" section to "Action Sequence"

Source Template: template/http_config.mst  - Template name configured in Templates section
Target Folder: - src/main/app   - Target folder of the configuration file
Target File Name: global.xml  - Target file to add the namespace

Preview should look similar to below screenshot


4.  Configuring " Append To Flow " action. Adds the contents of  project_x_salesforce.mst  to the project's Mule configuration file
Drag & Drop " Append To Flow" action from the "Action Types" section to "Action Sequence"

Source Template Path : template/http_requester.mst  - Template name configured in Templates section
Target Directory: - {{{flowDetails.targetFolder}}}   - Target folder of the configuration file
Target File: {{flowDetails.targetFileName}}  - Target file to add the namespace
Target Flow: {{flowDetails.targetFlowName}}  - Target flow name. This field is optional and will be derived dynamically based on the project

Preview should look similar to below screenshot


5. Click on the " Create Pattern" to upload the new pattern to your current exchange session.

  1. Generating Project using HTTP Requester Pattern
1. Click on " Generate Project" menu option and fill the basic details
2. In the next section select any source and add " HTTP Requester" pattern to the flow as shown in the screenshot below



3. Configure the " HTTP Requester" Pattern by selected a RAML API as shown in the screenshot below



4. Move to the next section and generate the project. Unzip the file and import the same in Anypoint Studio
5. We should have the RAML API copied to resources directory of the project and the HTTP Connector configured with the root RAML location as shown in the screenshot below






    • Related Articles

    • Building Your First Pattern

      This page will help you get started with building your first pattern. If you already are familiar with patterns and have built your first pattern, you can skip ahead to Building Advance Patterns  Let's understand the basics of a Pattern and then move ...