BlockChain and OpenUI5 for a #SocialCause – Organ Transplant
Motivation for this Proof of Concept
The idea for doing this proof of concept came because of a real life problem which i have gone through in the past(will not delve to much in those details). God forbid, imagine if one or many of critical organs does not work properly then doctor advise the patient for a transplant. In India he/she can get the transplant done either from a donor from the family or from people who are declared as brain dead and their family is willing to donate the organs.
Just to summarize as the title suggest this Proof of Concept(POC) is to help all those people who are looking for Organs to be transplanted across states & country(if countries agree).. As of now in India all the hospitals are using different softwares which only communicate maximum within their organization only, their is a strong disconnect between them. Few years back,I myself was looking for a Liver for one of my family member and trust me there is nothing available. Even within hospitals of same organization there is preference given to people who can still wait over the critical ones.
This is where i believe the idea of bringing all hospital on to a network which is transparent and trustworthy came. So this POC will cover setting up of BlockChain as a backend and then making a frontend app using OpenUI5. In this part of the blog we will cover how do we set up the backend using Hyperledger Fabric Technology as a service which implements BlockChain using SAP Cloud Platform and in next we will create the app.
Image Courtesy Mainpal Hospital
What will this POC do?
Since this a POC only, we will have two type of requests which our BlockChain created via Hyperledger Fabric will entertain.
- Adding organ available for transplant to BlockChain – Pos request
- Different type of Organ available across different organization – Query
Just to highlight here for people who want to try out BlockChain as a service, I would recommend them to first understand the basics of Hyperledger Fabric then only it will make more sense to them, this documentation of hyperledger covers the basics in detail. After that i will recommend you completely read in detail the SAP Help for Hyperledger.
Creating a BlockChain Instance.
We will be using SAP Cloud platform HyperLedger Fabric as a service to create the instance as highlighted in the this blog by Akash Kumar . Since we are using cloud service it creates network with below mentioned details.
Creating a Channel
Once we have created the instance for Blockchain in previous step, next step was to create a Channel which binds the peer and the corresponding organizations. We will generate the keys for the channel which we will use in our OpenUI5 to access the chaincode API’s. Chaincode is something which interacts with the blockchain,contains the business logic and provide API access to interact with the BlockChain, details covered in next section.
Creating the Chaincode.
Once we have the Channel created in previous step, next step was to deploy our business logic and ability to access it via API which is nothing but our chaincode. Two important documents which helped me in understanding about Channels and go shall must be gone through SAP Help for ChainCode and Hyperledger Sample Chaincode
The chain code consist of three parts as mentioned below.
- One is the name of the application
Id: com-sap-icn-blockchain-organTrans9
Version: 2
- Second is the structure of API to be exposed in YAML format, this basically defines for what path which function or business logic will be called.
swagger: "2.0"
info:
description: "Organ Transplant using OpenUI5 and BlockChain"
version: "1.0"
title: "Organ Transplant using OpenUI5 and BlockChain"
consumes:
- application/x-www-form-urlencoded
produces:
- application/json
parameters:
OrganType:
name: OrganType
in: path
description: Type of Organ for Transplant
required: true
type: string
maxLength: 255
BloodGroup:
name: BloodGroup
in: formData
description: Bloodgroup
required: true
type: string
maxLength: 255
Hospital:
name: Hospital
in: formData
description: Hospital Name
required: true
type: string
maxLength: 255
City:
name: City
in: formData
description: City
required: true
type: string
maxLength: 255
State:
name: State
in: formData
description: State
required: true
type: string
maxLength: 255
paths:
/{OrganType}:
get:
operationId: organsByType
summary: Get list of Organs available for Transplant by organ type
parameters:
- $ref: '#/parameters/OrganType'
responses:
200:
description: OK
schema:
type: object
properties:
values:
type: array
items:
type: object
properties:
OrganType:
type: string
Hospital:
type: string
City :
type: string
State:
type: string
400:
description: Mismatch
404:
description: Not Found
post:
operationId: initorgan
summary: Post an organ available for Transplant
parameters:
- $ref: '#/parameters/OrganType'
- $ref: '#/parameters/BloodGroup'
- $ref: '#/parameters/Hospital'
- $ref: '#/parameters/City'
- $ref: '#/parameters/State'
responses:
200:
description: Organ for Transplant updated
201:
description: Organ for Transplant updated
400:
description: Mismatch
409:
description: Organ already posted.
- Third is basically the GO file which contain our two functions for Posting and reading the organs data.
package main
import (
"bytes"
"encoding/json"
"fmt"
"strings"
"time"
"github.com/hyperledger/fabric/core/chaincode/shim"
pb "github.com/hyperledger/fabric/protos/peer"
)
var logger = shim.NewLogger("chaincode")
type OrganDonorChainCode struct {
}
type organ struct {
OrganType string `json:"organType"`
BloodGroup string `json:"BloodGroup"`
Hospital string `json:"Hospital"`
City string `json:"City"`
State string `json:"State"`
}
// start of program
func main() {
err := shim.Start(new(OrganDonorChainCode))
if err != nil {
fmt.Printf("Error Occured: %s", err)
}
}
// Start a chaincode.
func (t *OrganDonorChainCode) Init(stub shim.ChaincodeStubInterface) pb.Response {
return shim.Success(nil)
}
// Decode incoming request and call relevant methods.
func (t *OrganDonorChainCode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
function, args := stub.GetFunctionAndParameters()
switch function {
// Creating a new organ
case "initorgan":
return t.initorgan(stub, args)
// Get list of organs by type of organ
case "organsByType":
return t.organsByType(stub, args)
default:
return shim.Error("error occured ")
}
}
// FM to add the entry for the available organ
func (t *OrganDonorChainCode) initorgan(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var err error
// key as combination of time and input aruments
organBloodGroup := args[0] + args[1] + args[2] + args[3] + args[4] + time.Now().UTC().String()
organBloodGroup1 := args[1]
Hospital := strings.ToLower(args[2])
State := strings.ToLower(args[4])
City := strings.ToLower(args[3])
// check if by chance any entry exists
organAsBytes, err := stub.GetState(organBloodGroup)
if err != nil {
return shim.Error("error occure " + err.Error())
} else if organAsBytes != nil {
fmt.Println("organ exists " + organBloodGroup)
return shim.Error("organ exists " + organBloodGroup)
}
// create organ as json
OrganType := args[0]
organ := &organ{OrganType, organBloodGroup1, Hospital, City, State}
logger.Errorf("Data %d ", organ)
organJSONasBytes, err := json.Marshal(organ)
if err != nil {
return shim.Error(err.Error())
}
// save organ to blockchain
err = stub.PutState(organBloodGroup, organJSONasBytes)
if err != nil {
return shim.Error(err.Error())
}
return shim.Success(nil)
}
func (t *OrganDonorChainCode) organsByType(stub shim.ChaincodeStubInterface, args []string) pb.Response {
Organ := args[0]
queryString := fmt.Sprintf("{\"selector\":{\"organType\":\"%s\"}}", Organ)
logger.Errorf("QueryString %d ", queryString)
queryResults, err := getQueryResultForQueryString(stub, queryString)
if err != nil {
return shim.Error(err.Error())
}
return shim.Success(queryResults)
}
// =========================================================================================
// getQueryResultForQueryString executes the passed in query string.
// Result set is built and returned as a byte array containing the JSON results.
// =========================================================================================
func getQueryResultForQueryString(stub shim.ChaincodeStubInterface, queryString string) ([]byte, error) {
fmt.Printf("- getQueryResultForQueryString queryString:\n%s\n", queryString)
resultsIterator, err := stub.GetQueryResult(queryString)
if err != nil {
return nil, err
}
defer resultsIterator.Close()
// buffer is a JSON array containing QueryRecords
var buffer bytes.Buffer
buffer.WriteString("[")
bArrayMemberAlreadyWritten := false
for resultsIterator.HasNext() {
queryResponse, err := resultsIterator.Next()
if err != nil {
return nil, err
}
// Add a comma before array members, suppress it for the first array member
if bArrayMemberAlreadyWritten == true {
buffer.WriteString(",")
}
buffer.WriteString("{\"Key\":")
buffer.WriteString("\"")
buffer.WriteString(queryResponse.Key)
buffer.WriteString("\"")
buffer.WriteString(", \"Record\":")
// Record is a JSON object, so we write as-is
buffer.WriteString(string(queryResponse.Value))
buffer.WriteString("}")
bArrayMemberAlreadyWritten = true
}
buffer.WriteString("]")
fmt.Printf("- getQueryResultForQueryString queryResult:\n%s\n", buffer.String())
return buffer.Bytes(), nil
}
Swagger Testing
This is another thing which i learnt recently. how you can define the structure of your api and then you can generate client libraries for different languages of your choice including testing etc. more details are available here . We have tested our code for basic Creating organ availability requests and searching for which organ is available for transplant where as highlighted in screenshot.
BlockChain Explorer shows you the stored content also.
Next Steps
Next steps are very important to enhance my understanding of the blockchain concepts and build a full fledge application after the successful POC.
- In next part of the series we will be developing Frontend for the POC using OpenUI5 and exploring other features
- Once POC is completed, then plan is to bring in all the features so that it can serve as single platform for organ transplant donors and receivers and many other purposes.
Last but not the list working on such POC’s bring together load many ideas to be tried and shared. Looking forward for your feedback and idea, open to all ears.
Nabheet,
Does the Hospital network need to have SAP either on Cloud or On Premise ?
K.Kiran.
Thanks for the question. SAP on premise is not needed cloud and blockchain as a service will serve the purpose.
Thanks.Hope this Service will be affordable so that it will gain wide acceptance.
K.Kiran.