04 / 11Beginner
Comparing backends
Time to look at real code. The examples below compare a traditional Web2 app with a Chromia dapp, highlighting where the two differ and where they overlap, and introduce a few Chromia development concepts on the way. This is not a full tutorial on dapp development; for that, see the introductory dapp development course or the advanced dapp development course.
The examples use a stripped-down version of the dapp from the advanced course, a social media news feed. To keep the code short, the app does only three things: create users, let users publish posts, and return a list of posts.
You'll start on the backend. First comes a quick refresher on a basic Web2 backend, followed by the equivalent built on Chromia.
Web2 backend with Node.js, Express, and PostgreSQL
Web2 apps can be built on many different stacks. This example uses Node.js, Express, and PostgreSQL, though the ideas carry over to other languages and frameworks.
The first step is a PostgreSQL database hosted on a service such as AWS RDS or Google Cloud SQL.
With the database running, you write a Node.js service that connects to it, either through the Node.js PostgreSQL driver or through an ORM (Object Relational Mapper) like Sequelize. A Sequelize version looks roughly like this:
// db.jsimport { Sequelize, DataTypes, Model } from "sequelize";const sequelize = new Sequelize( "postgres://username:password@localhost:5432/mydatabase", { dialect: "postgres", logging: false, });// User Modelclass User extends Model {}User.init( { name: { type: DataTypes.STRING, allowNull: false }, id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true }, }, { sequelize, modelName: "User", timestamps: false });// Post Modelclass Post extends Model {}Post.init( { timestamp: { type: DataTypes.DATE, defaultValue: DataTypes.NOW }, userId: { type: DataTypes.INTEGER, references: { model: User, key: "id" }, }, content: { type: DataTypes.TEXT, allowNull: false }, }, { sequelize, modelName: "Post", timestamps: false, indexes: [{ fields: ["userId"] }], });// RelationsUser.hasMany(Post, { foreignKey: "userId" });Post.belongsTo(User, { foreignKey: "userId" });export default { sequelize, User, Post };The code defines two models, User and Post. It is deliberately minimal; a production app would usually need more models, but a small example makes the Web2 and Chromia comparison easier to follow.
The next step is an API for creating users and posts and for retrieving a list of users. This example builds it with Express, a widely used JavaScript web framework:
// server.jsimport express from "express";import bodyParser from "body-parser";import { User, Post } from "./db.js";const app = express();const PORT = 3000;app.use(bodyParser.json());// Create a userapp.post("/users", async (req, res) => { try { const user = await User.create(req.body); res.status(201).send(user); } catch (error) { res.status(400).send(error.message); }});// Create a postapp.post("/posts", async (req, res) => { try { const post = await Post.create(req.body); res.status(201).send(post); } catch (error) { res.status(400).send(error.message); }});// Fetch a list of users with simple paginationapp.get("/users", async (req, res) => { try { const limit = req.query.limit ? parseInt(req.query.limit, 10) : 10; const offset = req.query.offset ? parseInt(req.query.offset, 10) : 0; const { count, rows } = await User.findAndCountAll({ limit: limit, offset: offset, }); res.status(200).send({ total: count, data: rows }); } catch (error) { res.status(500).send(error.message); }});app.listen(PORT, () => { console.log(`Server is running on port ${PORT}`);});Authentication and authorization are left out here; a later part of the course covers them.
Finally, you deploy the Node.js service to a cloud host such as AWS, Google Cloud, or Heroku.
Web3 backend with Chromia entities and operations
On Chromia, you write the dapp backend in Rell. There is no database for you to host, because the Chromia platform handles that for you.
Start by defining the data model in Rell:
entity user { mutable name; key id: byte_array;}entity post { timestamp = op_context.last_block_time; index user; content: text;}When you deploy this code, the required tables are created for you in Chromia's distributed relational database. PostgreSQL runs underneath, but you never access it directly. Nodes running the Chromia core software interpret your Rell code and turn it into SQL queries. This keeps the database secure and ensures each dapp can modify only its own data.
Next, expose an API for creating users and posts and for retrieving a list of users:
operation create_user(name, pubkey) { create user(name, pubkey);}operation make_post(user_id: byte_array, content: text) { create post( user @ { user_id }, content );}query get_users(pointer: integer, n_users: integer) { val users = user @* {} ( .name ) offset pointer limit n_users; return ( pointer = pointer + users.size(), users = users );}An operation in Rell changes data in the database, while a query only reads data.
No further setup is needed. Rell exposes operations and queries automatically, and clients call them by sending transactions or queries to the news feed dapp on the Chromia network.
You deploy dapp code to the Chromia Network with the Chromia CLI. The Chromia Docs explain the CLI and the deployment process.