Tutorial: Create an Ethereum GraphQL Server with Node.js

Part 2—Connect a Smart Contract with GraphQL

Siddharth Parmar (Sid)
dev@red
6 min readJun 15, 2018

--

You can find Part 1 of this tutorial here.

In this part, we’ll create an Express server for our GraphQL API, and connect it to our Smart Contract using Web3 😎.

Set-up Some Test Accounts

Before we set up our server, install the ganache-cli and Metamask browser extension.

The Ganache CLI is part of the Truffle development framework for Ethereum and it will help us create some dummy accounts with which to test our contract.

We need the Metamask extension because it allows us to run Ethereum dApps in a regular web browser and also acts as a secure identity vault.

Run the command ganache-cli to generate a few test accounts and copy the “Mnemonic” phrase given to us in the terminal.

Ganache-cli output. The “Mnemonic phrase” is used to access the first account in the list, sort of like a password. For a more details understanding of why it’s used, you can start here: https://en.bitcoin.it/wiki/Mnemonic_phrase

Now click on the Metamask icon in your browser and connect the Metamask extension to the Localhost 8545 network.

Then, select “restore from seed phrase”, paste the phrase you copied from the terminal and create a new password.

If all went well, we should see that we have 100 ether to spend!

Connecting Ganache to Metamask

Next we’ll connect the Remix IDE, which we’ll use to write and test our Smart Contract, with Metamask by selecting the Injected Web3 option in the RUN tab.

Set the environment option to “Injected Web3” and provide the constructor arguments for your contract.

To deploy the contract we developed, add the prize string and click Deploy.

GraphQL API Set-up

Now we’ll build a basic GraphQL server using Apollo. Let’s start. Create a new directory for your project and run npm init -y inside of it.

Now we will set-up the basic file-structure of our GraphQL server. Create folders and files as per an image below:

File-structure for our GraphQL server.

donationContract.js is where the JavaScript version of our compiled Smart Contract will live. Inside this file we’ll need two pieces of information from Remix: The address of the deployed contract on the test blockchain, and something called an ABI.

What is an ABI? Learn more here.

The final file will look something like this:

const contractAddress = "0xd0a6E6C54DbC68Db5db3A091B171A77407Ff7ccf"const contractABI = [{    // Your ABI here...}]
Smart Contract address in the Remix IDE
Smart Contract ABI. You’ll need to deploy your contract to find this.

Now that we have the address of our newly deployed Ethereum Smart Contract, we need a way for our JavaScript application to communicate with it. Luckily, we have the web.js library for that! Install web3.js by running:

npm install --save-dev web3

Open getContract.js file in src/contract and add this code:

const Web3 = require("web3");// Importing contract details
const {address, ABI} = require("../../constants/donationContract");
const getWeb3 = () => {
return (web3 = new Web3(
new Web3.providers.HttpProvider("http://localhost:8545")
));
};
const getContract = new Promise(function(resolve, reject) {
const web3 = getWeb3();
// Create a JavaScript versions of your Smart Contract's interface // using the contract address and ABI we got from the Remix const donationContract = new web3.eth.Contract(ABI, address); if (donationContract) resolve(donationContract);
else reject();
});
const getCoinbase = async () => {
const web3 = getWeb3();
return await web3.eth.getCoinbase();
};
module.exports = { getContract, getCoinbase };

You can learn more about “coinbase” and Web3 here and here.

Creating the GraphQL Schema

Add the following GraphQL type definitions to yourschema.js file:

const typeDefs = 
`type Contract {
address: String!,
balance: Int
}
type DonationReceipt {
transactionHash: String!,
blockHash: String!,
blockNumber: Int!,
gasUsed: Int!,
status: Boolean!
}

type Query {
contract: Contract
}
type Mutation {
donate(amount: Int!): DonationReceipt
}
`;
module.exports = typeDefs;

This schema will help us check our contract’s details (balance and address) and make donations (we will receive a donation receipt in response).

Finally, let’s write our server. Open your terminal and install these packages in your project:

npm install --save-dev apollo-server-express body-parser express graphql graphql-tools

Add the following code to the top of index.js:

const express = require("express");
const bodyParser = require("body-parser");
const {
graphqlExpress,
graphiqlExpress
} = require("apollo-server-express");
const { makeExecutableSchema } = require("graphql-tools");
const typeDefs = require("./schema/schema");
const {
getContract,
getCoinbase
} = require("./contract/getContract");

Our next step is to create an Express server, and write a GraphQL resolver to get the balance of our contract.

Continue editing index.js:

let contractInstance = {};function getBalance() {
return contractInstance.methods.checkContractBalance().call();
}
const resolvers = {
Query: {
async contract() {
let balance = 0;
await getBalance()
.then(bal => (balance = bal / 1000000000000000000))
// Convert to ether from wei
.catch(err => console.log(err));
return {
address: contractInstance._address,
balance
};
}
}
};
// Create the schema
const schema = makeExecutableSchema({
typeDefs,
resolvers
});
// Initialize the app
const app = express();
const PORT = 4000;
// The GraphQL endpoint
app.use("/graphql", bodyParser.json(), graphqlExpress({ schema }));
// GraphiQL, a visual editor for graphql queries
app.use("/graphiql", graphiqlExpress({ endpointURL: "/graphql" }));
// Start the server and get contract instance
app.listen(PORT, () => {
console.log(`Go to http://localhost:${PORT}/graphiql to explore the GraphQL API!`);
// get our contract as soon as the server starts
getContract
.then(res => (contractInstance = res))
.catch(err => console.log(err));
});

If you have worked with GraphQL and Node.js, this should look familiar to you.

We’ve just written a simple resolver with async/await that returns our deployed Smart Contract’s address and it’s balance!

Visit http://localhost:4000/graphiql to test your GraphQL server.

If you see the following, congratulations! 🙌

GraphQL server — get balance query to our smart contract

Now how about a challenge? Let’s finish up by writing a GraphQL resolver so we can make donations to our new contract using a GraphQL mutation.

To do that, add the following function to index.js :

// after our query resolver put this code
Mutation: {
async function makeDonation(amount) {
let response;
let coinbase;
let error;
await getCoinbase()
.then(res => (coinbase = res))
.then(() =>
contractInstance.methods
.make_donation("sending some either")
.send({
gas: 300000,
value: amount * 1000000000000000000, // wei conversion
from: coinbase
})
.then(res => (response = res))
)
.catch(err => (error = err));
return response;
}
} // Mutation end

Remember that we imported getCoinbase from our getContract.js file. We are using it now to get the Coinbase and then make a donation.

We’ll add this code to our resolver now, below our contract function:

  async donate(obj, args, context) {
let transactionHash = "";
let blockHash = "";
let blockNumber = 0;
let gasUsed = 0;
let status = false;
const response = makeDonation(args.amount); await response
.then(res => {
transactionHash = res.transactionHash;
blockHash = res.blockHash;
blockNumber = res.blockNumber;
gasUsed = res.gasUsed;
status = res.status;
})
.catch(err => console.log(err));
return {
transactionHash,
blockHash,
blockNumber,
gasUsed,
status
};
}

Great!

Here’s the finished index.js file in case that was confusing.

Let’s check out if the new resolver works. Restart the server and run this mutation to make a donation. You should see your donation receipt like this:

To be sure everything worked, check your account balance in Metamask and the contract balance through Remix. All the values should be changed!

You can check out this GitHub repo to see this finished project.

Thank-you so much for coding-along this GraphQL and Smart Contract app with me. I hope you learned something along the way. Happy coding!

If you liked this post and want to keep learning about web and app development with RED Academy, be sure to follow us on Medium or check out our website.

--

--