npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

boosted-express

v1.0.0

Published

This package simplifies API development by providing an Express server with automatic route inference based on your folder structure. It promotes SOLID principles, integrates Swagger for documentation, Bunyan Logger for logging, and Mongoose for easy acce

Downloads

67

Readme

boosted-express

npm version License: MIT

boosted-express is an npm package designed to simplify and accelerate API development in Node.js, based on SOLID principles. This package was inspired by Carlos Illobre's article on implementing APIs using SOLID in Node.js, and has been extended to offer a powerful tool for building robust and maintainable APIs.

Features

  • Automatic Route Inference: Infers API routes based on your project's folder and file structure, eliminating the need to manually define routes in a routing file.
  • SOLID Principles: Promotes adherence to SOLID principles, especially Single Responsibility and Open/Closed.
  • Swagger Integration: Automatically generates API documentation using Swagger.
  • Bunyan Logger: Provides access to the Bunyan logger in all API functions.
  • Mongoose Integration: Easy access to Mongoose schemas through package configuration, allowing direct interaction with MongoDB in your routes.

Key Concepts from the Original Article

  1. Folder Structure as API Definition: The package uses your folder structure to define your API routes, promoting a clear and intuitive organization of your codebase.

  2. Single Responsibility Principle: Each file represents a single API endpoint, ensuring that each piece of code has one and only one reason to change.

  3. Open/Closed Principle: The system is open for extension (you can add new routes by adding new files) but closed for modification (existing routes don't need to be changed to add new ones).

  4. Dependency Inversion: The package handles the routing logic, allowing you to focus on writing the business logic for each endpoint.

  5. Separation of Concerns: By separating route definition (folder structure) from route implementation (file contents), the package promotes a clean separation of concerns.

Installation

Install the package using npm:

npm install boosted-express

Project Structure

boosted-express infers your API routes based on your project's folder structure. Here's an example:

index.js
/routes
    /user
        addUser.js
        getUsers.js
        /_id
            deleteUser.js
            updateUser.js

Each .js file should export an object with two properties:

module.exports = {
    operation: 'post',  // endpoint HTTP verb
    logic: async (req, res, next) => {
        // Your API logic here
    }
};

This structure will automatically generate the following routes:

  • POST /api/user: Invokes the 'logic' function exported by addUser.js
  • GET /api/user: Invokes the 'logic' function exported by getUsers.js
  • DELETE /api/user/:id: Invokes the 'logic' function exported by deleteUser.js
  • PUT /api/user/:id: Invokes the 'logic' function exported by updateUser.js

Usage

To use boosted-express in your project, set up your folder structure as described above, and the package will handle route inference and management automatically. Here's a example:

const expressBoost = require('boosted-express');

const { logger, database, server } = expressBoost({
    serverOptions: {
        scripts: "./routes/**/*.js",
        basepath: "/api",
        preMiddlewares: [],
        postMiddlewares: [],
        port: 8080,
        static: {
            basepath: '/st',
            root: './content',
            options: { maxAge: '1y' }
        }
    },
    swaggerOptions: {
        info: { 
            title: 'Demo API',
            description: 'Demo API Description',
            contact: {
                name: 'DAPI'
            },
        },
        urlpath: '/docs'
    },
    mongooseOptions: {
        schemas: './schemas/**/*.js',
        connectionString: 'mongodb://localhost:27017/demo',
        connectionOptions: {
            poolSize: 100, 
            useNewUrlParser: true, 
            useUnifiedTopology: true
        }
    },
    bunyanOptions: {
        name: "boosted-express-demo",
        level: "debug",
    }
});

server.start();

Configuration Options

serverOptions

  • scripts: Expression determining the location of API function scripts. Example: "./routes/**/*.js" will search for .js files within the 'routes' folder in the root of your project.

  • basepath: Base path for the API. For example, if the basepath is set to "myapi", and using the file structure from the example above, solid-express will infer that the route for addUser.js is "/myapi/user".

  • preMiddlewares: Express middlewares executed before the API route handler. You can use any middleware compatible with Express. For example, to use express-xml-bodyparser:

    const xmlparser = require('express-xml-bodyparser');
    const xmlParserInstance = xmlparser({ normalizeTags: false });
    
    const options = {
      serverOptions: {
        // ...
        preMiddlewares: [xmlParserInstance],
        // ...
      },
      // ...
    };
    
    const solidApi = require('solid-express')(options);
  • postMiddlewares: Express middlewares executed after the API route handler. These function similarly to the preMiddlewares property.

  • port: Server port.

  • static: Configuration for serving static content. For example, if you have a 'content' folder in your project root containing an index.html file, you can serve it at "http://localhost:8080/st/index.html" with the following configuration:

    const options = {
      serverOptions: {
        // ...
        static: {
          basepath: '/st',
          root: './content',
          options: { maxAge: '1y' }
        }
        // ...
      },
      // ...
    };
    
    const solidApi = require('solid-express')(options);
    solidApi.server.listen(8080);

    For all available options, refer to: Express Static Middleware Documentation

swaggerOptions

  • info: Swagger information (title, description, contact, etc.) For all available options for the info property, see: swagger-jsdoc npm package

  • urlpath: Base path for the auto-generated Swagger documentation site. Example: If set to '/docs', the documentation will be available at "http://localhost:8080/docs"

mongooseOptions

  • schemas: Expression determining the location of Mongoose schemas. Example: "./schemas/**/*.js" will search for .js files within the 'schemas' folder in the root of your project.

  • connectionString: MongoDB connection string.

  • connectionOptions: Mongoose connection options. For all available Mongoose connection options, see: Mongoose Connection Options

bunyanOptions

All configurable options for Bunyan can be found in the Bunyan documentation: Bunyan npm package

Using Mongoose Connection and Logger

solid-express injects the Mongoose connection with all defined schemas loaded, and the logger, through middlewares. This makes it easy to access your database models and logging functionality in your route handlers.

Let's look at an example to clarify:

Defining a Mongoose Schema

First, define your Mongoose schema. For example, in ./schemas/User.js:

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

const UserSchema = new Schema({
    name: String,
    document: String,
});

module.exports = UserSchema;

Using the Schema in a Route Handler

Now, let's use this schema in a route handler. For example, in ./routes/users/addUser.js:

module.exports = {
    operation: 'post',
    logic: async (req, res, next) => {
        try {
            if (!req.body.document || !req.body.name) {
                return res.status(400).send({ error: 'name & document properties are required' });
            }

            const newUser = new req.db.User({ 
                name: req.body.name,
                document: req.body.document
            });

            newUser.save((err, userStored) => {
                if (err) {
                    res.status(500).send({ message: 'Error on saving' });
                } else if (!userStored) {
                    res.status(404).send({ message: 'User not saved' });
                } else {
                    res.status(200).send({ user: userStored });
                }
                next(); // Call next() to pass control to the next middleware
            });
        } catch (error) {
            req.logger.error('Caught error in addUser', error);
            res.status(500).send({ error: 'Internal server error' });
            next(error); // Pass the error to the next error-handling middleware
        }
    }
};

Key Points

  1. Mongoose Connection: The Mongoose connection is available via req.db. In the example, we access the User model with req.db.User.

  2. Logger: The Bunyan logger is accessible via req.logger. Use it to log messages at different levels (e.g., req.logger.info(), req.logger.error()).

  3. Error Handling: Always wrap your logic in a try-catch block to handle unexpected errors. Use the logger to record these errors for debugging.

  4. Response Handling: Ensure you send appropriate HTTP status codes and meaningful messages in your responses.

  5. Middleware Flow: Always call next() at the end of your middleware function to ensure the request is passed to the next middleware in the chain. In case of errors, pass the error to next(error) to trigger error-handling middleware.

Contributing

Contributions are welcome! If you find a bug, need an extension, or have an improvement idea, please open an issue or submit a pull request on the GitHub repository.

License

This project is licensed under the MIT License.

Acknowledgements

This project was inspired by Carlos Illobre's article "Node.js & Express: How to Organize Your Routes in Very Big Applications (and Why Controllers are Evil)". We extend our gratitude to Carlos for sharing his insights on applying SOLID principles to Node.js API development.

Special thanks to Fernando Ron for introducing us to this article and initiating the development of this utility package.