github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/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 a handful of sample programs to see how Fabric
     9  apps work. These apps (and the smart contract they use) -- collectively known as
    10  ``fabcar`` -- provide a broad demonstration of Fabric functionality.  Notably, we
    11  will show the process for interacting with a Certificate Authority and generating
    12  enrollment certificates, after which we will leverage these generated identities
    13  (user objects) to query and update a ledger.
    14  
    15  We’ll go through three principle steps:
    16  
    17    **1. Setting up a development environment.** Our application needs a network to
    18    interact with, so we'll download one stripped down to just the components we need
    19    for registration/enrollment, queries and updates:
    20  
    21    .. image:: images/AppConceptsOverview.png
    22  
    23    **2. Learning the parameters of the sample smart contract our app will use.** Our
    24    smart contract contains various functions that allow us to interact with the ledger
    25    in different ways. We’ll go in and inspect that smart contract to learn about the
    26    functions our applications will be using.
    27  
    28    **3. Developing the applications to be able to query and update assets on the ledger.**
    29    We'll get into the app code itself (our apps have been written in Javascript) and
    30    manually manipulate the variables to run different kinds of queries and updates.
    31  
    32  After completing this tutorial you should have a basic understanding of how
    33  an application is programmed in conjunction with a smart contract to interact
    34  with the ledger (i.e. the peer) on a Fabric network.
    35  
    36  Setting up your Dev Environment
    37  -------------------------------
    38  
    39  First thing, let's download the Fabric images and the accompanying artifacts for the network
    40  and applications...
    41  
    42  Visit the :doc:`prereqs` page and ensure you have the necessary dependencies
    43  installed on your machine.
    44  
    45  Next, visit the :doc:`samples` page and follow the provided instructions.  Return to
    46  this tutorial once you have cloned the ``fabric-samples`` repository, and downloaded
    47  the latest stable Fabric images and available utilities.
    48  
    49  At this point everything should be installed.  Navigate to the ``fabcar`` subdirectory
    50  within your ``fabric-samples`` repository and take a look at what's inside:
    51  
    52  .. code:: bash
    53  
    54    cd fabric-samples/fabcar  && ls
    55  
    56  You should see the following:
    57  
    58  .. code:: bash
    59  
    60       enrollAdmin.js	invoke.js	package.json	query.js	registerUser.js	startFabric.sh
    61  
    62  Before starting we also need to do a little housekeeping.  Run the following command to
    63  kill any stale or active containers:
    64  
    65  .. code:: bash
    66  
    67    docker rm -f $(docker ps -aq)
    68  
    69  Clear any cached networks:
    70  
    71  .. code:: bash
    72  
    73    # Press 'y' when prompted by the command
    74  
    75    docker network prune
    76  
    77  And lastly if you've already run through this tutorial, you'll also want to delete the
    78  underlying chaincode image for the ``fabcar`` smart contract.  If you're a user going through
    79  this content for the first time, then you won't have this chaincode image on your system:
    80  
    81  .. code:: bash
    82  
    83    docker rmi dev-peer0.org1.example.com-fabcar-1.0-5c906e402ed29f20260ae42283216aa75549c571e2e380f3615826365d8269ba
    84  
    85  Install the clients & launch the network
    86  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    87  
    88  .. note:: The following instructions require you to be in the ``fabcar`` subdirectory
    89            within your local clone of the ``fabric-samples`` repo.  Remain at the
    90            root of this subdirectory for the remainder of this tutorial.
    91  
    92  Run the following command to install the Fabric dependencies for the applications.
    93  We are concerned with ``fabric-ca-client`` which will allow our app(s) to communicate
    94  with the CA server and retrieve identity material, and with ``fabric-client`` which
    95  allows us to load the identity material and talk to the peers and ordering service.
    96  
    97  .. code:: bash
    98  
    99    npm install
   100  
   101  Launch your network using the ``startFabric.sh`` shell script.  This command
   102  will spin up our various Fabric entities and launch a smart contract container for
   103  chaincode written in Golang:
   104  
   105  .. code:: bash
   106  
   107    ./startFabric.sh
   108  
   109  Alright, now that you’ve got a sample network and some code, let’s take a
   110  look at how the different pieces fit together.
   111  
   112  How Applications Interact with the Network
   113  ------------------------------------------
   114  
   115  For a more in-depth look at the components in our ``fabcar`` network (and how
   116  they're deployed) as well as how applications interact with those components
   117  on more of a granular level, see :doc:`understand_fabcar_network`.
   118  
   119  Developers more interested in seeing what applications **do** -- as well as
   120  looking at the code itself to see how an application is constructed -- should
   121  continue. For now, the most important thing to know is that applications use
   122  a software development kit (SDK) to access the **APIs** that permit queries and
   123  updates to the ledger.
   124  
   125  Enrolling the Admin User
   126  ------------------------
   127  
   128  .. note:: The following two sections involve communication with the Certificate
   129            Authority.  You may find it useful to stream the CA logs when running
   130            the upcoming programs.
   131  
   132  To stream your CA logs, split your terminal or open a new shell and issue the following:
   133  
   134  .. code:: bash
   135  
   136    docker logs -f ca.example.com
   137  
   138  Now hop back to your terminal with the ``fabcar`` content...
   139  
   140  When we launched our network, an admin user - ``admin`` - was registered with our
   141  Certificate Authority.  Now we need to send an enroll call to the CA server and
   142  retrieve the enrollment certificate (eCert) for this user.  We won't delve into enrollment
   143  details here, but suffice it to say that the SDK and by extension our applications
   144  need this cert in order to form a user object for the admin.  We will then use this admin
   145  object to subsequently register and enroll a new user.  Send the admin enroll call to the CA
   146  server:
   147  
   148  .. code:: bash
   149  
   150    node enrollAdmin.js
   151  
   152  This program will invoke a certificate signing request (CSR) and ultimately output
   153  an eCert and key material into a newly created folder - ``hfc-key-store`` - at the
   154  root of this project.  Our apps will then look to this location when they need to
   155  create or load the identity objects for our various users.
   156  
   157  Register and Enroll ``user1``
   158  -----------------------------
   159  
   160  With our newly generated admin eCert, we will now communicate with the CA server
   161  once more to register and enroll a new user.  This user - ``user1`` - will be
   162  the identity we use when querying and updating the ledger.  It's important to
   163  note here that it is the ``admin`` identity that is issuing the registration and
   164  enrollment calls for our new user (i.e. this user is acting in the role of a registrar).
   165  Send the register and enroll calls for ``user1``:
   166  
   167  .. code:: bash
   168  
   169    node registerUser.js
   170  
   171  Similar to the admin enrollment, this program invokes a CSR and outputs the keys
   172  and eCert into the ``hfc-key-store`` subdirectory.  So now we have identity material for two
   173  separate users - ``admin`` & ``user1``.  Time to interact with the ledger...
   174  
   175  Querying the Ledger
   176  -------------------
   177  
   178  Queries are how you read data from the ledger. This data is stored as a series
   179  of key/value pairs, and you can query for the value of a single key, multiple
   180  keys, or -- if the ledger is written in a rich data storage format like JSON --
   181  perform complex searches against it (looking for all assets that contain
   182  certain keywords, for example).
   183  
   184  This is a representation of how a query works:
   185  
   186  .. image:: images/QueryingtheLedger.png
   187  
   188  First, let's run our ``query.js`` program to return a listing of all the cars on
   189  the ledger.  We will use our second identity - ``user1`` - as the signing entity
   190  for this application.  The following line in our program specifies ``user1`` as
   191  the signer:
   192  
   193  .. code:: bash
   194  
   195    fabric_client.getUserContext('user1', true);
   196  
   197  Recall that the ``user1`` enrollment material has already been placed into our
   198  ``hfc-key-store`` subdirectory, so we simply need to tell our application to grab that identity.
   199  With the user object defined, we can now proceed with reading from the ledger.
   200  A function that will query all the cars, ``queryAllCars``, is
   201  pre-loaded in the app, so we can simply run the program as is:
   202  
   203  .. code:: bash
   204  
   205    node query.js
   206  
   207  It should return something like this:
   208  
   209  .. code:: json
   210  
   211    Query result count =  1
   212    Response is  [{"Key":"CAR0", "Record":{"colour":"blue","make":"Toyota","model":"Prius","owner":"Tomoko"}},
   213    {"Key":"CAR1",   "Record":{"colour":"red","make":"Ford","model":"Mustang","owner":"Brad"}},
   214    {"Key":"CAR2", "Record":{"colour":"green","make":"Hyundai","model":"Tucson","owner":"Jin Soo"}},
   215    {"Key":"CAR3", "Record":{"colour":"yellow","make":"Volkswagen","model":"Passat","owner":"Max"}},
   216    {"Key":"CAR4", "Record":{"colour":"black","make":"Tesla","model":"S","owner":"Adriana"}},
   217    {"Key":"CAR5", "Record":{"colour":"purple","make":"Peugeot","model":"205","owner":"Michel"}},
   218    {"Key":"CAR6", "Record":{"colour":"white","make":"Chery","model":"S22L","owner":"Aarav"}},
   219    {"Key":"CAR7", "Record":{"colour":"violet","make":"Fiat","model":"Punto","owner":"Pari"}},
   220    {"Key":"CAR8", "Record":{"colour":"indigo","make":"Tata","model":"Nano","owner":"Valeria"}},
   221    {"Key":"CAR9", "Record":{"colour":"brown","make":"Holden","model":"Barina","owner":"Shotaro"}}]
   222  
   223  These are the 10 cars. A black Tesla Model S owned by Adriana, a red Ford Mustang
   224  owned by Brad, a violet Fiat Punto owned by Pari, and so on. The ledger is
   225  key/value based and in our implementation the key is ``CAR0`` through ``CAR9``.
   226  This will become particularly important in a moment.
   227  
   228  Let's take a closer look at this program.  Use an editor (e.g. atom or visual studio)
   229  and open ``query.js``.
   230  
   231  The initial section of the application defines certain variables such as
   232  channel name, cert store location and network endpoints. In our sample app, these
   233  variables have been baked-in, but in a real app these variables would have to
   234  be specified by the app dev.
   235  
   236  .. code:: bash
   237  
   238    var channel = fabric_client.newChannel('mychannel');
   239    var peer = fabric_client.newPeer('grpc://localhost:7051');
   240    channel.addPeer(peer);
   241  
   242    var member_user = null;
   243    var store_path = path.join(__dirname, 'hfc-key-store');
   244    console.log('Store path:'+store_path);
   245    var tx_id = null;
   246  
   247  This is the chunk where we construct our query:
   248  
   249  .. code:: bash
   250  
   251    // queryCar chaincode function - requires 1 argument, ex: args: ['CAR4'],
   252    // queryAllCars chaincode function - requires no arguments , ex: args: [''],
   253    const request = {
   254      //targets : --- letting this default to the peers assigned to the channel
   255      chaincodeId: 'fabcar',
   256      fcn: 'queryAllCars',
   257      args: ['']
   258    };
   259  
   260  When the application ran, it invoked the ``fabcar`` chaincode on the peer, ran the
   261  ``queryAllCars`` function within it, and passed no arguments to it.
   262  
   263  To take a look at the available functions within our smart contract, navigate
   264  to the ``chaincode/fabcar/go`` subdirectory at the root of ``fabric-samples`` and open
   265  ``fabcar.go`` in your editor.
   266  
   267  .. note:: These same functions are defined within the Node.js version of the
   268            ``fabcar`` chaincode.
   269  
   270  You'll see that we have the following functions available to call: ``initLedger``,
   271  ``queryCar``, ``queryAllCars``, ``createCar``, and ``changeCarOwner``.
   272  
   273  Let's take a closer look at the ``queryAllCars`` function to see how it
   274  interacts with the ledger.
   275  
   276  .. code:: bash
   277  
   278    func (s *SmartContract) queryAllCars(APIstub shim.ChaincodeStubInterface) sc.Response {
   279  
   280  	startKey := "CAR0"
   281  	endKey := "CAR999"
   282  
   283  	resultsIterator, err := APIstub.GetStateByRange(startKey, endKey)
   284  
   285  This defines the range of ``queryAllCars``. Every car between ``CAR0`` and
   286  ``CAR999`` -- 1,000 cars in all, assuming every key has been tagged properly
   287  -- will be returned by the query.
   288  
   289  Below is a representation of how an app would call different functions in
   290  chaincode.  Each function must be coded against an available API in the chaincode
   291  shim interface, which in turn allows the smart contract container to properly
   292  interface with the peer ledger.
   293  
   294  .. image:: images/RunningtheSample.png
   295  
   296  We can see our ``queryAllCars`` function, as well as one called ``createCar``,
   297  that will allow us to update the ledger and ultimately append a new block to
   298  the chain in a moment.
   299  
   300  But first, go back to the ``query.js`` program and edit the constructor request
   301  to query ``CAR4``. We do this by changing the function in ``query.js`` from
   302  ``queryAllCars`` to ``queryCar`` and passing ``CAR4`` as the specific key.
   303  
   304  The ``query.js`` program should now look like this:
   305  
   306  .. code:: bash
   307  
   308    const request = {
   309      //targets : --- letting this default to the peers assigned to the channel
   310      chaincodeId: 'fabcar',
   311      fcn: 'queryCar',
   312      args: ['CAR4']
   313    };
   314  
   315  Save the program and navigate back to your ``fabcar`` directory.  Now run the
   316  program again:
   317  
   318  .. code:: bash
   319  
   320    node query.js
   321  
   322  You should see the following:
   323  
   324  .. code:: json
   325  
   326    {"colour":"black","make":"Tesla","model":"S","owner":"Adriana"}
   327  
   328  If you go back and look at the result from when we queried every car before,
   329  you can see that ``CAR4`` was Adriana’s black Tesla model S, which is the result
   330  that was returned here.
   331  
   332  Using the ``queryCar`` function, we can query against any key (e.g. ``CAR0``)
   333  and get whatever make, model, color, and owner correspond to that car.
   334  
   335  Great. At this point you should be comfortable with the basic query functions
   336  in the smart contract and the handful of parameters in the query program.
   337  Time to update the ledger...
   338  
   339  Updating the Ledger
   340  -------------------
   341  
   342  Now that we’ve done a few ledger queries and added a bit of code, we’re ready to
   343  update the ledger. There are a lot of potential updates we could make, but
   344  let's start by creating a car.
   345  
   346  Below we can see how this process works. An update is proposed, endorsed,
   347  then returned to the application, which in turn sends it to be ordered and
   348  written to every peer's ledger:
   349  
   350  .. image:: images/UpdatingtheLedger.png
   351  
   352  Our first update to the ledger will be to create a new car.  We have a separate
   353  Javascript program -- ``invoke.js`` -- that we will use to make updates. Just
   354  as with queries, use an editor to open the program and navigate to the
   355  code block where we construct our invocation:
   356  
   357  .. code:: bash
   358  
   359    // createCar chaincode function - requires 5 args, ex: args: ['CAR12', 'Honda', 'Accord', 'Black', 'Tom'],
   360    // changeCarOwner chaincode function - requires 2 args , ex: args: ['CAR10', 'Barry'],
   361    // must send the proposal to endorsing peers
   362    var request = {
   363      //targets: let default to the peer assigned to the client
   364      chaincodeId: 'fabcar',
   365      fcn: '',
   366      args: [''],
   367      chainId: 'mychannel',
   368      txId: tx_id
   369    };
   370  
   371  You'll see that we can call one of two functions - ``createCar`` or
   372  ``changeCarOwner``. First, let’s create a red Chevy Volt and give it to an
   373  owner named Nick. We're up to ``CAR9`` on our ledger, so we'll use ``CAR10``
   374  as the identifying key here. Edit this code block to look like this:
   375  
   376  .. code:: bash
   377  
   378    var request = {
   379      //targets: let default to the peer assigned to the client
   380      chaincodeId: 'fabcar',
   381      fcn: 'createCar',
   382      args: ['CAR10', 'Chevy', 'Volt', 'Red', 'Nick'],
   383      chainId: 'mychannel',
   384      txId: tx_id
   385    };
   386  
   387  Save it and run the program:
   388  
   389  .. code:: bash
   390  
   391     node invoke.js
   392  
   393  There will be some output in the terminal about ``ProposalResponse`` and
   394  promises. However, all we're concerned with is this message:
   395  
   396  .. code:: bash
   397  
   398     The transaction has been committed on peer localhost:7053
   399  
   400  To see that this transaction has been written, go back to ``query.js`` and
   401  change the argument from ``CAR4`` to ``CAR10``.
   402  
   403  In other words, change this:
   404  
   405  .. code:: bash
   406  
   407    const request = {
   408      //targets : --- letting this default to the peers assigned to the channel
   409      chaincodeId: 'fabcar',
   410      fcn: 'queryCar',
   411      args: ['CAR4']
   412    };
   413  
   414  To this:
   415  
   416  .. code:: bash
   417  
   418    const request = {
   419      //targets : --- letting this default to the peers assigned to the channel
   420      chaincodeId: 'fabcar',
   421      fcn: 'queryCar',
   422      args: ['CAR10']
   423    };
   424  
   425  Save once again, then query:
   426  
   427  .. code:: bash
   428  
   429    node query.js
   430  
   431  Which should return this:
   432  
   433  .. code:: bash
   434  
   435     Response is  {"colour":"Red","make":"Chevy","model":"Volt","owner":"Nick"}
   436  
   437  Congratulations. You’ve created a car!
   438  
   439  So now that we’ve done that, let’s say that Nick is feeling generous and he
   440  wants to give his Chevy Volt to someone named Dave.
   441  
   442  To do this go back to ``invoke.js`` and change the function from ``createCar``
   443  to ``changeCarOwner`` and input the arguments like this:
   444  
   445  .. code:: bash
   446  
   447    var request = {
   448      //targets: let default to the peer assigned to the client
   449      chaincodeId: 'fabcar',
   450      fcn: 'changeCarOwner',
   451      args: ['CAR10', 'Dave'],
   452      chainId: 'mychannel',
   453      txId: tx_id
   454    };
   455  
   456  The first argument -- ``CAR10`` -- reflects the car that will be changing
   457  owners. The second argument -- ``Dave`` -- defines the new owner of the car.
   458  
   459  Save and execute the program again:
   460  
   461  .. code:: bash
   462  
   463    node invoke.js
   464  
   465  Now let’s query the ledger again and ensure that Dave is now associated with the
   466  ``CAR10`` key:
   467  
   468  .. code:: bash
   469  
   470    node query.js
   471  
   472  It should return this result:
   473  
   474  .. code:: bash
   475  
   476     Response is  {"colour":"Red","make":"Chevy","model":"Volt","owner":"Dave"}
   477  
   478  The ownership of ``CAR10`` has been changed from Nick to Dave.
   479  
   480  .. note:: In a real world application the chaincode would likely have some access
   481            control logic. For example, only certain authorized users may create
   482            new cars, and only the car owner may transfer the car to somebody else.
   483  
   484  Summary
   485  -------
   486  
   487  Now that we’ve done a few queries and a few updates, you should have a pretty
   488  good sense of how applications interact with the network. You’ve seen the basics
   489  of the roles smart contracts, APIs, and the SDK play in queries and updates and
   490  you should have a feel for how different kinds of applications could be used to
   491  perform other business tasks and operations.
   492  
   493  In subsequent documents we’ll learn how to actually **write** a smart contract
   494  and how some of these more low level application functions can be leveraged
   495  (especially relating to identity and membership services).
   496  
   497  Additional Resources
   498  --------------------
   499  
   500  The `Hyperledger Fabric Node SDK repo <https://github.com/hyperledger/fabric-sdk-node>`__
   501  is an excellent resource for deeper documentation and sample code.  You can also consult
   502  the Fabric community and component experts on `Hyperledger Rocket Chat <https://chat.hyperledger.org/home>`__.
   503  
   504  .. Licensed under Creative Commons Attribution 4.0 International License
   505     https://creativecommons.org/licenses/by/4.0/