github.com/kchristidis/fabric@v1.0.4-0.20171028114726-837acd08cde1/docs/source/write_first_app.rst (about) 1 Writing Your First Application 2 ============================== 3 4 .. note:: If you're not yet familiar with the fundamental architecture of a 5 Fabric network, you may want to visit the :doc:`blockchain` and 6 :doc:`build_network` documentation prior to continuing. 7 8 In this section we'll be looking at two sample applications to see how Fabric 9 apps work. These apps (and the smart contract they use) -- collectively known as 10 "Fabcar" -- involve querying a ledger that has been pre-populated with cars and 11 then updating that ledger to add new cars and to change car owners. 12 13 We’ll go through three principle steps: 14 15 **1. Setting up a development environment.** Our application needs a network to 16 interact with, so we'll download one stripped down to just the components we need 17 to run queries and updates: 18 19 .. image:: images/AppConceptsOverview.png 20 21 **2. Learning the parameters of the sample smart contract our app will use.** Our 22 smart contract contains various functions that allow us to interact with the ledger 23 in different ways. We’ll go in and inspect that smart contract to learn about the 24 functions our applications will be using. 25 26 **3. Developing the applications to be able to query and update Fabric records.** 27 We'll get into the app code itself (our apps have been written in Javascript) and 28 manually manipulate the variables to run different kinds of queries and updates. 29 30 After completing this tutorial you should have a basic understanding of how 31 an application is programmed in conjunction with a smart contract to interact 32 with the ledger on a Fabric network. All in about 30 minutes. 33 34 First, let's get our network and our apps... 35 36 Setting up a Development Environment 37 ------------------------------------ 38 39 Visit the :doc:`prereqs` page and ensure you have the necessary dependencies 40 installed on your machine. 41 42 Also, let's remove any containers and chaincode (smart contracts run on 43 chaincode) images you might have running to ensure you don't have a port 44 conflict or Docker issue. 45 46 First, remove the containers: 47 48 .. code:: bash 49 50 docker rm -f $(docker ps -aq) 51 52 Next, delete the chaincode image: 53 54 .. code:: bash 55 56 docker rmi dev-peer0.org1.example.com-fabcar-1.0 57 58 Now that your machine is set up, navigate to a directory where you want the 59 samples downloaded to and issue the clone command: 60 61 .. code:: bash 62 63 git clone https://github.com/hyperledger/fabric-samples.git 64 65 This command will create a directory, ``fabric-samples`` (in which multiple 66 samples and tutorial apps have now been downloaded), and a specific 67 subdirectory, ``fabcar``. 68 69 Enter that directory: 70 71 .. code:: bash 72 73 cd fabric-samples/fabcar 74 75 Now take a look at what's inside your ``fabcar`` directory. 76 77 .. code:: bash 78 79 ls 80 81 You should see the following: 82 83 .. code:: bash 84 85 creds invoke.js package.json query.js startFabric.sh 86 87 Use the ``startFabric.sh`` script to launch the network. This script downloads 88 and extracts the Fabric docker images, so it will take a few minutes to 89 complete: 90 91 .. code:: bash 92 93 ./startFabric.sh 94 95 One last thing. We need to install the SDK (software development kit) node 96 modules: 97 98 .. code:: bash 99 100 npm install 101 102 Alright, now that you’ve got a sample network and some code, let’s take a 103 look at how the different pieces fit together. 104 105 How Applications Interact with the Network 106 ------------------------------------------ 107 108 For a more in-depth look at the components in our Fabcar network (and how 109 they're deployed) as well as how applications interact with those components 110 on more of a granular level, click :doc:`understand_fabcar_network`. 111 112 Developers more interested in seeing what applications **do** -- as well as 113 looking at the code itself to see how an application is constructed -- should 114 continue. For now, the most important thing to know is that applications use 115 a software development kit (SDK) to access the **APIs** that permit queries and 116 updates to the ledger. 117 118 Querying the Ledger 119 ------------------- 120 121 Queries are how you read data from the ledger. This data is stored as a series 122 of key/value pairs, and you can query for the value of a single key, multiple 123 keys, or -- if the ledger is written in a rich data storage format like JSON -- 124 perform complex searches against it (looking for all assets that contain 125 certain keywords, for example). 126 127 This is a representation of how a query works: 128 129 .. image:: images/QueryingtheLedger.png 130 131 .. note:: You will issue all subsequent commands from the ``fabcar`` directory. 132 133 First, let's run our ``query.js`` program to return a listing of all the cars on 134 the ledger. A function that will query all the cars, ``queryAllCars``, is 135 pre-loaded in the app, so we can simply run the program as is: 136 137 .. code:: bash 138 139 node query.js 140 141 It should return something like this: 142 143 .. code:: json 144 145 Query result count = 1 146 Response is [{"Key":"CAR0", "Record":{"colour":"blue","make":"Toyota","model":"Prius","owner":"Tomoko"}}, 147 {"Key":"CAR1", "Record":{"colour":"red","make":"Ford","model":"Mustang","owner":"Brad"}}, 148 {"Key":"CAR2", "Record":{"colour":"green","make":"Hyundai","model":"Tucson","owner":"Jin Soo"}}, 149 {"Key":"CAR3", "Record":{"colour":"yellow","make":"Volkswagen","model":"Passat","owner":"Max"}}, 150 {"Key":"CAR4", "Record":{"colour":"black","make":"Tesla","model":"S","owner":"Adriana"}}, 151 {"Key":"CAR5", "Record":{"colour":"purple","make":"Peugeot","model":"205","owner":"Michel"}}, 152 {"Key":"CAR6", "Record":{"colour":"white","make":"Chery","model":"S22L","owner":"Aarav"}}, 153 {"Key":"CAR7", "Record":{"colour":"violet","make":"Fiat","model":"Punto","owner":"Pari"}}, 154 {"Key":"CAR8", "Record":{"colour":"indigo","make":"Tata","model":"Nano","owner":"Valeria"}}, 155 {"Key":"CAR9", "Record":{"colour":"brown","make":"Holden","model":"Barina","owner":"Shotaro"}}] 156 157 These are the 10 cars. A black Tesla Model S owned by Adriana, a red Ford Mustang 158 owned by Brad, a violet Fiat Punto owned by Pari, and so on. The ledger is 159 key/value based and in our implementation the key is ``CAR0`` through ``CAR9``. 160 This will become particularly important in a moment. 161 162 Now let's see what it looks like under the hood (if you'll forgive the pun). 163 Use an editor (e.g. atom or visual studio) and open the ``query.js`` program. 164 165 The initial section of the application defines certain variables such as 166 chaincode ID, channel name and network endpoints. In our sample app, these 167 variables have been baked-in, but in a real app these variables would have to 168 be specified by the app dev. 169 170 .. code:: bash 171 172 var options = { 173 wallet_path: path.join(__dirname, './network/creds'), 174 user_id: 'PeerAdmin', 175 channel_id: 'mychannel', 176 chaincode_id: 'fabcar', 177 network_url: 'grpc://localhost:7051', 178 }; 179 180 This is the chunk where we construct our query: 181 182 .. code:: bash 183 184 // queryCar - requires 1 argument, ex: args: ['CAR4'], 185 // queryAllCars - requires no arguments , ex: args: [''], 186 const request = { 187 chaincodeId: options.chaincode_id, 188 txId: transaction_id, 189 fcn: 'queryAllCars', 190 args: [''] 191 }; 192 193 When the application ran, it invoked the fabcar smart contract, ran the 194 ``queryAllCars`` function within it, and passed no arguments to it. 195 196 To take a look at the available functions within our smart contract, navigate 197 to the ``chaincode`` subdirectory and open ``fabcar.go`` in your editor. You'll 198 see that we have the following functions available to call: ``initLedger``, 199 ``queryCar``, ``queryAllCars``, ``createCar``, and ``changeCarOwner``. 200 201 Let's take a closer look at the ``queryAllCars`` function to see how it 202 interacts with the ledger. 203 204 .. code:: bash 205 206 func (s *SmartContract) queryAllCars(APIstub shim.ChaincodeStubInterface) sc.Response { 207 208 startKey := "CAR0" 209 endKey := "CAR999" 210 211 resultsIterator, err := APIstub.GetStateByRange(startKey, endKey) 212 213 This defines the range of ``queryAllCars``. Every car between ``CAR0`` and 214 ``CAR999`` -- 1,000 cars in all, assuming every call has been tagged properly 215 -- will be returned by the query. 216 217 Below is a representation of how an app would call different functions in 218 chaincode, showing the various APIs -- ``createCar``, ``queryallCars``, etc -- 219 available to use. 220 221 .. image:: images/RunningtheSample.png 222 223 We can see our ``queryAllCars`` function, as well as one called ``createCar``, 224 that will allow us to update the ledger and ultimately append a new block to 225 the chain in a moment. 226 227 But first, go back to the ``query.js`` program and edit the constructor request 228 to query ``CAR4``. We do this by changing the function in ``query.js`` from 229 ``queryAllCars`` to ``queryCar`` and passing ``CAR4`` as the specific 230 “argument” (or “key”). 231 232 ``query.js`` should now look like this: 233 234 .. code:: bash 235 236 const request = { 237 chaincodeId: options.chaincode_id, 238 txId: transaction_id, 239 fcn: 'queryCar', 240 args: ['CAR4'] 241 }; 242 243 Save the program and navigate back to your ``fabcar`` directory. Now run the 244 program again: 245 246 .. code:: bash 247 248 node query.js 249 250 You should see the following: 251 252 .. code:: json 253 254 {"colour":"black","make":"Tesla","model":"S","owner":"Adriana"} 255 256 If you go back and look at the result from when we queried every car before, 257 you can see that CAR4 was Adriana’s black Tesla model S, which is the result 258 that was returned here. 259 260 Using the ``queryCar`` function, we can query against any key (e.g. ``CAR0``) 261 and get whatever make, model, color, and owner correspond to that car. 262 263 Great. At this point you should be comfortable with the basic query functions 264 in the smart contract and the handful of parameters in the query program. 265 Time to update the ledger... 266 267 Updating the Ledger 268 ------------------- 269 270 Now that we’ve done a few ledger queries and added a bit of code, we’re ready to 271 update the ledger. There are a lot of potential updates we could make, but 272 let's start by creating a car. 273 274 Below we can see how this process works. An update is proposed, endorsed, 275 then returned to the application, which sends it to be ordered and written 276 to the ledger: 277 278 .. image:: images/UpdatingtheLedger.png 279 280 Our first update to the ledger will be to create a new car. We have a separate 281 Javascript program -- ``invoke.js`` -- that we will use to make updates. Just 282 as with queries, use an editor to open the program and navigate to the 283 codeblock where we construct our invocation: 284 285 .. code:: bash 286 287 // createCar - requires 5 args, ex: args: ['CAR11', 'Honda', 'Accord', 'Black', 'Tom'], 288 // changeCarOwner - requires 2 args , ex: args: ['CAR10', 'Barry'], 289 // send proposal to endorser 290 var request = { 291 targets: targets, 292 chaincodeId: options.chaincode_id, 293 fcn: '', 294 args: [''], 295 chainId: options.channel_id, 296 txId: tx_id 297 }; 298 299 You'll see that we can call one of two functions - ``createCar`` or 300 ``changeCarOwner``. First, let’s create a red Chevy Volt and give it to an 301 owner named Nick. We're up to ``CAR9`` on our ledger, so we'll use ``CAR10`` 302 as the identifying key here. Edit this codeblock to look like this: 303 304 .. code:: bash 305 306 var request = { 307 targets: targets, 308 chaincodeId: options.chaincode_id, 309 fcn: 'createCar', 310 args: ['CAR10', 'Chevy', 'Volt', 'Red', 'Nick'], 311 chainId: options.channel_id, 312 txId: tx_id 313 }; 314 315 Save it and run the program: 316 317 .. code:: bash 318 319 node invoke.js 320 321 There will be some output in the terminal about Proposal Response and 322 Transaction ID. However, all we're concerned with is this message: 323 324 .. code:: bash 325 326 The transaction has been committed on peer localhost:7053 327 328 To see that this transaction has been written, go back to ``query.js`` and 329 change the argument from ``CAR4`` to ``CAR10``. 330 331 In other words, change this: 332 333 const request = { 334 chaincodeId: options.chaincode_id, 335 txId: transaction_id, 336 fcn: 'queryCar', 337 args: ['CAR4'] 338 }; 339 340 To this: 341 342 .. code:: bash 343 344 const request = { 345 chaincodeId: options.chaincode_id, 346 txId: transaction_id, 347 fcn: 'queryCar', 348 args: ['CAR10'] 349 }; 350 351 Save once again, then query: 352 353 .. code:: bash 354 355 node query.js 356 357 Which should return this: 358 359 .. code:: bash 360 361 Response is {"colour":"Red","make":"Chevy","model":"Volt","owner":"Nick"} 362 363 Congratulations. You’ve created a car! 364 365 So now that we’ve done that, let’s say that Nick is feeling generous and he 366 wants to give his Chevy Volt to someone named Barry. 367 368 To do this go back to ``invoke.js`` and change the function from ``createCar`` 369 to ``changeCarOwner`` and input the arguments like this: 370 371 .. code:: bash 372 373 var request = { 374 targets: targets, 375 chaincodeId: options.chaincode_id, 376 fcn: 'changeCarOwner', 377 args: ['CAR10', 'Barry'], 378 chainId: options.channel_id, 379 txId: tx_id 380 }; 381 382 The first argument -- ``CAR10`` -- reflects the car that will be changing 383 owners. The second argument -- ``Barry`` -- defines the new owner of the car. 384 385 Save and execute the program again: 386 387 .. code:: bash 388 389 node invoke.js 390 391 Now let’s query the ledger and see that it’s been updated to reflect this: 392 393 .. code:: bash 394 395 node query.js 396 397 It should return this result: 398 399 .. code:: bash 400 401 Response is {"colour":"Red","make":"Chevy","model":"Volt","owner":"Barry"} 402 403 The ownership of ``CAR10`` has been changed from Nick to Barry. 404 405 Summary 406 ------- 407 408 Now that we’ve done a few queries and a few updates, you should have a pretty 409 good sense of how applications interact with the network. You’ve seen the basics 410 of the roles smart contracts, APIs, and the SDK play in queries and updates and 411 you should have a feel for how different kinds of applications could be used to 412 perform other business tasks and operations. 413 414 In subsequent documents we’ll learn how to actually **write** a smart contract 415 and how some of these more low level application functions can be leveraged 416 (especially relating to identity and membership services). 417 418 Additional Resources 419 -------------------- 420 421 The `Hyperledger Fabric Node SDK repo <https://github.com/hyperledger/fabric-sdk-node>`__ 422 is an excellent resource for deeper documentation and sample code. You can also consult 423 the Fabric community and component experts on `Hyperledger Rocket Chat <https://chat.hyperledger.org/home>`__. 424 425 .. Licensed under Creative Commons Attribution 4.0 International License 426 https://creativecommons.org/licenses/by/4.0/