NEAR zero to hero: Building a Full-stack application
This is the second tutorial of NEAR Nigeria zero to hero series. The goal of this series is to transform a programmer with no experience in developing decentralized applications to a skilled NEAR developer. Learn more about this series here.
This tutorial is meant to provide easy on-boarding to the NEAR SDK and how to build a full-stack decentralized application on NEAR. You will spin up a full-stack application template using “create-near-app” and NEAR Rust SDK.
The example presented in this tutorial is a simple scaffold that consists mainly of the smart contract components and front-end application components.
Introduction
Building blockchain applications can be daunting even for seasoned web developers. This may be because as a blockchain developer, you are in full control of your development environment and its configurations.
“create-near-app” is a utility package that allows you as a developer to quickly and easily build applications backed by NEAR Protocol.
NEAR Rust SDK is composed of robust, battle tested rust libraries that makes writing and testing mission critical smart contracts on NEAR much easier.
Prerequisites
To complete this tutorial successfully, you will need:
- Rust toolchain
- A NEAR account
- NEAR command-line interface (near-cli)
- Working knowledge of JavaScript
- Working knowledge of Rust
- Experience using git and GitHub
#note: check the previous tutorial to set-up the first three requirements.
Getting started
To create a new NEAR project with default settings, you just need one command
Using npm’s npx:
npx create-near-app [options] new-project
Or, if you prefer yarn:
yarn create near-app [options] new-project
#note: without any options, this will create a project with a vanilla JavaScript frontend and an AssemblyScript smart contract.
Other options:
— frontend=react — use React for your frontend template
— contract=rust — use Rust for your smart contract
Creating a new project
The steps below describe how to create a new NEAR project that uses React for the frontend and Rust smart contract.
- Open a terminal and run:
yarn create near-app — frontend=react — contract=rust fs-z2h
This command creates a new project named “fs-z2h”, that has Rust smart contract template, React frontend integrated with the smart contract template as well as helpful configurations out of the box.
- Run:
cd fs-z2h
This command sets your current directory to “fs-z2h”. Inspect the directory to see the files created for you.
Exploring the code
- The “back-end” code lives in the “contract” directory. It contains “Cargo.toml” and “src” directory.
- The “frontend” code lives in the “frontend” directory. It contains “App.js”, “index.js” “index.html” and “asset” directory
Breaking it down
Before we continue, let’s review some parts of the newly created project. We’ll break down the code in pieces in the next sections.
#note: Before you proceed, open the newly created project in your favourite code editor.
The Back-end
Let’s review some parts of the smart contract’s source code in ./contract/src/lib.rs.
Imports and initial code
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
use near_sdk::{env, near_bindgen};
At the top of this file you have the standard imports. The packages that follow the use statement can be found as dependencies in Cargo.toml. All the imports involving serialization are used to bundle the code/storage so that it’s ready for the blockchain.
The code also takes env from near-sdk-rs. This will provide a blockchain context for the smart contract execution including; the sender of a transaction, tokens sent, logging, etc.
#note: When writing smart contracts, the pattern is to have a struct with an associated impl where you write the core logic into functions.
The core logic: the struct
const DEFAULT_MESSAGE: &str = “Hello”;
#[near_bindgen]
#[derive(Default, BorshDeserialize, BorshSerialize)]
pub struct Contract {
message: String,
}
impl Default for Contract{
fn default() -> Self{
Self{message: DEFAULT_MESSAGE.to_string()}
}
}
#[near_bindgen]
impl Contract {
…
We declare our Contract which contains a variable message, and impl, which define the functions that ‘act’ on the variable message.
The core logic: contract initialization
impl Default for Contract{
fn default() -> Self{
Self{message: DEFAULT_MESSAGE.to_string()}
}
}
This block of code defines the default message after the smart contract is deployed to initialize the smart contract.
#note: this is similar to a constructor in solidity
Unit tests
The unit tests begin at:
mod tests {
…
}
and continue until the end of the lib.rs file.
Writing a test
The unit test code comes into play here:
fn set_then_get_greeting() {
let mut contract = Contract::default();
contract.set_greeting(“howdy”.to_string());
assert_eq!(
contract.get_greeting(),
“howdy”.to_string()
);
}
You may add as many tests as you need following the pattern in this file. Similar to unit tests in other languages and frameworks, just add the attribute: #[test] above the block of code to have it executed in the test suite.
In this section, you will test the smart contract, compile it, and generate a wasm release binary. You can easily test the smart contract code using cargo. Navigate to “src” directory and run:
cargo test — — nocapture
You should get an output like:
running 2 tests
Saving greeting howdy
test tests::get_default_greeting … ok
test tests::set_then_get_greeting … ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Compile the code
Assuming that all the tests passed ok, you can go ahead and compile the smart contract. Navigate to “src” directory and run:
cargo build — target wasm32-unknown-unknown — release
#note: The above build command is setting a target flag to create a WebAssembly .wasm file.
The Front-end
Let’s review some parts of the source code in ./frontend/assets/js/near/config.js, ./frontend/assets/js/near/utils.js, and ./frontend/App.js.
./frontend/assets/js/near/config.js
NEAR has several development networks operating independently of each other with their own accountIDs.
The config.js file makes network configuration a walk in the park. It defines the name of your contract and different networks for unique cases, including: continuous integration test, development, and production.
#note: development network is used for this tutorial.
./frontend/assets/js/near/utils.js
The utils.js file contains useful abstraction from the near-api-js. These abstractions:
- set your network configuration defined in config.js
- connect your frontend web interface to the configured network
- initialize your contract APIs
- login NEAR accounts
- logout NEAR accounts
./frontend/App.js
App.js contains the meat of interactivity with the smart contract. App.js imports your configuration from config.js, and utilities from utils.js.
The main function in App.js include:
- login the user
- ensures the user “authorized” the smart contract access to her wallet
- queries your smart contract for the message using the API defined in utils.js
- call your smart contract set_greeting using the API defined in utils.js
- logout the user
Running the application
That was a mouthful of information, let’s wrap it up by deploying your smart contract to testnet and deploying your frontend to GitHub using gh-pages
Setting up deployment configuration
With the compiled .wasm file ready, you can go ahead and deploy the smart contract. To deploy it, you will use near-cli and your testnet NEAR account.
- Authorize near-cli, by running:
near login
- Provide an accountID to deploy your smart contract in the config.js file like so:
const CONTRACT_NAME = process.env.CONTRACT_NAME || “fs-z2h.testnet”;
#note: “fs-z2h.testnet” is the name of the testnet account created for this tutorial
#note: The default network for near-cli is testnet. If you would like to change this to mainnet or betanet, please see near-cli network selection for instructions.
Now that your login keys have been saved to the home directory, you can use near-cli to deploy the compiled contract to NEAR.
Now that your login keys have been saved, you can use the pre-configured frontend deployment script to deploy the app to github using gh-pages.
- Follow the steps here to set up your project github repository.
- Push your code from your local git directory to github
Deploying your application 🚀
Deploying your smart contract and your frontend is as simple as running a simple command. Ensure that you have configured your accountID and your code has been pushed to github.
Open a terminal and run:
yarn deploy
This builds your smart contract, runs some tests and deploys the wasm files to your testnet accountID.
Congratulations! Your application is live!!!
#note: alternatively, you can run your frontend locally and test out your application before pushing to github using yarn dev.
Next steps
This example should be used as a guide to rapidly build applications on NEAR. Each part can be modified to suit your specific use case.
You are encouraged to modify the source code as much as possible and even completely ignore it if it is too simple or advanced for your use case.
Now that you’re familiar with the build process, a natural next step is to learn how NEAR works. In the next series you will build a fungible token and some learn some of the essential pieces of NEAR that makes it a simple, and fast blockchain protocol.
Versioning for this article
At the time of this writing, this example works with the following versions:
- cargo 1.62.0 (a748cf5a3 2022–06–08)
- rustc 1.62.0 (a8314ef7d 2022–06–27)
- near-cli: 3.4.0