
Hello of us! On this tutorial, we’re going to discover ways to create a easy REST API to work together with the Ethereum blockchain utilizing Golang.
Web3.js is the de-facto library to work together for interacting with Ethereum in JavaScript and Node.js. It takes care of encoding payloads and producing the RPC calls. Web3.js may be very standard and closely documented.
However, (geth), the most well-liked Ethereum implementation, is written in Go. It’s a whole Ethereum node. For those who construct a dApp in Go, then you definately’ll be utilizing the go-ethereum libraries straight which suggests you are able to do every part the node can do.
So, for this tutorial, I selected to make use of Go as our weapon.
In easy phrases, interacting with the blockchain implies that you’ll be making RPC calls over HTTP. Any language will be capable to do this for you however, utilizing a compiled language reminiscent of Go gives you a greater efficiency… If efficiency is necessary to you or your crew.
Sufficient of boring introduction!

For our tutorial, we’re going to arrange 4 endpoints:
Get the most recent blockGet transaction by hashGet handle balanceTransfer ether to an handle
This isn’t an enormous deal, however I believe is cool as a place to begin to extra complicated implementations.
If you wish to get the entire code you possibly can obtain it here.
SET UP
I used go 1.13.8 for this tutorial, to get your Go model simply run:
$ go model
# outputs
go model go1.13.8 darwin/amd64
First we’re going to create our mission by operating the next command:
That can create on the root of your working listing the file
go.mod
with the next content material:
module github.com/LuisAcerv/goeth-api
go 1.13
Now let’s create our mission construction. I’ve to say right here that you need to use the construction that higher matches your wants.
On the root of your mission create a brand new
foremost.go
file.
$ echo "bundle foremost" >> foremost.go
Now we have to create three directories:
$ mkdir handler
$ mkdir fashions
$ mkdir modules
And inside every of these folders we’re going to create a
foremost.go
file, and we must always have the next construction:
.
├── handler
│ └── foremost.go
├── fashions
│ └── foremost.go
├── modules
│ └── foremost.go
├── go.mod
├── go.sum
├── foremost.go
Ganache-CLI
As a way to work together with the Ethereum blockchain, we’d like a supplier, a supplier is a node we’ve got entry to make RPC calls over HTTP. You should utilize a testnet reminiscent of ropsten or kovan by means of a supplier reminiscent of Infura, however for this tutorial, we’re going to arrange an area digital node utilizing ganache.
On the official truffle website you possibly can obtain ganache, is fairly straightforward to arrange and gives you all you want for testing proposes. It comes with a pleasant UI which can present you the transactions, accounts and logs of your “node”.

After you have ganache put in and operating we’re good to start out writing some code.
We’ve a
./fashions/foremost.go
file. This file comprises the constructions we’re going to use in our API.
We add the next content material:
bundle fashions
// Block information construction
sort Block struct {
BlockNumber int64 `json:"blockNumber"`
Timestamp uint64 `json:"timestamp"`
Issue uint64 `json:"problem"`
Hash string `json:"hash"`
TransactionsCount int `json:"transactionsCount"`
Transactions []Transaction `json:"transactions"`
}
// Transaction information construction
sort Transaction struct {
Hash string `json:"hash"`
Worth string `json:"worth"`
Fuel uint64 `json:"fuel"`
GasPrice uint64 `json:"gasPrice"`
Nonce uint64 `json:"nonce"`
To string `json:"to"`
Pending bool `json:"pending"`
}
// TransferEthRequest information construction
sort TransferEthRequest struct {
PrivKey string `json:"privKey"`
To string `json:"to"`
Quantity int64 `json:"quantity"`
}
// HashResponse information construction
sort HashResponse struct {
Hash string `json:"hash"`
}
// BalanceResponse information construction
sort BalanceResponse struct {
Tackle string `json:"handle"`
Stability string `json:"steadiness"`
Image string `json:"image"`
Items string `json:"items"`
}
// Error information construction
sort Error struct {
Code uint64 `json:"code"`
Message string `json:"message"`
}
Now that we’ve got our fashions outlined and prepared for use, we’re going to create the strategies in command of interacting with the blockchain.
To begin with we need to set up the
go-ethereum
module, and we are able to do this by operating the next command:
$ go get -u github.com/ethereum/go-ethereum
In our
./modules/foremost.go
we’re going to create a operate that retrieves the most recent block from the blockchain.
This operate goes to provide us the details about the block and the transactions embedded in it.
func GetLatestBlock(consumer ethclient.Shopper) *Fashions.Block {
// We add a get well operate from panics to stop our API from crashing because of an surprising error
defer func() {
if err := get well(); err != nil {
fmt.Println(err)
}
}()
// Question the most recent block
header, _ := consumer.HeaderByNumber(context.Background(), nil)
blockNumber := huge.NewInt(header.Quantity.Int64())
block, err := consumer.BlockByNumber(context.Background(), blockNumber)
if err != nil {
log.Deadly(err)
}
// Construct the response to our mannequin
_block := &Fashions.Block{
BlockNumber: block.Quantity().Int64(),
Timestamp: block.Time(),
Issue: block.Issue().Uint64(),
Hash: block.Hash().String(),
TransactionsCount: len(block.Transactions()),
Transactions: []Fashions.Transaction{},
}
for _, tx := vary block.Transactions() {
_block.Transactions = append(_block.Transactions, Fashions.Transaction{
Hash: tx.Hash().String(),
Worth: tx.Worth().String(),
Fuel: tx.Fuel(),
GasPrice: tx.GasPrice().Uint64(),
Nonce: tx.Nonce(),
To: tx.To().String(),
})
}
return _block
}
Now, we need to have a operate to retrieve details about a given transaction, for instance, if we switch ether to from one account to a different, the API will reply with de transaction hash, and we are able to use it to get the transaction info.
To try this we add a brand new operate to our
./modules/foremost.go
// GetTxByHash by a given hash
func GetTxByHash(consumer ethclient.Shopper, hash frequent.Hash) *Fashions.Transaction {
defer func() {
if err := get well(); err != nil {
fmt.Println(err)
}
}()
tx, pending, err := consumer.TransactionByHash(context.Background(), hash)
if err != nil {
fmt.Println(err)
}
return &Fashions.Transaction{
Hash: tx.Hash().String(),
Worth: tx.Worth().String(),
Fuel: tx.Fuel(),
GasPrice: tx.GasPrice().Uint64(),
To: tx.To().String(),
Pending: pending,
Nonce: tx.Nonce(),
}
}
One other factor we need to know is our steadiness, for that we have to add one other operate.
// GetAddressBalance returns the given handle steadiness =P
func GetAddressBalance(consumer ethclient.Shopper, handle string) (string, error) {
account := frequent.HexToAddress(handle)
steadiness, err := consumer.BalanceAt(context.Background(), account, nil)
if err != nil {
return "0", err
}
return steadiness.String(), nil
}
The final operate we’re going to add into our modules bundle is the one that may enable us to ship ether from one account to a different.
And I need to make a parenthesis right here. This operate requires that the consumer sends the sender personal key to signal the transaction, that implies that your consumer will broadcast the consumer’s personal key by means of HTTP and if you’re going to do one thing like this utilizing with this code or one other else, then at the least be sure you are utilizing HTTPS.
Stated that allow’s add the operate to our modules bundle.
func TransferEth(consumer ethclient.Shopper, privKey string, to string, quantity int64) (string, error) {
defer func() {
if err := get well(); err != nil {
fmt.Println(err)
}
}()
// Assuming you've got already related a consumer, the subsequent step is to load your personal key.
privateKey, err := crypto.HexToECDSA(privKey)
if err != nil {
return "", err
}
// Perform requires the general public handle of the account we're sending from -- which we are able to derive from the personal key.
publicKey := privateKey.Public()
publicKeyECDSA, okay := publicKey.(*ecdsa.PublicKey)
if !okay {
return "", err
}
fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
// Now we are able to learn the nonce that we must always use for the account's transaction.
nonce, err := consumer.PendingNonceAt(context.Background(), fromAddress)
if err != nil {
return "", err
}
worth := huge.NewInt(quantity) // in wei (1 eth)
gasLimit := uint64(21000) // in items
gasPrice, err := consumer.SuggestGasPrice(context.Background())
if err != nil {
return "", err
}
// We determine who we're sending the ETH to.
toAddress := frequent.HexToAddress(to)
var information []byte
// We create the transaction payload
tx := varieties.NewTransaction(nonce, toAddress, worth, gasLimit, gasPrice, information)
chainID, err := consumer.NetworkID(context.Background())
if err != nil {
return "", err
}
// We signal the transaction utilizing the sender's personal key
signedTx, err := varieties.SignTx(tx, varieties.NewEIP155Signer(chainID), privateKey)
if err != nil {
return "", err
}
// Now we're lastly able to broadcast the transaction to the whole community
err = consumer.SendTransaction(context.Background(), signedTx)
if err != nil {
return "", err
}
// We return the transaction hash
return signedTx.Hash().String(), nil
}
Good! we’ve got a operate to switch ether, now all collectively:
bundle modules
import (
"context"
"crypto/ecdsa"
"fmt"
"log"
"math/huge"
Fashions "github.com/LuisAcerv/goeth-api/fashions"
"github.com/ethereum/go-ethereum/frequent"
"github.com/ethereum/go-ethereum/core/varieties"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
)
// GetLatestBlock from blockchain
func GetLatestBlock(consumer ethclient.Shopper) *Fashions.Block {
// We add a get well operate from panics to stop our API from crashing because of an surprising error
defer func() {
if err := get well(); err != nil {
fmt.Println(err)
}
}()
// Question the most recent block
header, _ := consumer.HeaderByNumber(context.Background(), nil)
blockNumber := huge.NewInt(header.Quantity.Int64())
block, err := consumer.BlockByNumber(context.Background(), blockNumber)
if err != nil {
log.Deadly(err)
}
// Construct the response to our mannequin
_block := &Fashions.Block{
BlockNumber: block.Quantity().Int64(),
Timestamp: block.Time(),
Issue: block.Issue().Uint64(),
Hash: block.Hash().String(),
TransactionsCount: len(block.Transactions()),
Transactions: []Fashions.Transaction{},
}
for _, tx := vary block.Transactions() {
_block.Transactions = append(_block.Transactions, Fashions.Transaction{
Hash: tx.Hash().String(),
Worth: tx.Worth().String(),
Fuel: tx.Fuel(),
GasPrice: tx.GasPrice().Uint64(),
Nonce: tx.Nonce(),
To: tx.To().String(),
})
}
return _block
}
// GetTxByHash by a given hash
func GetTxByHash(consumer ethclient.Shopper, hash frequent.Hash) *Fashions.Transaction {
defer func() {
if err := get well(); err != nil {
fmt.Println(err)
}
}()
tx, pending, err := consumer.TransactionByHash(context.Background(), hash)
if err != nil {
fmt.Println(err)
}
return &Fashions.Transaction{
Hash: tx.Hash().String(),
Worth: tx.Worth().String(),
Fuel: tx.Fuel(),
GasPrice: tx.GasPrice().Uint64(),
To: tx.To().String(),
Pending: pending,
Nonce: tx.Nonce(),
}
}
// TransferEth from one account to a different
func TransferEth(consumer ethclient.Shopper, privKey string, to string, quantity int64) (string, error) {
defer func() {
if err := get well(); err != nil {
fmt.Println(err)
}
}()
// Assuming you've got already related a consumer, the subsequent step is to load your personal key.
privateKey, err := crypto.HexToECDSA(privKey)
if err != nil {
return "", err
}
// Perform requires the general public handle of the account we're sending from -- which we are able to derive from the personal key.
publicKey := privateKey.Public()
publicKeyECDSA, okay := publicKey.(*ecdsa.PublicKey)
if !okay {
return "", err
}
fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
// Now we are able to learn the nonce that we must always use for the account's transaction.
nonce, err := consumer.PendingNonceAt(context.Background(), fromAddress)
if err != nil {
return "", err
}
worth := huge.NewInt(quantity) // in wei (1 eth)
gasLimit := uint64(21000) // in items
gasPrice, err := consumer.SuggestGasPrice(context.Background())
if err != nil {
return "", err
}
// We determine who we're sending the ETH to.
toAddress := frequent.HexToAddress(to)
var information []byte
// We create the transaction payload
tx := varieties.NewTransaction(nonce, toAddress, worth, gasLimit, gasPrice, information)
chainID, err := consumer.NetworkID(context.Background())
if err != nil {
return "", err
}
// We signal the transaction utilizing the sender's personal key
signedTx, err := varieties.SignTx(tx, varieties.NewEIP155Signer(chainID), privateKey)
if err != nil {
return "", err
}
// Now we're lastly able to broadcast the transaction to the whole community
err = consumer.SendTransaction(context.Background(), signedTx)
if err != nil {
return "", err
}
// We return the transaction hash
return signedTx.Hash().String(), nil
}
// GetAddressBalance returns the given handle steadiness =P
func GetAddressBalance(consumer ethclient.Shopper, handle string) (string, error) {
account := frequent.HexToAddress(handle)
steadiness, err := consumer.BalanceAt(context.Background(), account, nil)
if err != nil {
return "0", err
}
return steadiness.String(), nil
}
Now we have to arrange our API to work together with the features we wrote by means of HTTP endpoints. To do that we’re going to use gorilla/mux.
In our foremost file we’re going the add the next content material:
bundle foremost
import (
"fmt"
"log"
"internet/http"
Handlers "github.com/LuisAcerv/goeth-api/handler"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/gorilla/mux"
)
func foremost() {
// Create a consumer occasion to hook up with our providr
consumer, err := ethclient.Dial("http://localhost:7545")
if err != nil {
fmt.Println(err)
}
// Create a mux router
r := mux.NewRouter()
// We'll outline a single endpoint
r.Deal with("/api/v1/eth/{module}", Handlers.ClientHandler{consumer})
log.Deadly(http.ListenAndServe(":8080", r))
}
Now we have to create handler for our endpoint, since we’ve got added a parameter
module
to our endpoint we can deal with our features with a single handler. As I mentioned earlier than be happy to make use of the structure you would like on your personal mission.
Now in our
./handler/foremost.go
we’re going to add the next content material:
bundle handlers
import (
"encoding/json"
"fmt"
"internet/http"
Fashions "github.com/LuisAcerv/goeth-api/fashions"
Modules "github.com/LuisAcerv/goeth-api/modules"
"github.com/ethereum/go-ethereum/frequent"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/gorilla/mux"
)
// ClientHandler ethereum consumer occasion
sort ClientHandler struct {
*ethclient.Shopper
}
func (consumer ClientHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Get parameter from url request
vars := mux.Vars(r)
module := vars["module"]
// Get the question parameters from url request
handle := r.URL.Question().Get("handle")
hash := r.URL.Question().Get("hash")
// Set our response header
w.Header().Set("Content material-Sort", "utility/json")
// Deal with every request utilizing the module parameter:
change module {
case "latest-block":
_block := Modules.GetLatestBlock(*consumer.Shopper)
json.NewEncoder(w).Encode(_block)
case "get-tx":
if hash == "" {
json.NewEncoder(w).Encode(&Fashions.Error{
Code: 400,
Message: "Malformed request",
})
return
}
txHash := frequent.HexToHash(hash)
_tx := Modules.GetTxByHash(*consumer.Shopper, txHash)
if _tx != nil {
json.NewEncoder(w).Encode(_tx)
return
}
json.NewEncoder(w).Encode(&Fashions.Error{
Code: 404,
Message: "Tx Not Discovered!",
})
case "send-eth":
decoder := json.NewDecoder(r.Physique)
var t Fashions.TransferEthRequest
err := decoder.Decode(&t)
if err != nil {
fmt.Println(err)
json.NewEncoder(w).Encode(&Fashions.Error{
Code: 400,
Message: "Malformed request",
})
return
}
_hash, err := Modules.TransferEth(*consumer.Shopper, t.PrivKey, t.To, t.Quantity)
if err != nil {
fmt.Println(err)
json.NewEncoder(w).Encode(&Fashions.Error{
Code: 500,
Message: "Inside server error",
})
return
}
json.NewEncoder(w).Encode(&Fashions.HashResponse{
Hash: _hash,
})
case "get-balance":
if handle == "" {
json.NewEncoder(w).Encode(&Fashions.Error{
Code: 400,
Message: "Malformed request",
})
return
}
steadiness, err := Modules.GetAddressBalance(*consumer.Shopper, handle)
if err != nil {
fmt.Println(err)
json.NewEncoder(w).Encode(&Fashions.Error{
Code: 500,
Message: "Inside server error",
})
return
}
json.NewEncoder(w).Encode(&Fashions.BalanceResponse{
Tackle: handle,
Stability: steadiness,
Image: "Ether",
Items: "Wei",
})
}
}
That is it, if we go to our terminal and run:
We will begin testing our API. Be sure you are operating your ganache occasion and in your browser go to: http://localhost:8080/api/v1/eth/latest-block and if every part is okay then it is best to see one thing like this:

Now let’s attempt to switch some ether from one account to a different, first copy the personal key of the sender from ganache:

And in addition copy an handle to ship the ether:

Now utilizing
curl
, let’s make a switch!:
$ curl -d '{"privKey":"12a770fe34a793800abaab0a48b7a394ae440b9117d000178af81b61cda8ff15", "to":"0xa8Ce5Fb2DAB781B8f743a8096601eB01Ff0a246d", "quantity":1000000000000000000}' -H "Content material-Sort: utility/json" -X POST http://localhost:8080/api/v1/eth/send-eth
It’s best to obtain the transaction hash as response:
{"hash":"0xa5417ae03a817e41ddf36303f3ea985e6bd64a504c662d988bcb47913be8d472"}
Now let’s get the transaction info utilizing our API, go to: http://localhost:8080/api/v1/eth/get-tx?hash=<tx-hash-from-response>
And it is best to see one thing like this:

And eventually, let’s test the steadiness of the handle by going to http://localhost:8080/api/v1/eth/get-balance?address=<the-recipient-address>

That is it, we’ve got created a easy API to start out interacting with the Ethereum blockchain and carry out some fundamental actions.
Within the following half we’re going to enhance our current code and we’re going to add performance to work together with sensible contracts and ERC20 tokens.
Repository: https://github.com/LuisAcerv/goeth-api
Try this tutorial on how create bitcoin HD Pockets utilizing Go.
And that is it, if you wish to speak then comply with me on twitter.
See you quickly with the subsequent half or in one other coding journey.
Comfortable hacking!
