日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Hyperledger Fabric Rest API服务开发教程【含源码】

發布時間:2025/3/21 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Hyperledger Fabric Rest API服务开发教程【含源码】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Hyperledger Fabric Rest API服務開發教程【含源碼】

Hyperledger Fabric 提供了軟件開發包/SDK以幫助開發者訪問fabric網絡 和部署在網絡上的鏈碼,但是Hyperledger Fabric官方沒有提供簡單易用的REST API訪問接口,在這個教程里我們將學習如何利用Hyperledger Fabric的SDK 來開發REST API服務器。

1、系統結構概述

相關推薦:H..Fabric Java 開發教程?|?H..Fabric Nodejs開發教程

整個系統包含兩個物理節點:

  • Fabric節點:運行Fabric示例中的First Network,并且實例化了Fabcar鏈碼
  • API服務器節點:運行REST API Server代碼供外部訪問

下面是部署在AWS上的兩個節點實例的情況:

首先參考官方文檔安裝hyperledger fabric。

然后運行腳本fabcar/startFabric.sh:

1 2 cd fabric-samples/fabcar ./startFabric.sh

上述腳本運行之后,我們就得到一個正常運轉的Hyperledger Fabric網絡(著名的演示網絡First Network),包含2個機構/4個對等節點, 通道為mychannel,鏈碼Fabcar安裝在全部4個對等節點上并且在mychannel上激活。賬本中有10條車輛記錄,這是調用 合約的initLedger方法的結果。

現在我們為REST API Server準備身份標識數據。使用fabcar/javascript創建一個用戶標識user1,我們將在REST API Server 中使用這個身份標識:

1 2 3 4 5 cd javascript npm install node enrollAdmin.js node registerUser.js ls wallet/user1

運行結果如下:

現在Rest API Server需要的東西都備齊了:

  • org1的連接配置文件:first-network/connection-org1.json
  • Node.js包文件:fabcar/package.json
  • User1身份錢包:fabcar/javascript/wallet/user1/

后面我們會把這些數據文件拷貝到Rest API Server。

2、Rest API Server設計

我們使用ExressJS來開發API服務,利用query.js和invoke.js 中的代碼實現與fabric交互的邏輯。API設計如下:

  • GET /api/queryallcars:返回全部車輛記錄
  • GET /api/query/CarID:返回指定ID的車輛記錄
  • POST /api/addcar/:添加一條新的車輛記錄
  • PUT /api/changeowner/CarID:修改指定ID的車輛記錄

3、Rest API Server代碼實現

apiserver.js代碼如下:

express

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 var bodyParser = require('body-parser');var app = express(); app.use(bodyParser.json());// Setting for Hyperledger Fabric const { FileSystemWallet, Gateway } = require('fabric-network'); const path = require('path'); const ccpPath = path.resolve(__dirname, '.', 'connection-org1.json');app.get('/api/queryallcars', async function (req, res) {try {// Create a new file system based wallet for managing identities.const walletPath = path.join(process.cwd(), 'wallet');const wallet = new FileSystemWallet(walletPath);console.log(`Wallet path: ${walletPath}`);// Check to see if we've already enrolled the user.const userExists = await wallet.exists('user1');if (!userExists) {console.log('An identity for the user "user1" does not exist in the wallet');console.log('Run the registerUser.js application before retrying');return;}// Create a new gateway for connecting to our peer node.const gateway = new Gateway();await gateway.connect(ccpPath, { wallet, identity: 'user1', discovery: { enabled: true, asLocalhost: false } });// Get the network (channel) our contract is deployed to.const network = await gateway.getNetwork('mychannel');// Get the contract from the network.const contract = network.getContract('fabcar');// Evaluate the specified transaction.// queryCar transaction - requires 1 argument, ex: ('queryCar', 'CAR4')// queryAllCars transaction - requires no arguments, ex: ('queryAllCars')const result = await contract.evaluateTransaction('queryAllCars');console.log(`Transaction has been evaluated, result is: ${result.toString()}`);res.status(200).json({response: result.toString()});} catch (error) {console.error(`Failed to evaluate transaction: ${error}`);res.status(500).json({error: error});process.exit(1);} });app.get('/api/query/:car_index', async function (req, res) {try {// Create a new file system based wallet for managing identities.const walletPath = path.join(process.cwd(), 'wallet');const wallet = new FileSystemWallet(walletPath);console.log(`Wallet path: ${walletPath}`);// Check to see if we've already enrolled the user.const userExists = await wallet.exists('user1');if (!userExists) {console.log('An identity for the user "user1" does not exist in the wallet');console.log('Run the registerUser.js application before retrying');return;}// Create a new gateway for connecting to our peer node.const gateway = new Gateway();await gateway.connect(ccpPath, { wallet, identity: 'user1', discovery: { enabled: true, asLocalhost: false } });// Get the network (channel) our contract is deployed to.const network = await gateway.getNetwork('mychannel');// Get the contract from the network.const contract = network.getContract('fabcar');// Evaluate the specified transaction.// queryCar transaction - requires 1 argument, ex: ('queryCar', 'CAR4')// queryAllCars transaction - requires no arguments, ex: ('queryAllCars')const result = await contract.evaluateTransaction('queryCar', req.params.car_index);console.log(`Transaction has been evaluated, result is: ${result.toString()}`);res.status(200).json({response: result.toString()});} catch (error) {console.error(`Failed to evaluate transaction: ${error}`);res.status(500).json({error: error});process.exit(1);} });app.post('/api/addcar/', async function (req, res) {try {// Create a new file system based wallet for managing identities.const walletPath = path.join(process.cwd(), 'wallet');const wallet = new FileSystemWallet(walletPath);console.log(`Wallet path: ${walletPath}`);// Check to see if we've already enrolled the user.const userExists = await wallet.exists('user1');if (!userExists) {console.log('An identity for the user "user1" does not exist in the wallet');console.log('Run the registerUser.js application before retrying');return;}// Create a new gateway for connecting to our peer node.const gateway = new Gateway();await gateway.connect(ccpPath, { wallet, identity: 'user1', discovery: { enabled: true, asLocalhost: false } });// Get the network (channel) our contract is deployed to.const network = await gateway.getNetwork('mychannel');// Get the contract from the network.const contract = network.getContract('fabcar');// Submit the specified transaction.// createCar transaction - requires 5 argument, ex: ('createCar', 'CAR12', 'Honda', 'Accord', 'Black', 'Tom')// changeCarOwner transaction - requires 2 args , ex: ('changeCarOwner', 'CAR10', 'Dave')await contract.submitTransaction('createCar', req.body.carid, req.body.make, req.body.model, req.body.colour, req.body.owner);console.log('Transaction has been submitted');res.send('Transaction has been submitted');// Disconnect from the gateway.await gateway.disconnect();} catch (error) {console.error(`Failed to submit transaction: ${error}`);process.exit(1);} })app.put('/api/changeowner/:car_index', async function (req, res) {try {// Create a new file system based wallet for managing identities.const walletPath = path.join(process.cwd(), 'wallet');const wallet = new FileSystemWallet(walletPath);console.log(`Wallet path: ${walletPath}`);// Check to see if we've already enrolled the user.const userExists = await wallet.exists('user1');if (!userExists) {console.log('An identity for the user "user1" does not exist in the wallet');console.log('Run the registerUser.js application before retrying');return;}// Create a new gateway for connecting to our peer node.const gateway = new Gateway();await gateway.connect(ccpPath, { wallet, identity: 'user1', discovery: { enabled: true, asLocalhost: false } });// Get the network (channel) our contract is deployed to.const network = await gateway.getNetwork('mychannel');// Get the contract from the network.const contract = network.getContract('fabcar');// Submit the specified transaction.// createCar transaction - requires 5 argument, ex: ('createCar', 'CAR12', 'Honda', 'Accord', 'Black', 'Tom')// changeCarOwner transaction - requires 2 args , ex: ('changeCarOwner', 'CAR10', 'Dave')await contract.submitTransaction('changeCarOwner', req.params.car_index, req.body.owner);console.log('Transaction has been submitted');res.send('Transaction has been submitted');// Disconnect from the gateway.await gateway.disconnect();} catch (error) {console.error(`Failed to submit transaction: ${error}`);process.exit(1);} })app.listen(8080);

代碼中對原來fabcar的query.js和invoke.js修改如下:

  • ccpPath修改為當前目錄,因為我們要使用同一路徑下的連接配置文件connection-org1.json
  • 在gateway.connect調用中,修改選項discovery.asLocalhost為false

4、Rest API Server的連接配置文件

API服務依賴于連接配置文件來正確連接fabric網絡。文件 connection-org1.json 可以直接從 fabric網絡中獲取:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 {"name": "first-network-org1","version": "1.0.0","client": {"organization": "Org1","connection": {"timeout": {"peer": {"endorser": "300"}}}},"organizations": {"Org1": {"mspid": "Org1MSP","peers": ["peer0.org1.example.com","peer1.org1.example.com"],"certificateAuthorities": ["ca.org1.example.com"]}},"peers": {"peer0.org1.example.com": {"url": "grpcs://localhost:7051","tlsCACerts": {"pem": "-----BEGIN CERTIFICATE-----\nMIICVjCCAf2gAwIBAgIQEB1sDT11gzTv0/N4cIGoEjAKBggqhkjOPQQDA jB2MQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGF tcGxlLmNvbTEfMB0GA1UEAxMWdGxz\nY2Eub3JnMS5leGFtcGxlLmNvbTAeFw0xOTA5MDQwMjQzMDBaFw0yOTA5MDEwMjQz\nMDBaMHYxCzAJB gNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH\nEw1TYW4gRnJhbmNpc2NvMRkwFwYDVQQKExBvcmcxLmV4YW1wbGUuY29tM R8wHQYD\nVQQDExZ0bHNjYS5vcmcxLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D\nAQcDQgAEoN0qd5hM2SDfvGzNjTCXuQqyk+X K4VISa16/y9iXBPpa0onyAXJuv7T0\noPf+mh3T7/g8uYtV2bwTpT2XFO3Q6KNtMGswDgYDVR0PAQH/BAQDAgGmMB0GA1Ud\nJQQWMBQGCCsGA QUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1Ud\nDgQiBCCalpyChmrLtpgOll6TVmlMOO/2iiyI2PadNPsIYx51mTAKBggqh kjOPQQD\nAgNHADBEAiBLNoAYWe9LvoxxBxl3sUM64kl7rx6dI3JU+dJG6FRxWgIgCu1ONEyp\nfux9lZWr6gcrIdsn/8fQuWiOIbAgq0HSr60 =\n-----END CERTIFICATE-----\n"},"grpcOptions": {"ssl-target-name-override": "peer0.org1.example.com","hostnameOverride": "peer0.org1.example.com"}},"peer1.org1.example.com": {"url": "grpcs://localhost:8051","tlsCACerts": {"pem": "-----BEGIN CERTIFICATE-----\nMIICVjCCAf2gAwIBAgIQEB1sDT11gzTv0/N4cIGoEjAKBggqhkjOPQQDA jB2MQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGF tcGxlLmNvbTEfMB0GA1UEAxMWdGxz\nY2Eub3JnMS5leGFtcGxlLmNvbTAeFw0xOTA5MDQwMjQzMDBaFw0yOTA5MDEwMjQz\nMDBaMHYxCzAJB gNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH\nEw1TYW4gRnJhbmNpc2NvMRkwFwYDVQQKExBvcmcxLmV4YW1wbGUuY29tM R8wHQYD\nVQQDExZ0bHNjYS5vcmcxLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D\nAQcDQgAEoN0qd5hM2SDfvGzNjTCXuQqyk+X K4VISa16/y9iXBPpa0onyAXJuv7T0\noPf+mh3T7/g8uYtV2bwTpT2XFO3Q6KNtMGswDgYDVR0PAQH/BAQDAgGmMB0GA1Ud\nJQQWMBQGCCsGA QUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1Ud\nDgQiBCCalpyChmrLtpgOll6TVmlMOO/2iiyI2PadNPsIYx51mTAKBggqh kjOPQQD\nAgNHADBEAiBLNoAYWe9LvoxxBxl3sUM64kl7rx6dI3JU+dJG6FRxWgIgCu1ONEyp\nfux9lZWr6gcrIdsn/8fQuWiOIbAgq0HSr60 =\n-----END CERTIFICATE-----\n"},"grpcOptions": {"ssl-target-name-override": "peer1.org1.example.com","hostnameOverride": "peer1.org1.example.com"}}},"certificateAuthorities": {"ca.org1.example.com": {"url": "https://localhost:7054","caName": "ca-org1","tlsCACerts": {"pem": "-----BEGIN CERTIFICATE-----\nMIICUTCCAfegAwIBAgIQSiMHm4n9QvhD6wltAHkZPTAKBggqhkjOPQQDA jBzMQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGF tcGxlLmNvbTEcMBoGA1UEAxMTY2Eu\nb3JnMS5leGFtcGxlLmNvbTAeFw0xOTA5MDQwMjQzMDBaFw0yOTA5MDEwMjQzMDBa\nMHMxCzAJBgNVB AYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T\nYW4gRnJhbmNpc2NvMRkwFwYDVQQKExBvcmcxLmV4YW1wbGUuY29tMRwwG gYDVQQD\nExNjYS5vcmcxLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE\nz93lOhLJG93uJQgnh93QcPPal5NQXQnAutF KYkun/eMHMe23wNPd0aJhnXdCjWF8\nMRHVAjtPn4NVCJYiTzSAnaNtMGswDgYDVR0PAQH/BAQDAgGmMB0GA1UdJQQWMBQG\nCCsGAQUFBwMCB ggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdDgQiBCDK\naDhLwl3RBO6eKgHh4lHJovIyDJO3jTNb1ix1W86bFjAKBggqhkjOPQQDA gNIADBF\nAiEA8KTKkjQwb1TduTWWkmsLmKdxrlE6/H7CfsdeGE+onewCIHJ1S0nLhbWYv+G9\nTbAFlNCpqr0AQefaRT3ghdURrlbo\n----- END CERTIFICATE-----\n"},"httpOptions": {"verify": false}}} }

當fabcar/startFabric.sh執行時,我們可以交叉檢查證書的傳播是否正確。 peer0.org1和 peer1.org1 的證書是org1的 TLS root CA 證書簽名的。

注意所有的節點都以localhost引用,我們稍后會將其修改為Fabric Node的 公開IP地址。

5、用戶身份標識

我們已經在Fabric節點上生成了一個用戶標識user1并保存在wallet目錄中, 我們可以看到有三個對應的文件:私鑰、公鑰和證書對象:

稍后我們會把這些文件拷貝到Rest API Server上。

6、安裝Rest API Server節點

1、首先在Rest API Server節點上安裝npm、node:

1 2 3 4 5 6 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-essentialnode -v npm -v

驗證結果如下:

2、然后在Rest API Server上創建一個目錄:

1 2 mkdir apiserver cd apiserver

3、接下來將下面的文件從Fabric節點拷貝到Rest API Server節點。我們 利用loccalhost在兩個EC2實例間拷貝:

1 2 3 4 5 6 7 # 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/

運行結果如下:

4、可以看到現在所有的文件都拷貝到Rest API Server了,為了保持一致,我們將user1/改名為wallet/user1/:

1 2 3 cd apiserver mkdir wallet mv user1 wallet/user1

運行結果如下:

5、現在在Rest API Server上創建上面的apiserver.js文件。

6、修改連接配置文件connection-org1.json 中的fabric節點的ip地址:

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

運行結果如下:

7、在/etc/hosts中增加條目以便可以正確解析fabric節點的IP:

1 2 3 4 5 6 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

運行結果如下:

8、安裝必要的依賴包:

1 2 npm install npm install express body-parser --save

9、萬事俱備,啟動Rest API Server:

1 node apiserver.js

7、訪問API

我們的API服務在8080端口監聽,在下面的示例中,我們使用curl來 演示如何訪問。

1、查詢所有車輛記錄

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

運行結果如下:

2、添加新的車輛記錄并查詢

1 2 3 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/addcarcurl http://[API-Server-Node-IP]:8080/api/query/CAR12

運行結果如下:

3、修改車輛所有者并再次查詢

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

運行結果如下:

我們也可以用postman得到同樣的結果:


原文鏈接:An Implementation of API Server for Hyperledger Fabric Network

總結

以上是生活随笔為你收集整理的Hyperledger Fabric Rest API服务开发教程【含源码】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。