Skip to content

DApp Development: Server‐side Communication

Ananthan edited this page Sep 4, 2024 · 5 revisions

Initialize a Node.js Project

We are using Node.js to create a backend application to communicate with the blockchain. We use Node.js because it is simple, has a fast development cycle, and uses JavaScript, a single language on both the frontend and backend.

However, we require some kind of gateway for the user to access our backend application. This is where APIs come in. Now, for Node.js, we can write them from scratch, but having a framework like Express eases our process.

We have developed a CLI tool to create a boilerplate Express project. Simply running the command will create enough configuration required for our project.

npx @kba-tools/create-express-app@latest

We don't want to complicate our first application, so give it a name similar to 'certificate-app' and choose 'JavaScript' as the language. Since we don't want any UI provided by Express itself, choose 'None' for the template. You can choose your preference for the package manager.

The CLI will install all the application's dependencies. To continue, we need only run the script below.

npm run dev

We can see the application is Listening on port 8080..

We can test our APIs using tools like cURL or Postman. Let's see what happens next.

curl http://127.0.0.1:8080

Adding Ethers

Our APIs work fine now, but we need them to communicate with our deployed smart contract. We use Ethers, a popular library for smart contract interaction written for JavaScript-based applications. First, we need to install it.

npm install ethers

Next, we must create a file named 'instance.js' or something similar inside the src folder.

Import the Contract and JsonRpcProvider classes from ethers. JsonRpcProvider creates a connection object with our blockchain, while Contract creates a contract instance for the interaction.

import { Contract, JsonRpcProvider } from "ethers";

However, to create a contract instance, we require the contract's ABI, the contract address, and the signer/wallet to sign the transactions initiated by the application. For the ABI and contract address, we can use the artifacts from Hardhat.

import details from "./deployed_addresses.json" assert { type: "json" };

import Cert from "./Cert.json" assert { type: "json" };

Then, we establish a connection with the blockchain by passing the IP and port used by the Hardhat simulation (assuming default values here). Since all the accounts in the Hardhat node are unlocked by default, we use the getSigner function from the provider object instead of creating a Wallet object. However, creating a Wallet object is mandatory for a public chain. getSigner returns the first unlocked account in the simulation.

const provider = new JsonRpcProvider("http://127.0.0.1:8545");
const signer = await provider.getSigner();

OR

const wallet = new Wallet('<your-private-key>', provider);

Finally, we can create the instance. However, we must also export it to access it in the routes.

export const instance = new Contract(details["CertModule#Cert"],  Cert.abi, signer);

Updating Routes for Smart Contract Interaction

We will add two route handlers in 'src/routes/index.js'.

But first, we need to import our contract instance.

import { instance } from "../instance.js";

After we create a route '/issue' for writing the data, we use the HTTP/POST method for this route. The data can be sent via the request body.

As a precaution, we will wrap the logic inside our router in a try...catch block. Calling the issue function from the smart contract will return a transaction since it is a write operation. We are both logging and sending the transaction as the response.

router.post("/issue", async (req, res) => {
  try {
    const trx = await instance.issue(req.body.id, req.body.name, req.body.course, req.body.grade, req.body.date);
    console.log(trx);
    res.json(trx);
  } catch (error) {
    console.log(error);
    res.json(error);
  }
});

While testing the API using cURL/Postman, remember to specify the method as POST and add the data to the response body.

curl -X POST http://127.0.0.1:8080/issue -H "Content-Type: application/json" -d '{"id": 101, "name": "Yao", "course": "Ethereum Developer", "grade": "A", "date": "24-04-24"}'

We create another route '/fetch' with the HTTP/GET method to retrieve the data we have just sent. To get a certificate corresponding to an ID, we can send the ID as a query in the request. We call our public mapping to fetch the data corresponding to the ID.

router.get("/fetch", async (req, res) => {
  try {
    const result = await instance.Certificates(req.query.id);
    console.log(result);
    res.json(result);
  } catch (error) {
    console.log(error);
    res.json(error);
  }
});

To get the certificate corresponding to an ID, we must specify that in the URL.

curl http://127.0.0.1:8080/fetch?id=101

If everything works fine, then we have successfully created a server-side application to communicate our deployed smart contract in the blockchain.



Clone this wiki locally