Skip to content

jayeen28/falcon-boilerplate

Repository files navigation

Falcon Boilerplate

Falcon Boilerplate is a service-based Node.js backend boilerplate that will help you kickstart and manage your projects more efficiently. This REST API server boilerplate is built upon a powerful stack of technologies, including Express.js, Socket.io, and MySQL, to provide a comprehensive solution for web service development and database management. You can work faster like a falcon by using this template.

Getting Started

Follow these steps to get started with Falcon Boilerplate:

  1. Folder Renaming:
    Start by renaming the demo_ssl folder to ssl and demo_settings to settings.

  2. Configuration:
    Configure your application settings in the settings/dev.js file for development and settings/prod.js for production. You will get the settings inside every request and socket events. The settings used will be determined by the NODE_ENV variable inside the index.js file at the root.

  3. Database Setup
    Install MySQL server on your system and configure the settings file to access the server.

  4. Start the Server
    Start the server using nodemon to enable hot-reloading during development:

    yarn dev

Creating Services

Follow these steps to create a new service:

  1. Create the service root file
    Start by organizing your services within the services directory. Each service should have its own dedicated folder and a corresponding file for the service entry points also a single or multiple entity file for building the core logic.
    Example:

    - services
      | - user
        | - user.js
        | - user.entity.js
    
  2. Generate service and entity with vs code snippets
    If you are using vs code. Then there is two vs code snippets to generate the service and entity code with basic crud wrapper functions. If you follow this step then you don't need to follow step number 3 and 4.

    Trigger Content
    service service code with basic crud api routes and socket function.
    entity entity for the basic crud apies.
  3. Create the api routes and register socket listeners in the service root file
    Service Root File (e.g., user.js):

    const { create, handleClickButton } = require('./user.entity');
    
    /**
     * INSTRUCTIONS:
     * 1. Call API and socket handler functions from entity file (e.g., user.entity.js).
     */
    
    /**
     * Define API routes for user management.
     */
    function userApi() {
    
      /**
       * POST /user
       * @description This route is used to create a user.
       * @response {Object} 201 - The new user.
       * @body {Object} - The data to create a user.
      */
      this.router.post('/user', create(this));
    }
    
    /**
     * Register event handlers for user-related events.
     */
    function userSocket() {
          this.socket.on('clickedButton', handleClickButton(this));
    }
    
    module.exports = { userApi, userSocket };
  4. Create entity functions
    Entity File (e.g., user.entity.js):

    const TABLE_NAME = 'user';
    
    module.exports.create = ({ db }) => async (req, res, next) => {
      try {
        await db.execute(`CALL precedure(?,?)`, ['argument1', 'argument2']);
        return res.status(200).send('data');
      } catch (e) { next(e) }
    };
    
    module.exports.handleClickButton = async ({ db }) => {
      // Implement the functionality you need.
    }

    Note: In this boilerplate, all functions are connected to the Falcon class. This gives you access to various features, like I have accessed the db above. It also allows you to easily add new tools and functionalities to the Falcon class and access them globally.

Inject the service in the app

Lastly For making the service available for your clients you have to inject that in the app.
Follow these steps:

  1. Inject api service:

    const { errorMiddleware } = require("./middlewares");
    +const { userApi } = require("./user/user");
    
    function apiServices() {
    + userApi.call(this);
      this.router.use(errorMiddleware(this))
    };
  2. Inject socket service:

    const { errorMiddleware } = require("./middlewares");
    +const { userApi, userSocket } = require("./user/user");
    
    function apiServices() {
      userApi.call(this);
      this.router.use(errorMiddleware(this))
    };
    
    function socketServices() {
    +  userSocket.call(this);
    };

    As simple as that. Your services are good to go now.

Handling Api Error

In the entity, if you invoke the next function of express with an Error instance as its first parameter, the errorMiddleware function will be triggered. The error will be permanently logged in the data/server_error/{year}/{month}/{day}.log file, and the client will receive a 500 response with a reference id. If reference id is not found in the response, it means the middleware failed to save the error. The error log can be found in the console.

module.exports.create = ({ db }) => async (req, res, next) => {
  try {
    const user = await db.create({ table: TABLE_NAME, payload: { data: req.body } });
    return res.status(201).send(user);
  } catch (e) { next(e) }
};

Serving client

You can place your client code inside the client folder. The Falcon boilerplate will search for the index.html file to serve the client.

Docker

Custom network is only required for production mode because development mode will run on host network.

# Creating bridge type network (if not already exists)
# The database and the api will be in this network.
docker network create -d bridge falcon

Two Docker Compose files are provided:

  • compose_dev.yml: For development mode.
  • compose.yml: For production mode.
# Running in Development Mode
docker compose -f compose_dev.yml up

# Rebuilding API Image (if needed or something went wrong)
docker compose -f compose_dev.yml up --build
# Running in Production Mode
docker compose up -d