An Implementation of API Server for Hyperledger Fabric Network
By: Kc Tam
Tags: Rest Api, Blockchain Application, Hyperledger Fabric, Nodejs

Overview

Hyperledger Fabric comes with the Software Development Kit (SDK) for external access to a fabric network and chaincode functions deployed in the fabric network. Nowadays a more popular way of accessing an application is through REST API, which is not yet available officially in Hyperledger Fabric. Nevertheless it is not very difficult to implement one with some libraries.

This article is to show how to use ExpressJS to implement one. For those following me, you may notice that this has been shown in my previous article “Deep-Dive into Fabcar” (link). In this article, I run the API server in a separate instance. I see this as more realistic implementation.

Again I am using Fabcar as the application (chaincode) and First Network as the fabric network. The API server code is largely adopted from the original javascript code, with modification to meet the deployment.

Setup

In this setup we have two physical nodes

Fabric Node : which runs the First Network with Fabcar chaincode instantiated

: which runs the First Network with Fabcar chaincode instantiated API Server Node: which runs the API Server code and for external access

Here are the two nodes deployed as EC2 instances in AWS.

Setup the Fabric Node

Step 1: Make a fabric node by installing the prerequisite tools and all software related to Hyperledger Fabric. I am using release 1.4.3 in this demonstration. You can make reference to my previous article about building a fabric node.

Step 2: Run script fabcar/startFabric.sh .

cd fabric-samples/fabcar

./startFabric.sh

After this script is fully executed, we now have a running First Network (2-org 4-peer setup), mychannel is up, Fabcar chaincode is installed on all four peer nodes, and instantiated on mychannel. The ledger has 10 car records, which is a result of initLedger() being invoked. Everything on the fabric network side is up and running.

To understand more about the First Network and Fabcar application, please take a look on my previous article, which has a more detail description.

Now let’s prepare an identity for API Server.

Step 3: Use client codes provided in fabcar/javascript to create a user (user1) identity. This will be used in API Server.

cd javascript

npm install

node enrollAdmin.js

node registerUser.js

ls wallet/user1

Now we have all we need for API Server. They are

Connection profile for org1: first-network/connection-org1.json

Node Package file: fabcar/package.json

User1 identity or wallet: fabcar/javascript/wallet/user1/

These files will be copied to API Server later.

API Server: Design

We are using ExpressJS to build the API Server, and leveraging the client code query.js and invoke.js to build the actual logic. Here we discuss a bit the code and configuration setup.

API design

We are going to define four APIs. They are

GET /api/queryallcars return all cars

return all cars GET /api/query/CarID return the car record of CarID specified

return the car record of CarID specified POST /api/addcar/ add a new car record with detail specified in body

add a new car record with detail specified in body PUT /api/changeowner/CarID change the car record with a new owner specified in body

apiserver.js

This is a standard ExpressJS code for an API Server. There are some modification from the provided query.js and invoke.js inside fabcar/javascript .

ccpPath is changed to the current directory as we are going to keep connection-org1.json in the same path.

is changed to the current directory as we are going to keep in the same path. in the gateway.connect of all APIs we change the option of discovery.asLocalhost to false

Connection Profile: connection-org1.json

The API Server relies on the connection profile given in order to make correct connection to fabric network. The file connection-org1.json is directly obtained from the fabric network, i.e., first-network.

As we can cross-check the certificates are properly propagated when fabcar/startFabric.sh is executed. Those for peer0.org1 and peer1.org1 are taken from the TLS root CA cert of org1, while the one for CA is the CA certificate of org1.

Note that all nodes are referred to localhost. We need to change it to the Fabric Node public IP later.

User Identity

We have generated a user (user1) on Fabric Node. They are stored inside wallet directory. Inside which we see three files. They are the private key (signing key), public key and an object keeping the required information such as certificate.

We will copy this identity to API server later.

Setup the API Server Node

Step 1: Install npm, node and make on the API Server Node.

sudo apt-get update

sudo apt install curl

curl -sL https://deb.nodesource.com/setup_8.x | sudo bash -

sudo apt install -y nodejs

sudo apt-get install build-essential node -v

npm -v

Step 2: Create a directory in API server.

mkdir apiserver

cd apiserver

Step 3: Copy the following files from Fabric Node to the API server. We use a localhost to copy between the two EC2 instances.

# localhost (update your own IP of the two servers) # temp is an empty directory

cd temp scp -i ~/Downloads/aws.pem ubuntu@[Fabric-Node-IP]:/home/ubuntu/fabric-samples/first-network/connection-org1.json . scp -i ~/Downloads/aws.pem ubuntu@[Fabric-Node-IP]:/home/ubuntu/fabric-samples/fabcar/javascript/package.json . scp -r -i ~/Downloads/aws.pem ubuntu@[Fabric-Node-IP]:/home/ubuntu/fabric-samples/fabcar/javascript/wallet/user1/ . scp -r -i ~/Downloads/aws.pem * ubuntu@[API-Server-Node-IP]:/home/ubuntu/apiserver/

Step 4: We see all these files now in API Server. For sake of consistence we move user1/ to wallet/user1/ .

cd apiserver

mkdir wallet

mv user1 wallet/user1

Step 5: Now create the apiserver.js file for the API server.

Step 6: Modify the connection profile connection-org1.json with the Fabric Node IP address.

sed -i 's/localhost/[Fabric-Node-IP]/g' connection-org1.json

Step 7: Add entries in /etc/hosts such that they will point to Fabric Node.

127.0.0.1 localhost

[Fabric-Node-IP] orderer.example.com

[Fabric-Node-IP] peer0.org1.example.com

[Fabric-Node-IP] peer1.org1.example.com

[Fabric-Node-IP] peer0.org2.example.com

[Fabric-Node-IP] peer1.org2.example.com

Step 8: Install the required modules.

npm install

npm install express body-parser --save

Step 9: Now we have all the required modules. We can run API server.

node apiserver.js

Access the API

Our API server listens to port 8080. We set up the API Server Node such that these APIs are accessible everywhere. In this demo I am using my localhost to access the APIs with curl.

Test 1: Query all cars

curl http://[API-Server-Node-IP]:8080/api/queryallcars

Here we see the 10 preloaded car records in the ledger

Test 2: Add a new car and query that car

curl -d '{"carid":"CAR12","make":"Honda","model":"Accord","colour":"black","owner":"Tom"}' -H "Content-Type: application/json" -X POST http://[API-Server-Node-IP]:8080/api/addcar curl http://[API-Server-Node-IP]:8080/api/query/CAR12

We see the newly added car record in ledger.

Test 3: Change owner for a car and query that car again

curl http://[API-Server-Node-IP]:8080/api/query/CAR4 curl -d '{"owner":"KC"}' -H "Content-Type: application/json" -X PUT http://[API-Server-Node-IP]:8080/api/changeowner/CAR4 curl http://[API-Server-Node-IP]:8080/api/query/CAR4

We see the owner of a specified car updated in the ledger.

And we get the same result using Postman.

Discussion

Though we are using one Fabric Node to simulate a whole fabric network, this setup should be applicable to more complex deployment (e.g. multi-node, multi-channel). What we need is to provide the correct connection profile for API server to access. Note that the digital identity (certificate) is kept in API Server. This means that all transactions, no matter issued from anyone outside the world, are “proxied” by the API Server. If we need access control on the API Server, it is something beyond the Hyperledger Fabric. We can use traditional methods to control the access to API Server. If we wish to identify the incoming user in the fabric network level, we need to pass the user identity to end user, and develop a mechanism to let user sign the transaction. It is out of the scope of this article. This approach should be easily adapted into docker container, as far as all required components and configuration are done when creating an image. It can be further optimized with proper variable setup to avoid manual modification.

Summary

We have used a separate EC2 instance holding the API Server, accessing a fabric network with chaincode deployed. This serves a standard way to allow other applications or frontend accessing those chaincode functions according to the logic defined in the API server.