API Gateway Developer Guide

REST API For Nimble Logistic Contract.

This repository provides the API endpoints for a Nimble Logisitic Contract.

This acts as the API gateway which exposes the functionality of smart contracts to the out side world.

Running the server:

In order to start the server first you have to get the Fabric Connection Profile. This is required for the gateway to proceed and connect with the smart contracts.

This is standing out side of the Block Chain Eco System and it connecs with the smart contract based on the credentials we are providing.

The current client is using A FileSystemWallet to manage identities for interacting with the network.

$ npm install
$ npm run build
$ npm start

Controllers

There are two types of main controllers which mainly works as the gateways for the 2 exposed contracts.

  1. IDENTITY CONTROLLER :- Connects with the Identity smart contract and perform identity related tasks and exposes them as API’s
  2. BP CONTROLLER :- Connects with Logistic smart contract and perform logistic tracing related tasks and exposes them as API’s

IDENTITY CONTROLLER

There are several actions that Identity controller performs.

  1. Register User :- During the registration to Nimble platform this will add the user to block chain state.
  2. Get User :- Providing id of the user retrieve the user details from the block chain state.
  3. Update User :- Change the organization of an identity in case base platform user update.
  4. Delete User :- Delete user from the block chain state by providing id.
  5. UserExists :- Check weather the user exists in the block chain state.
  6. Get User from Email :- Retrieve user based on other attributes like user email.

BP CONTROLLER

There are several actions that BP controller performs.

  1. Create Order :- Add a new order state to the block chain.
  2. Delete Order :- Delete an order from block chain state.
  3. Get Order :- Get order from block chain state.
  4. Order Exists :- Check weather an order exists in block chain state.
  5. Update Order :- Change the custodian and location of an order.

Working with muyltiple contracts in Chain Code.

In Fabric there is Chaincodes which can be defined as a collection of Smart Contracts.

This client has the ability to connect to any chaincode and any smart contract defined in those chain codes.

Look at the below sample on how to define this in the fabri-connection.json file.

 "conn1": [
      {
        "channel": "mychannel",
        "chaincodes": {
          "logistic-contract": ["org.nimble.supplychain_network.identity","org.nimble.supplychain_network.logistic"]
        }
      }

How desgin API Controllers.

Apart from the currently defined ones you can easily define you’re controllers.

  1. Define the path configuration (Connection, Allowed Clients, API Path, Module Path) in fabri-connection.json file.

  2. Define you’re own route for you’re controller.

  3. Define the controller according to the functioanliy exposed by the Smart contracts.

Security

Apart from the Ping and Health endpoints all endpoints are secured.

Performing an introspection prior forwarding the request to the smart contract based on the token frowarded by the 3rd party application.

You can define the protected paths on the API config as mentioned above.

Also you can define the Allowed Keycloack clients (Tokenns issued from these clients can go through).

Under the covers

You should have a good understanding of how a Hyperledger Fabric network and its SDK to interact with it works, but there are some high level concepts outlined here to understand the flow.

A FileSystemWallet is used to manage identities for interacting with the network. More information can be found in the Hyperledger Fabric SDK for node.js doc. Look in server/helpers/wallet.ts for some wallet helper functions.

A gateway to talk to the network is established with the Gateway class, by passing the common connection profile, a specified identity, and the wallet that contains that identity.

// gateway and contract connection
await gateway.connect(ccp, {
  identity: user,
  wallet: walletHelper.getWallet(),
});

Once the gateway is established, you connect to the channel by a getNetwork call to the gateway.

const network = await gateway.getNetwork(config.channelName);

Then make a call to get the chaincode with a getContract call.

const contract = await network.getContract(config.chaincodeName, config.chaincodeName.contractName);

contractName is optional parameter (if you don’t have multiple contracts).

Once you have the contract object, you can start invoking and querying the chaincode!

// invoke transaction
const invokeResponse = await contract.submitTransaction('Health');

// query
const queryResponse = await contract.evaluateTransaction('Health');

NOTE: This application uses a custom module to dynamically create and mount middleware functions that connect to a Fabric gateway. See the Fabric Routes Custom Middleware section for more details.

Development

This app is built using Node.js and the express.js framework. The entire backend application is found within the server directory. The public directory contains the swagger.yaml used by the Swagger UI to display API definitions. Note that we use the swagger-ui-express npm package to serve and render the Swagger UI, instead of directly including the ui source code.

To start the server in development mode, run npm run dev. This will start the server with nodemon, which automatically restarts the node app when you make file changes. It simplifies testing when making changes and adding functionality.

The server is configured and started from the server/server.ts file. Routers that contain all the routes of your app are added in the routes directory. The corresponding controllers/handlers (the logic performed when those apis are called) of those routes are found in the controllers directory. When adding a new route to the api, you will first create a new router (or add to an existing router) in the routes directory, and also include it in routes/index.ts. Then you will add the logic function in the controllers directory. For example, if I wanted to add a new /ping route, you would create a routes/ping.ts file. The file’s contents would look like this:

import * as config from 'config';
import * as express from 'express';
import { getLogger } from 'log4js';

// controller logic for this route
import * as pingCtrl from '../controllers/ping';

const router = express.Router();

/**
 * Set up logging
 */
const logger = getLogger('routes - ping');
logger.level = config.get('logLevel');

logger.debug('setting up /ping route');

/**
 * Add routes
 */
router.get('/', pingCtrl.default); // specify path and controller function for this route

module.exports = router; // export router

Routes are registered to the server by taking the exported router in routes/index.ts, which basically takes all of the routers in the directory and combines them to pass to the express app. At this point, we’ve created the new router, but it won’t be registered with the express app. To do that, we either need to add the route information in config/fabric-connections.json file or open routes/index.ts and add the following lines:

import ping = require('./ping');
router.use('/ping', ping);

Now all we need to add is the logic. Create a controllers/ping.ts file. Remember our function name needs to match what we specified when adding the route to the router. The file’s contents would look something like this:

import * as config from 'config';
import { getLogger } from 'log4js';

import * as util from '../helpers/util';

const logger = getLogger('controllers - ping');
logger.level = config.get('logLevel');

const pingCC = async (req, res) => {
  logger.debug('entering >>> pingCC()');

  // ping chaincode
  const jsonRes = {
    statusCode: 200,
    success: true,
    message: 'Pinged chaincode successfully!',
  };

  logger.debug('exiting <<< pingCC()');
  util.sendResponse(res, jsonRes);
};

export { pingCC as default };

That’s it, you now have a new route in your server! Remember it’s important to keep your swagger.yaml up to date when you add new endpoints or make changes to existing ones.

The middlewares directory contains any middleware that is used in the app, such as error handling in error-handler.ts.

The helpers directory contains any helper functions used in the app, such as a send response helper in util.ts to send a request response back.

For full API reference and documentation, start the server and navigate to http://localhost:3000/api-docs/. Also, please see:

Scaffold Development Reference

This repository is using the API-Bootstrap scaffolded template from IBM Blockchain Team for the development. Thanks alot for the amazing work by them.

Previous