Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
Murali_Shanmu
Active Contributor
In this blog I would like to share my experience building an application which consumes some of the Leonardo services. This was something I have been working on for an internal training. This consumer app provides an option for the end user to take a picture of a product  and view the details of the product along with the product review. Below are the high level tasks which the app would perform.

  • Process the image by leveraging the Machine Learning services of SAP Cloud Platform (SAP CP) to identify the product

  • Lookup the product details which have been replicated to the HANA database

  • Retrieve product reviews which are stored in the blockchain service


Below is the solution diagram which shows the SAP CP components involved.



The focus of this blog is only on the Blockchain service. If you would like to know how to use the Machine Learning services or use the new HANA service on Cloud Foundry, you could follow the below blogs.

 

Below is the final output of the application which I built. After uploading the image, the app will use the standard pre-trained ML image classification service to identify the product as an Apple iPod and then retrieve the Product master details from HANA service and its reviews form Blockchain service.


Setup Blockchain service


In order to being working on the Hyperledger blockchain service, you would need entitlements in your Global SAP CP account. In the below screenshot, I have assigned all the relevant entitlements to my Cloud Foundry subaccount.


Configuring Hyperledger blockchain service


Once the entitlements have been assigned to your subaccount, you should be able to see the Hyperledger Fabric service in the service marketplace.



Click on the Hyperledger Fabric service and in the “Instances” menu create a new instance.



Select the plan as “dev” and accept the defaults.



In the last screen, provide a name for your instance. In my example, I have given the name “MyHyperLedger”.



Once your instance is created, open the dashboard. When prompted for login credentials, provide your SAP CP credentials (use email ID) to access the dashboard.



In the Dashboard, you should be able to see an order node and set of peers which are in running state. For this scenario, I am using Channels. Channels are like a private subnet of communication between specific members in the network and the transactions are only visible to those.

Navigate to the channels menu and create a channel specifically to maintain product reviews.



Once you have created a channel, create a service instance by clicking on the icon in the right hand corner



In the popup, you can provide a service instance name or accept the defaults.



Access the Service Instance dashboard by clicking on the icon shown below.



In this dashboard, you can explore all the transactions which have been carried out in this channel. In order interact with Hyperledger service, we would need keys. In the Overview menu, locate Service Keys section and type in “authkey” and click on “create key” button. This should give you a Client ID and Client Secret. Make a note of these. You will also need the URL when invoking the APIs later.

 


Uploading a chaincode program to the channel


Chaincode programs (referred to as smart contracts) embed the business logic and are deployed on a hyperledger channel. Chaincodes have APIs which can be used to expose the business logic. Currently chaincodes are supported in GO language. For this scenario, I have created a chaincode program which supports Read/Write/Search of product reviews.

You would need to have an. Archive file prepared with the below structure.

 



You can find my source code here in GitHub. Below are the three files which I am using.

Chaincode.yaml file contains the ID and version. Every time you make a change to the programs, you can update the version here and upload the archive file again.

Product_review.yaml file describes the HTTP interface to the chaincode

Product_review.go file contains the actual implementation of each of the operations in Go language.

You can find more info on packaging chaincode programs in SAP Help

There is a Hello World sample program which shows how to create a simple structure and use the READ/Write operations. I based my programs on top of the sample code and enhanced it for my requirements.

Note that in the Product_review.yaml file, the parameters have been defined fore each operation.
post:
operationId: create
summary: Creates a text by ID
parameters:
- $ref: '#/parameters/id'
- $ref: '#/parameters/text'
- $ref: '#/parameters/review'
- $ref: '#/parameters/name'
- $ref: '#/parameters/location'
- $ref: '#/parameters/rating'

In the Product_review.go file, I have defined a Doc structure as follows. Note that each structure fields start with a capital letter.
type Doc struct {
Text string `json:"text"`
Review string `json:"review"`
Name string `json:"name"`
Location string `json:"location"`
Rating string `json:"rating"`
}

Below is the code snippet from the Product_review.go file.. I have implemented the search function to take the input of a product and provide search results which include elements from the structure.
func (cc *ProductReview) search(stub shim.ChaincodeStubInterface, args []string) peer.Response {

searchString := strings.Replace(args[0], "\"", ".", -1) // protect against SQL injection
queryString := fmt.Sprintf("{\"selector\": {\"text\": {\"$regex\": \"%s\"}}, \"fields\": [\"text\",\"review\",\"name\",\"location\",\"rating\"], \"limit\":99}", strings.Replace(searchString, "\"", ".", -1))
resultsIterator, err := stub.GetQueryResult(queryString)
if err != nil {
return Error(http.StatusInternalServerError, err.Error())
}
defer resultsIterator.Close()

// Write return buffer
var buffer bytes.Buffer
buffer.WriteString("{ \"values\": [")
for resultsIterator.HasNext() {
it, _ := resultsIterator.Next()
if buffer.Len() > 15 {
buffer.WriteString(",")
}
var doc Doc
buffer.WriteString("{\"id\":\"")
buffer.WriteString(it.Key)
buffer.WriteString("\", \"review\":\"")
buffer.WriteString(doc.FromJson(it.Value).Review)
buffer.WriteString("\", \"product\":\"")
buffer.WriteString(doc.FromJson(it.Value).Text)
buffer.WriteString("\", \"name\":\"")
buffer.WriteString(doc.FromJson(it.Value).Name)
buffer.WriteString("\", \"location\":\"")
buffer.WriteString(doc.FromJson(it.Value).Location)
buffer.WriteString("\", \"rating\":\"")
buffer.WriteString(doc.FromJson(it.Value).Rating)
buffer.WriteString("\"}")
}
buffer.WriteString("]}")

return Success(http.StatusOK, "OK", buffer.Bytes())
}

It’s time to upload the chaincode program. Navigate to the chaincode menu.



Provide a zip file which contains all the relevant files.



Once you have deployed the zip file, you can test it by clicking on the “test chaincode”



This will open up a swagger window. Click on “Authorize” and provide the client ID and client secret captured earlier



Use the POST operation to add entries into the blockchain. You can use the GET operation to view the entries too.



Since our application is going to use blockchain to retrieve product reviews for a particular product, you can use the Search option with wildcard as shown below.


Testing using Postman REST Client


You can invoke the same APIs using Postman. We would first need to obtain an access token.

Use the GET method and provide the URL obtain during the creation of the authkey. Suffix the URL with “/oauth/token?grant_type=client_credentials”. For user name and password, provide client ID and secret. This request should provide you an access token. Make a note of it.



In a new window, use the GET method and provide the URL to invoke the search pattern function. I wasted 2 hours by using a POST method 😞

URL: https://hyperledger-fabric.cfapps.eu10.hana.ondemand.com/api/v1/chaincodes/<chaincode_ID>/latest/sea...

For Authorization, add Bearer and <access token> and submit the request. This should return list of product reviews which match the search criteria.


Creating an application which invokes ML & Blockchain service


For the HTML5 app to invoke the ML or Blockchain APIs you would need to create destinations in the SAP CP Neo environment.

 

Create your destinations with the below URLs.

Token URL: https://cal.authentication.eu10.hana.ondemand.com/oauth/token

Service URL: https://hyperledger-fabric.cfapps.eu10.hana.ondemand.com/api/v1/chaincodes/<chaincode_ID>/latest/sea...

Authentication = NoAuthentication



Once your destinations have been setup, you can refer these destinations in your HTML5 app.
var tokenURL = "/blockchaintoken"
var clientId = "<client-ID to be replaced>";
var clientSecret = "<client-secret to be replaced";

$.ajax({
url: tokenURL + "?grant_type=client_credentials",
type: "GET",
contentType: "application/json",
dataType: "json",
async: false,
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", "Basic " + btoa(clientId + ":" + clientSecret));
},
success: function (response) {
debugger;
accessToken = response.access_token;
},
timeout: 5000
});


var searchCondition = productInfo.toLowerCase();
var serviceURL = '/blockchainservice';
var productReviews = {};
$.ajax({
url: serviceURL + "/" + searchCondition,
type: "GET",
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", "Bearer " + accessToken);
},
async: false,
success: function (data) {
try {
debugger;
var results = data.values;
var productsInfo = {
reviews: []
};

for (var i in results) {
var item = results[i];
productsInfo.reviews.push({
"id": item.id,
"location": item.location,
"name": item.name,
"rating": item.rating,
"review": item.review,
"product": item.product
});
}

var oModel1 = new sap.ui.model.json.JSONModel(productsInfo);
oModel1.setDefaultBindingMode("TwoWay");
that.getView().setModel(oModel1);

} catch (err) {
MessageToast.show("Caught - [ajax error] :" + err.message);
}
},
error: function (request, status, error) {
MessageToast.show("Caught - [ajax error] :" + request.responseText);
}
});

Below is the final output of the HTML5 app which renders the output from the blockchain service APIs.

 



 
8 Comments
Labels in this area