Add custom attributes to an application in WSO2 Store/Developer Portal (WSO2 AM 2.6)

Madhuri Bandara
6 min readAug 25, 2019
[ Source: https://www.skadate.com/wp-content/uploads/2017/02/bya.png]

WSO2 store or developer portal is a place for developers to self-register, explore, evaluate and subscribe to APIs. Also, it provides a web interface for API publishers to host and advertise their APIs. In the WSO2 store, when you creating applications there are predefined application attributes. However, if you want to add custom attributes to your applications, here are the steps that you need to follow. So I am about to explain a way to enable the functionality to provide a set of custom attributes while creating applications.

I believe you all have downloaded the WSO2 API Manager and I will refer the location of WSO2 API Manager as <APIM_HOME>. In order to set a custom attribute which will appear in the store portal, the attribute should be configured. This can be done in two ways,

  1. Server-specific configuration
  2. Tenant-specific configuration

I will explain about server-specific configuration in this sample scenario.

To do server-specific configurations, open <APIM_HOME>/repository/conf/api-manager.xml file and add your custom application attributes as the following example.

<ApplicationConfiguration>   <ApplicationAttributes>     <Attribute required="true">       <Name>External Reference Id</Name>       <Description>Sample description</Description>     </Attribute>   </ApplicationAttributes></ApplicationConfiguration>

Save the file and restart the server in order to see the added new custom attribute on the store portal. So now go to the store portal and click on add new application button. You will see the following interface,

[ Source: https://docs.wso2.com/download/attachments/92520819/add-attributes.png?version=2&modificationDate=1533121215000&api=v2 ]

Let’s think about a scenario where you want to add many custom attributes but those differ from application to application. In such cases, we have to add a new sub-theme for the WSO2 store.

First, repeat what we have done above and change the application attribute in the ‘api-manager.xml’ as follows,

<ApplicationConfiguration>   <ApplicationAttributes>     <Attribute required="true">       <Name>Custom Attributes</Name>       <Description>Sample custom attributes</Description>     </Attribute>   </ApplicationAttributes></ApplicationConfiguration>

Note that do not restart the server, since one more configuration should be done in order to add a subtheme for the WSO2 store.

Let’s copy the file named template.jag from the path <APIM_HOME>/repository/deployment/server/jaggeryapps/store/site/themes/wso2/templates/application/application-add.

Then create a new directory called ‘NewSubTheme’ in <APIM_HOME>/repository/deployment/server/jaggeryapps/store/site/themes/wso2/subtheme. Inside this directory create following directories templates/application/application-add and paste ‘template.jag’ into the application-add folder.

Now set this created NewSubTheme as a subtheme for WSO2 Store portal. In order to do so, edit <APIM_HOME>/repository/deployment/server/jaggeryapps/store/site/conf/site.json file by adding the following,

"theme" : {        "base" : "wso2",        "subtheme" : "NewSubTheme"     }

This is a one-time configuration that does not need any update per application creation. So now restart the server.

Let’s edit the template.jag to achieve our sample requirements. Open the template.jag and add the following to the location where the custom attributes should be placed (should be inside the form with ‘appAddForm’ id),

<div id="attributeContainer"><% if(applicationAttributes!=null) { %><input type="hidden" name="numberOfAttributes"  id="numberOfAttributes" value="<%= encode.forHtml(applicationAttributes.length) %>"/><%// Iterate through the keys, read from configuration filefor (i = 0; i < applicationAttributes.length; i++) { %><div class="form-group"><% if (applicationAttributes[i].Attribute) { %><label class="col-md-3 col-lg-3 control-label" for="attribute_<%= i%>"><%=encode.forHtml(i18n.localize(applicationAttributes[i].Attribute,applicationAttributes[i].Attribute))%><% if ( Boolean(applicationAttributes[i].required ) || applicationAttributes[i].Required ) { %><span class="requiredAstrix">*</span></label><div class="col-md-8 col-lg-6"><input type="hidden" id="attributeKey_<%= i.toString()%>" value="<%= encode.forHtml(applicationAttributes[i].Attribute) %>"/><span class="d-inline-block" tabindex="0" data-toggle="tooltip" title="<% if (applicationAttributes[i].Description) { %><%= applicationAttributes[i].Description%> <%} %>"><input type="text" class="form-control required" name="attribute_<%= i.toString()%>" id="attribute_<%= i.toString()%>"/></span></div><% } else { %></label><div class="col-md-8 col-lg-8"><input type="hidden" id="attributeKey_<%= i.toString()%>" value="<%= encode.forHtml(applicationAttributes[i].Attribute) %>"/><div class="row"><div class="col-md-5 col-lg-5"><input id="attribute_key" type="text" placeholder="property name" class="form-control"><label id="attribute_key_error" class="error hidden"></label></div><div class="col-md-5 col-lg-5"><input id="attribute_value" type="text" placeholder="property value" class="form-control"><label id="attribute_value_error" class="error hidden"></label></div><div class="col-md-2 col-lg-2"><a class="btn" class="add" id="custom_attribute_add"><span class="icon fw-stack" style="font-size:10px"><i class="fw fw-add fw-stack-1x"></i><i class="fw fw-circle-outline fw-stack-2x"></i></span></a></div></div><div class="row"><div class="col-md-8 col-lg-8"><input type="hidden" class="form-control required" name="attribute_<%= i.toString()%>" id="attribute_<%= i.toString()%>"/><div class="col-sm-6 col-lg-offset-3 col-md-6 col-xs-6" id="showData"></div></div></div><div class="row"><div class="col-md-8 col-lg-8"><table id="propertyTable" class="certificates-table table table-striped"></table></div></div></div><% }}%></div><% }}%></div>

The script for above is as follows,

<script>$('#custom_attribute_add').on('click', function() {$("#attribute_key_error").addClass("hidden").hide();$("#attribute_value_error").addClass("hidden").hide();var apiPropertiesElement = $("#attribute_0");var reservedKeyWords = ["provider", "version", "context", "status", "description", "subcontext", "doc", "lcstate","name", "tags"];var propertyKeyVal = $("#attribute_key").val().trim();var propertyVal = $("#attribute_value").val().trim();if (!propertyKeyVal || propertyKeyVal == "") {$("#attribute_key_error").text(i18n.t("Property name cannot be empty.")).removeClass("hidden").show();return;}if (!propertyVal || propertyVal == "") {$("#attribute_value_error").text(i18n.t("Property value cannot be empty.")).removeClass("hidden").show();return;}if (propertyKeyVal.indexOf(' ') >= 0) {$("#attribute_key_error").text(i18n.t("Property name should not have space. Please select a different " +"property name.")).removeClass("hidden").show();return;}for (var keyWord in reservedKeyWords) {if (propertyKeyVal.toLowerCase() === reservedKeyWords[keyWord]) {$("#attribute_key_error").text(i18n.t("Property name matches with one of the reserved keywords." +" Please select a different property name.")).removeClass("hidden").show();return;}}if (propertyKeyVal.length > 80) {$("#attribute_key_error").text(i18n.t("Property name can have maximum of 80 characters." +" Please select a different property name.")).removeClass("hidden").show();return;}if (propertyVal.length > 900) {$("#attribute_value_error").text(i18n.t("Property value can have maximum of 900 characters.")).removeClass("hidden").show();return;}var apiPropertiesValue = apiPropertiesElement.val();var apiPropertiesObject = {};if (apiPropertiesValue) {apiPropertiesObject = JSON.parse(apiPropertiesValue);}if (!apiPropertiesObject) {apiPropertiesObject = {};}if (apiPropertiesObject.hasOwnProperty(propertyKeyVal)) {$("#attribute_key_error").text(i18n.t("Property " + propertyKeyVal + " already exist for this API. Property names are" +" unique. Please select a different property name.")).removeClass("hidden").show();return;}apiPropertiesObject[propertyKeyVal] = propertyVal;document.getElementById("attribute_0").value = JSON.stringify(apiPropertiesObject);document.getElementById("attribute_key").value="";document.getElementById("attribute_value").value="";var table = document.getElementById("propertyTable");var row = table.insertRow(0);var cellKey = row.insertCell(0);var cellValue = row.insertCell(1);var cellDelButton = row.insertCell(2);cellKey.innerHTML = propertyKeyVal;cellValue.innerHTML = propertyVal;var button = document.createElement('input');button.setAttribute('type', 'button');button.setAttribute('value','Delete');button.setAttribute('color', '#FFFFFF');button.setAttribute('background-color','#4CAF50');var style = document.createElement('style');style.type = 'text/css';style.innerHTML = '.cssClass { color: #fff; background-color: #064973; border: none }';document.getElementsByTagName('head')[0].appendChild(style);button.setAttribute('class', 'cssClass');cellDelButton.append(button);button.onclick = function(){delete apiPropertiesObject[propertyKeyVal];document.getElementById("attribute_0").value = JSON.stringify(apiPropertiesObject);table.deleteRow(this.parentNode.parentNode.rowIndex);if(Object.keys(apiPropertiesObject).length === 0 && apiPropertiesObject.constructor === Object){document.getElementById("attribute_0").value = "";}};//button.setAttribute('onclick', 'removeRow(this, propertyKeyVal)');});function removeRow(oButton, propertyKeyVal) {var apiPropertiesElement = $("#attribute_0");delete apiPropertiesObject[propertyKeyVal];var empTab = document.getElementById('propertyTable');empTab.deleteRow(oButton.parentNode.parentNode.rowIndex);}</script>

You can change or do more customization to the sub-theme, no need to restart the server. It will appear when you refresh the WSO2 store portal.

Now your subtheme is ready to use. Go to the WSO2 store portal and click on the add application button. In this page, you can see our new custom attribute,

Add custom attributes to your application,

It will appear as follows in the application view page (as a JSON, since we did not customize the application-view page),

Now you can give a different number of custom attributes to your applications which might differ from one application to another. So if you need more customization simply follow these steps and customize the corresponding jaggery file according to your requirement. And add it as a sub-theme to WSO2 store 😊.

--

--