-
Notifications
You must be signed in to change notification settings - Fork 44
DApp Development: Server‐side Communication
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
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);
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.
- Introduction
- Rise of Ethereum
- Ethereum Fundamentals
- DApps & Smart Contracts
- MetaMask Wallet & Ether
- Solidity: Basics
- Solidity: Advanced
- Solidity Use cases and Examples
- DApp Development: Introduction
- DApp Development: Contract
- DApp Development: Hardhat
- DApp Development: Server‐side Communication
- DApp Development: Client-side Communication
- Advanced DApp Concepts: Infura
- Advanced DApp Concepts: WalletConnect
- Event‐driven Testing
- Interacting with the Ethereum Network
- Tokens: Introduction
- Solidity: Best Practises
- Smart Contract Audit
- Ethereum: Advanced Concepts
- Evolution of Ethereum
- Conclusion