Creating a simple referral System in ExpressJS
Tags: javascript, node, mongodb, api
Published: 2024-06-29 19:26:20

What is a Referral System

A referral system is a platform where current users of an application can invite other people to sign up/join the application. 
It is a marketing tactic used to promote the growth of an application by offering incentives (rewards) by keeping track of the number of users they invite successfully.

Overview of the application.
The fullstack application where this system is implemented in, is one where users are prompted to connect their web3 (metamask) wallets 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lijd388wethl3p1jr91h.png)
in order to unlock the social tasks page which contains the invite (referral) task
![Referral task](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2vpq856qyukn7v1ovbxa.png)

Now that the basic introduction is over, lets get to the code and logic.

After initializing the nodejs project with `npm init` and installing relevant dependencies

a server.js file was created to serve as an entrypoint to the backend application using mongoose as the ORM for mongoDB

```
const express = require("express");
const app = express();
const cors = require("cors");
const mongoose = require("mongoose");
require("dotenv").config();

// env strings
const mongo = process.env.CONNECTION_STRING;

// middleware
app.use(cors());
app.options("*", cors);
app.use(express.json());

//routes
const usersRouter = require("./Router/users");

app.use("/api/users", usersRouter);

app.get("/", (req, res) => {
  res.json("hello");
});

// db connect
mongoose
  .connect(mongo)
  .then(() => console.log("connected to db"))
  .catch((err) => console.log(err));

app.listen(8080, () => {
  console.log("listening to server");
});
```
A simple express router was used route all API endpoints related to the user, for organisation purposes 

---

In the userRoutes file, a simple user schema containing the shape of how the user document would look in the database

```
const { User } = require("../Models/user");
const express = require("express");
const router = express.Router();
``` 
The userId was used as the unique identifier for each user, and sent from the frontend to the backend endpoint through a URL string Parameter
example:
`https://backendserver.com/api?referral=referralId&foo=bar`

everything after the question make becomes a 'query parameter' and can be chained with the '&' character

---

in the actual api route,

- the referral id is received from the fronted through query param
- the user's wallet is sent through the request body
- uses Mongoose methods on the User object to perform dB queries
- adds points when the requirements are satisfied

```
// Route handler for signing in by connecting wallet/ creating new user
router.post("/", async (req, res) => {
  try {
    const { r } = req.query; // Get the id from the query parameters
    const { wallet } = req.body;

    if (r) {
      try {
        // Signup with referral
        const inviter = await User.findOne({ _id: r });
        console.log(inviter);
        const invited = await User.findOne({ wallet });

   // If invited user doesn't exist, create their account in db, 
    log them in, and add points to inviter
        if (!invited) {
          const newUser = new User({ wallet });
          await newUser.save();

          // add points to inviter
          const updatedInviter = await User.findOneAndUpdate(
            { _id: r },
            { $inc: { referrals: 1, points: 1 } },
            { new: true },
          );

          return res.status(200).json(newUser);
        } else {
          // If the invited user exists in db, return its details
          return res.status(200).json(invited);
        }
      } catch (error) {
        console.error("Error adding referral point:", error);
        return res.status(500).json({ error: "Internal server error" });
      }
    } else {
      // Regular signup process
      try {
        // Check if the wallet address already exists
        const existingUser = await User.findOne({ wallet });
        if (existingUser) {
          // Wallet address already exists
          return res.status(200).json(existingUser);
        } else {
          // Wallet address doesn't exist, create a new user
          const newUser = new User({
            wallet,
          });
          await newUser.save();
          return res.status(200).json(newUser);
        }
      } catch (error) {
        console.error("Error connecting wallet:", error);
        return res.status(500).json({ error: "Internal server error" });
      }
    }
  } catch (error) {
    console.error("Error:", error);
    return res.status(500).json({ error: "Internal server error" });
  }
});
```
thanks for reading ;)

to learn more:
https://hng.tech/internship
https://hng.tech/hire