A step by step guide to building a basic Node application with Obyte integration for absolute beginners.
By the end of this tutorial, you will have built a browser application that allows a user to post payments, data and data-feeds to the Obyte network.
We will be writing a Node js application using the Express framework with Pug Templating and Bootstrap. For Obyte integration, we will be using Obyte js libraries.
This tutorial assumes no prior knowledge of any of the above. However, you need to have Node and npm installed on your machine.
Before we can start coding, we’ll need to get Node and npm installed on your machine.
To check that Node and npm are installed correctly, open your terminal and type:
node -v
followed by:
npm -v
That will output the version number of each program. At the time of writing, my Node js version is v10.10.0 my npm version is 6.4.1.
Create a new directory for your application, e.g. myObyteApp.
Initialise your new project, by going to your terminal window and typing the following command:
npm init -y
That will create and populate a package.json file in your directory.
Express is a lightweight web application framework for Node.js, which provides a robust set of features for writing web apps. These features include route handling, template engine integration and a middleware framework.
Type following command in the terminal window:
npm install --save express
--save option, adds Express to the dependencies section of the package.json file.
nodemon is a convenience tool. It will watch the files in the directory it was started in, and if it detects any changes, it will automatically restart Node application. Type following command in the terminal window:
npm install --save-dev nodemon
In your application folder create index.js file, then add the following code to it:
const app = require('./startup/app');
const server = app.listen(process.env.PORT || 3000, () => {
console.log(`Express is running on port ${server.address().port}`);
});
Create startup folder under your application folder and add app.js file to it, then add following code to it:
const express = require('express');
const app = express();
// routers
module.exports = app;
Your application directory should look like this:
myObyteApp
startup
app.js
index.js
package.json
Now, you can start your application by typing the following in the command window:
nodemon
By default, nodemon will look for index.js file. Your server will start on port 3000, and you should see the following message in the command window:

Create a routes folder under your application folder. Add home.js, postDAG.js and searchDAG.js files to the routes folder.
Add the following code to the home.js file:
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.send('Home page');
});
module.exports = router;
Add the same code to the postDAG.js and searchDAG.js files, replacing res.send('Home page'); with res.send('Post DAG page'); and res.send('Search DAG page'); as appropriate.
Add routes code to the app.js file as follows:
// routes
const home = require('../routes/home');
const postDAG = require('../routes/postDAG');
const searchDAG = require('../routes/searchDAG');
app.use('/', home);
app.use('/home', home);
app.use('/postDAG', postDAG);
app.use('/searchDAG', searchDAG);
Test it by opening a browser and typing http://localhost:3000/ as the URL. You should see the Home Page message displayed in the browser. The same message should show when typing http://localhost:3000/home
Repeat test by typing http://localhost:3000/postDAG to see Post DAG Page message and http://localhost:3000/searchDAG to see Search DAG Page message.
The next step is to use the Pug Templating Engine to assist with Front End development. Pug Template Engine uses static template files defined as part of the application. At runtime, the template engine replaces variables in a template file with actual values and transforms the template into an HTML file sent to the client.
We also will be using CSS from Bootstrap, which we will be dynamically acquiring at run time.
Install Pug saving it as a dependency, by typing the following command:
npm i --save pug
Create views folder under your application folder and add layout.pug file under it.
Add the following code to the layout.pug file:
doctype html
html
head
title= `${title}`
link(rel='stylesheet', href='https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css')
body
header.navbar.bg-info.text-light
h1 My Application
include menu.pug
div.container-fluid
block content
Add a menu.pug template file into the views folder and add the following code to it:
header.bg-light
block menu
ul.nav.nav-tabs
li.nav-item
a.nav-link.text-dark(href=".")="Home"
li.nav-item
a.nav-link.text-dark(href="postDAG")= "Post to DAG"
li.nav-item
a.nav-link.text-dark(href="searchDAG")= "Search DAG"
Add an index.pug template into the views folder and add the following code to it:
extends layout block content h2 Welcome! p Some text...
Repeat this process to add postDAG.pug and searchDAG.pug templates into the views folder, replacing:
h2 Welcome!
with:
h2 Post to DAG
and:
h2 Search DAG
respectively.
Your directory structure should look like the following:
myObyteApp
routes
home.js
postDAG.js
searchDAG.js
startup
app.js
views
index.pug
layout.pug
menu.pug
postDAG.pug
searchDAG.pug
index.js
package.json
Import Node's native Path module, by adding the following code to the app.js file:
const path = require('path');This module will be used to build the path to your views folder.
Configure app.js to use Pug as a layout engine and to look for templates inside the views folder by adding the following commands after app.use('/', home); line:
app.set('../views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');Your app.js file should look like following:
const express = require('express');
const app = express();
const path = require('path');
// routes
const home = require('../routes/home');
const postDAG = require('../routes/postDAG');
const searchDAG = require('../routes/searchDAG');
app.set('../views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use('/', home);
app.use('/home', home);
app.use('/postDAG', postDAG);
app.use('/searchDAG', searchDAG);
module.exports = app;Finally, modify all files in the routes folder replacing res.send command with res.render command as follows:
Replace res.send('Home page'); with res.render('index', { title: 'Home page' }); in the home.js file.
Replace res.send('Post DAG page'); with res.render('postDAG', { title: 'Post to DAG page' }); in the postDAG.js file.
Replace res.send('Search DAG page'); with res.render('searchDAG', { title: 'Search DAG page' }); in the searchDAG.js file.
Restart server from the command window by typing nodemon
Test the application in a browser.
Extend postDAG.pug template as following:
extends layout
block content
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
h2 Post to DAG
p.
Use Data option on this page to post arbitrary key-value pairs into
Obyte network.
Use Data Feed option on this page to post values into datafeeds
as an oracle.
// JavaScript section
// Form section
form(method='POST' action='/postDAG')
div.form-group
div.form-row
div.col-md-2
label(for='type') Type:
select.form-control(
id='type'
name='type'
onchange='typeChange()'
required
)
option(value='') What to post?
option(value='bytes') Bytes
option(value='data') Data
option(value='data_feed') Data Feed
div.col-md-7
label(for='wif') WIF of wallet to be used to fund the transaction
input.form-control(
id='wif'
name='wif'
placeholder='WIF'
required
)
div(id='paymentDiv')
div(id='dataDiv')
div.form-group
button.btn.btn-primary(type='submit') Post to DAG
div(id='errorDiv')
// Result Section
In the above template we have used standard Bootstrap 4 css classes, e.g.: form-group form-row col-md-2 col-md-4 form-control btn btn-primary.
You should see the basic data entry form in the browser. However, at this stage payment and data sections of the form are missing and none of the buttons is working yet.
Create a javascripts directory under the views folder. And add to it the following files: js_changeType.pug, js_paymentDiv.pug, js_dataDiv.pug, js_dataRows.pug and js_dataName.pug.
Add the following code to the js_changeType.pug file:
// Javascript for dynamic creation of the data entry form
script.
var rowId = 1, type, placeholder, error='';
function typeChange() {
type = document.getElementById("type").value;
// remove all subforms
var elements = document.getElementsByClassName("subform");
var count=0, element;
for (var i = 0; i < elements.length; i++) {
element = elements[i];
element.parentNode.removeChild(element);
count++;
}
// remove results
var resultElement = document.getElementById('result');
if (resultElement) resultElement.parentNode.removeChild(resultElement);
// remove errors
var errElement = document.getElementById('error');
if (errElement) errElement.parentNode.removeChild(errElement);
// add payment subform
if (type === 'bytes') {
paymentDiv();
}
// add data subform
if (type === 'data' || type === 'data_feed') {
if (type === 'data') placeholder = 'Field';
if (type === 'data_feed') placeholder = 'Data Feed Name';
dataDiv();
}
}Add the following code to the js_paymentDiv.pug file:
// Javascript for dynamic creation of the Payments section of the Form
script.
function paymentDiv() {
var element = document.createElement('div');
var innerHTML =
`<div class='form-group subform' id='payment'>
<h5> Payment details</h5>
<div class='form-row'>
<div class='col-md-4'>
<label for='amount'>Amount</label>
<input
class='form-control'
id='amount'
name='amount'
placeholder='Bytes'>
</div>
<div class='col-md-7'>
<label for='recipient'>Recipient's wallet address</label>
<input
class='form-control'
id='recipient'
name='recipient'
placeholder='Address'>
</div>
</div>
</div>`;
element.innerHTML = innerHTML;
document.getElementById("paymentDiv").appendChild(element);
}Add the following code to the js_dataDiv.pug file:
// Javascript for dynamic creation of the Data section of the Form
script.
function dataDiv() {
// dynamically create Data section of the Form
//alert('inside dataDiv function');
var element = document.createElement('div');
var innerHTML =
`<div class='form-group subform' id='data'>
<div class='form-group'>
<h5> Values Dynamic</h5>
<div class='form-row' id='1'>
<div class='col-md-4'>
<input
class='form-control field1'
id='field-1'
placeholder='${placeholder}'
onchange='setName(id)'>
</div>
<div class='col-md-7'>
<input
class='form-control'
id='value-1'
placeholder='Value'>
</div>
</div>
</div>
<div id='newRows'></div>
<div class='form-group'>
<button type='button' onclick='addRow()'>+</button>
</div>
</div>`;
element.innerHTML = innerHTML;
document.getElementById("dataDiv").appendChild(element);
}Add the following code to the js_dataRows.pug file:
// Javascript to add/remove rows from the Data section of the Form
script.
function addRow() {
rowId++;
var fieldId = 'field-' + rowId;
var valueId = 'value-' + rowId;
var buttonId = 'button-' + rowId;
var element = document.createElement('div');
element.id = rowId;
var innerHTML =
`<div class='form-group'>
<div class='form-row'>
<div class='col-md-4'>
<input type='text'
id=${fieldId}
class='form-control field1'
placeholder='${placeholder}'
onchange='setName(id)'>
</div>
<div class='col-md-7'>
<input type='text'
id=${valueId}
class='form-control'
placeholder='Value'>
</div>
<div class='col-md-1'>
<button type="button"
id=${buttonId}
onclick='removeRow( ${rowId} )'>-</button>
</div>
</div>
</div>`;
element.innerHTML = innerHTML;
document.getElementById("newRows").appendChild(element);
//getPlaceholder();
}
function removeRow(rowId) {
// Removes an element from the document
var element = document.getElementById(rowId);
element.parentNode.removeChild(element);
}Add the following code to the js_dataName.pug file:
// Javascript to set name property of the data field and check for uniqueness
script.
function setName(id) {
// get the value of the 1st field in the row
var name = document.getElementById(id).value;
// check that the value of the 1st field is unique
uniqueName(id, name);
// set name attribute of the 2nd field in the row to the value of 1st field
var element = document.getElementById('value-'+id.substr(6));
element.setAttribute('name', name);
}
function uniqueName(id, name) {
// validate that the data in 'field'/'data feed' is unique
var elements = document.getElementsByClassName('field1');
var count=0;
for (var i = 0; i < elements.length; i++) {
if (name === elements[i].value) count++
}
if (count > 1) {
var message = placeholder + ' has to be unique.'
showError(message);
// if 1st row is removed, remove delete button from the next row
if (id.substr(6) === '1') {
var buttonId = 'button-' + elements[1].id.substr(6);
var elementButton = document.getElementById(buttonId);
elementButton.parentNode.removeChild(elementButton);
}
// remove row
removeRow(id.substr(6));
}
}
function showError(message) {
// dynamically display error
var element = document.createElement('div');
var innerHTML =
`<div class='form-group' id='error'>
<div class='alert alert-danger alert-dismissible' id='error'>
<a class='close' href='#' data-dismiss='alert'>×</a>
<strong>Error:</strong>
<span>${message}</span>
</div>`;
element.innerHTML = innerHTML;
document.getElementById("errorDiv").appendChild(element);
}
Add the following code to the // JavaScript section of the postDAG.pug template. Keep indentation the same as following:
// JavaScript section include javascripts/js_changeType.pug include javascripts/js_paymentDiv.pug include javascripts/js_dataDiv.pug include javascripts/js_dataRows.pug include javascripts/js_dataName.pug
Test the form by selecting different Type values. Test adding and removing rows in the data section.
Add router.post section after the router.get section of the routes/postDAG.js file containing a placeholder for future Obyte integration as follows:
router.post('/', (req, res) => {
// preparing transaction data
// posting obyte payment & displaying results
// posting obyte data & displaying results
// posting obyte data feed & displaying results
// testing post router
console.log(req.body);
res.send('Posted to DAG');
})Test Submit by clicking the Post to DAG button. This should display 'Posted to DAG' message in your browser. You would not be able to see submitted data on your console just yet though.
Install a package named body-parser, which will make it easier to access the form data:
npm install --save body-parser
Then add following code to your startup/app.js file:
const bodyParser = require('body-parser');
...
app.use(bodyParser.urlencoded({ extended: true }));Place app.use(bodyParser.urlencoded({ extended: true })); line before app.use('/', home); line.
Test your application and check the console to see your data posted to the server.
You should see something like this displayed on the console: { type: 'data', wid: 'wid123test', 'myField 1': 'myValue 1', myField2: 'myValue 2', 'myField 3': 'myValue 3' }
Posting data or transactions to the Obyte network require payment in Bytes. In a real-life application, this can be done by the users of your application from their wallets.
However, in this tutorial, you will have to fund the transactions yourself from your own Obyte wallet.
Instructions on creating Obyte testnet GUI wallet can be found at https://obyte.org/testnet.html. Download the version for your operating system and install it selecting the option for generating the desktop icon.
For the purposes of this tutorial, we will refer to this wallet as your GUI wallet.
Fund your Obyte testnet GUI wallet by clicking on the link on the https://obyte.org/testnet.html page. You will need to wait 10-15 minutes for the transaction to be confirmed.
Next, you need to create another wallet to work with your application. This wallet will be used to fund saving data and sending payments.
For the purposes of this tutorial, we will refer to it as the Obyte js Wallet.
Click on the link below and select Testnet Env option, then click the Generate new random wallet button.
This creates your js wallet. Note the js wallet's details shown.
The generated WIF will be used for Obyte js integration and the address will be used for funding. When working with testnet, you can save this in the obyte/TestWalletInfo.txt file. However, when working with live wallets, make sure to keep this data private, as anyone with access to this data would be able to control funds in your wallet!
Fund your new js wallet by sending Bytes to its address from your GUI wallet. Make sure you send enough Bytes to use for testing. 20,000 or more.
Check that everything worked by going to the Testnet DAG explorer to view public transactions and searching using your js wallet's address.
Install Obyte libraries by running following command in the terminal window:
npm i obyte --save
I have got a whole bunch of errors re secp256k1, and I could not figure out how to resolve it. However, this does not seems to have any impact on what I am trying to do here.
Create obyte.js file in the startup directory containing the following code:
const obyte = require('obyte');
// connect to obyte testnet
const options = { testnet: true };
const client = new obyte.Client('wss://obyte.org/bb-test', options);
// To keep the connection with the WebSocket node alive you need to notify the node that your peer is awake every 10 sec.
setInterval(function() {
client.api.heartbeat()
}, 10 * 1000);
module.exports = client;
We are running this demo against Obyte testnet. When you are ready to connect to live Obyte network, replace // connect to obyte testnet with the following code:
// connect to mainnet official node wss://obyte.org/bb const client = new obyte.Client();
Then, add the following code to the top section of the routers/postDAG.js file.
const client = require('../startup/obyte');
We are going to modify router.post section of the routers/postDAG.js file.
Add the following code to the // preparing transaction data subsection:
// preparing transaction data
const type = req.body.type;
const wif = req.body.wif;
if (type === 'bytes') {
var params = {
outputs: [ {
address: req.body.recipient, // The Obyte address of the recipient
amount: Number(req.body.amount) } ] };// The amount she/he receives
}
if (type === 'data' || type === 'data_feed') {
var params = req.body;
delete params.type;
delete params.wif;
}Add the following code to the // posting obyte payment & displaying results subsection:
// posting obyte payment & displaying results
if (type === 'bytes') {
client.post.payment(params, wif, function(err, result) {
res.render('postDAG', { title: 'Data Transaction is Posted to DAG', err, result });
});
}Add the following code to the // posting obyte data & displaying results subsection:
// posting obyte data & displaying results
if (type === 'data') {
client.post.data(params, wif, function(err, result) {
res.render('postDAG', { title: 'Data is Posted to DAG', err, result });
});
}Add the following code to the // posting obyte data feed & displaying results subsection:
// posting obyte data feed & displaying results
if (type === 'data_feed') {
client.post.data(params, wif, function(err, result) {
res.render('postDAG', { title: 'Data Feed is Posted to DAG', err, result });
});
}And finally, comment out // testing post router subsection.
Add the following code to the // Results Section of the views/postDAG.pug file:
// Result Section
br
if result
div.alert.alert-success.alert-dismissible(id='result')
a.close( href='#' data-dismiss='alert' ) ×
h4 Transaction posted !
p Unit hash:
span= result
hr
a.alert-link( href="https://testnetexplorer.obyte.org/#"+result target="testnet" )
span See it on the DAG.
if err
div.alert.alert-danger.alert-dismissible(id='error')
a.close( href='#' data-dismiss='alert' ) ×
strong Error:
span data can not be saved !
span= err
Test posting Obyte payments, data and data feed transactions. Click on the link in the results section of your page to view your transaction on the Obyte network.
You have to have GIT installed on your machine.
Update "scripts" section of the package.json file to contain the following:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node index.js"
},In command prompt window, go to your project directory, and type git init
This will initialise your git repository. And you will get Initialized empty Git repository... message back. Check the status by typing git status at any time.
Create .gitignore file in your project directory. Use this file to specify files and/or directories you do not want to publish. For example, to exclude myNotes.txt file and /myNotes folder add the following lines to the .gitignore file:
myNotes.txt /myNotes
Type git add . at the command prompt window in the root of your project directory. This will take some time and you will see a lot of warnings like warning: LF will be replaced by CRLF in package.json, which you can ignore. Type git status to check status.
Type git commit -m "1st commit from local" at the command prompt in the root of your project directory. This will commit all your changes. Type git status to check git status.
Sign up with Heroku for one of their free hosting packages.
Login to your new Heroku account in the browser.
Please follow Getting Started on Heroku with Node.js guide at https://devcenter.heroku.com/articles/getting-started-with-nodejs#set-up and install the Heroku Command Line Interface (CLI).
In command prompt go to your project directory and type heroku login Then create new Heroku project by typing heroku create myProject
This will create Heroku project and provide you with url.
In command prompt type git push heroku master
It is a good practice to keep your source on Github. Sign up for a free account using your email address, then login.
Create a new Github repository by clicking on the New button. Github will ask you for a repository name. After repository is generated, Github will provide you with commands for pushing your local code to the new repository.
In command prompt go to your project directory and execute'git remote add origin
Next push your locally stored code into the new repository git push -u origin master
Anytime you make changes to your application remember to update your Github repostiory and deploy to Heroku. Simply go to your project folder in command prompt and type following commands:
git add . git commit -m "another commit" git push -u origin master git push heroku master
This tutorial is coming soon.