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

@studiowebux/app

v5.0.0

Published

This module can be use as the core of the application, it offers directly some tools.

Downloads

122

Readme

Introduction

This module offers multiple features:

  1. Load configurations from a directory to a variable named config
  2. Manage errors
  3. Translate directly from the backend
  4. Convert ID to URL
  5. Guess the IP address of the client
  6. Convert MongoDB arrays to object
  7. Load modules in named variables

This module is built to be used as the base of the application.

For more details (EN/FR) : Wiki

Installation

npm install --save @studiowebux/app

NPM

Usage

Configuration

| Key | Value | Description | More info | | ------------- | ---------------------------------------------------------------------- | ----------- | --------- | | configuration | An absolute path to the directory that contains all the configurations | |

Example:

const opts = {
  configuration: path.join(__dirname, '..', 'config'),
};

Functions

constructor(opts, log = console)

Initialize the config variable,

const WebuxApp = require('@studiowebux/app');

let webuxApp = new WebuxApp(
  {
    configuration: path.join(__dirname, '..', 'config'),
  },
  console
);

The opts parameter is optional.

LoadConfiguration(): Object

To load the configurations using the path specified during the initialization,

const WebuxApp = require('../src/index');
const path = require('path');
const options = {
  configuration: path.join(__dirname, 'config'),
};

const webuxApp = new WebuxApp(options);

webuxApp.LoadConfiguration();

It is also possible to add configurations manually,

webuxApp.config._manual = {
  testing: 'test1',
};

The LoadConfiguration function append the configurations.

LoadModule(modulePath): Object

This function adds exported variables from a file in a centralized variable.

For example, to load all helpers functions in this variable helpers.*

Proceed as follow,

const constants = webuxApp.LoadModule(path.join(__dirname, 'api', 'v1', 'constants'));

const validations = webuxApp.LoadModule(path.join(__dirname, 'api', 'v1', 'validations'));

const helpers = webuxApp.LoadModule(path.join(__dirname, 'api', 'v1', 'helpers'));

const middlewares = webuxApp.LoadModule(path.join(__dirname, 'api', 'v1', 'middlewares'));

console.log(constants);
console.log(helpers);
console.log(middlewares);
console.log(validations);

The files must have a specific structure:

helpers/user.js

function GetUsers() {
  return ['user1', 'user2', 'user3'];
}

let users = ['Default User 1', 'Default User 2'];

module.exports = {
  GetUsers,
  users,
};

Variables and functions are accessible doing :

  • helpers.user.users
  • helpers.user.GetUsers()

The modulePath is mandatory, This value is the absolute path of the directory that has all modules to import.

IdToURL(id, resource, endpoint): String

This function returns an URL based on the information received in parameters.

For example,
A user with this id: 346

const WebuxApp = require('@studiowebux/app');
const webuxApp = new WebuxApp();

const URL = webuxApp.IdToURL(346, 'user', 'https://webuxlab.com/api/v1');

The result : https://webuxlab.com/api/v1/user/346

The id parameter is mandatory, This value is the resource id. The resource is mandatory, This value is the resource name to create the RESTAPI route The endpoint is optional (By default, The config.server.endpoint variable if defined is used), this value is the prefix of the URL.

ToObject(array): Object

This function converts a list to an object

Currently, this function has been only tested with results from MongoDB

let users = [
  { _id: '12345abc22...', name: 'test' },
  { _id: '12345abc23...', name: 'test2' },
  { _id: '12345abc24...', name: 'test3' },
];
console.log(webuxApp.ToObject(users));

The result:

{
  '12345abc22...': { _id: '12345abc22...', name: 'test' },
  '12345abc23...': { _id: '12345abc23...', name: 'test2' },
  '12345abc24...': { _id: '12345abc24...', name: 'test3' }
}

The array is mandatory, The value must be an array with objects, each object must have this key _id to create the mapping.

ConfigureLanguage(): Object

This function configures the i18n. It uses this one from NPM : i18n

This function returns the configured i18n object. Also the module is available using webuxApp.i18n

This function requires a configuration,

For all available options, read the official documentation.

const path = require('path');
const language = {
  availables: ['fr', 'en'],
  directory: path.join(__dirname, '..', 'locales'),
  default: 'en',
  autoReload: true,
  syncFiles: true,
};

Example,

Without loading the configurations automatically,

index.js

const WebuxApp = require('@studiowebux/app');
const webuxApp = new WebuxApp();

// To configure the i18n
webuxApp.config.language = language;

const i18n = webuxApp.ConfigureLanguage();

With the configurations loaded automatically, config/language.js

const path = require('path');
module.exports = {
  availables: ['fr', 'en'],
  directory: path.join(__dirname, '..', 'locales'),
  default: 'en',
  autoReload: true,
  syncFiles: true,
};

index.js

const path = require('path');
const WebuxApp = require('@studiowebux/app');
const webuxApp = new WebuxApp({
  configuration: path.join(__dirname, 'config'),
});

const i18n = webuxApp.ConfigureLanguage();

I18nOnRequest(): Function

This function adds the i18n directly in the express routes (res.__)
For more details, read the official documentation : i18n

This function is used with app.use() from Express.

Usage:

const express = require("express");
const path = require("path");
const app = express();
const WebuxApp = require("@studiowebux/app);

const webuxApp = new WebuxApp({configuration: path.join(__dirname, "config")});

webuxApp.LoadConfiguration();

const i18n = webuxApp.ConfigureLanguage();

app.use(webuxApp.I18nOnRequest());

app.get("/", (req, res) => {
  console.log(webuxApp.i18n.getLocale());

  res.status(200).send({ msg: res.__("MSG_BONJOUR"), lang: i18n.getLocale() });
});

app.listen(1337, () => {
  console.log("Server is listening on port 1337");
});

As shown in the example, there is three ways to use this module,

  1. webuxApp.i18n.*
  2. i18n.*
  3. res.__()

GetIP(request): String

This function guesses the client IP address

It reads these variables:

req.headers['x-forwarded-for'] ||
  req.connection.remoteAddress ||
  req.socket.remoteAddress ||
  (req.connection.socket ? req.connection.socket.remoteAddress : null);

If the address isn't detected, the function returns null.

The reque st is mandatory, This value is provided by the express router.

For example,

...
app.get("/", (req, res) => {
  return res.status(200).send({
    msg: res.__("MSG_BONJOUR"),
    lang: webuxApp.i18n.getLocale(),
    from: webuxApp.GetIP(req),
  });
});
...

ErrorHandler(code, msg, extra, devMsg): Error

It standardizes the error messages and formats them to facilitate the flow.

Example,

const WebuxApp = require('@studiowebux/app');
const webuxApp = new WebuxApp();

app.get('/error', (req, res) => {
  throw webuxApp.ErrorHandler(400, 'Bad Request', { test: 'An object to add extra information' }, 'Message for the dev. team');
});

Request the /error route to see the error returned. It uses the HTTP Code 400 with this messages: Bad Request, then it also provide a way to add an object containing more details and a message for the developers.

The code parameter is optional (by default, 500), The HTTP code The msg parameter is optional, A message to inform the user of the error. The extra is optional, An object with extra informations. The devMsg is optional, A message to inform the developers.

GlobalErrorHandler(): Function

It intercepts all errors thrown by the ErrorHandler() function.
This function must be use at the end, after loading all routes.

This function is used with app.use() from Express.

Par example,

const express = require('express');
const path = require('path');
const app = express();
const WebuxApp = require('@studiowebux/app');

const webuxApp = new WebuxApp();

app.get('/hello', (req, res) => {
  return res.status(200).send({
    msg: 'Bonjour !',
  });
});

app.get('/error', (req, res) => {
  throw webuxApp.ErrorHandler(400, 'Bad Request', { test: 'An object to add extra information' }, 'Message for the dev. team');
});

// Must be after all routes definition, including the static resources
app.use(webuxApp.GlobalErrorHandler());

app.listen(1337, () => {
  console.log('Server is listening on port 1337');
});

NotFoundErrorHandler(): Function

Permet d'intercepter les routes qui ne sont pas trouvées.
Pour utiliser cette fonction, vous devez l'ajouter avant la fonction GlobalErrorHandler(), mais après la définition des routes.

This function is used with app.use() from Express.

Example,

const express = require('express');
const path = require('path');
const app = express();
const WebuxApp = require('@studiowebux/app');

const webuxApp = new WebuxApp();

app.get('/hello', (req, res) => {
  return res.status(200).send({
    msg: 'Bonjour !',
  });
});

app.get('/error', (req, res) => {
  throw webuxApp.ErrorHandler(400, 'Bad Request', { test: 'An object to add extra information' }, 'Message for the dev. team');
});

// Must be after all route definitions, including the static resources
app.use(webuxApp.NotFoundErrorHandler());
app.use(webuxApp.GlobalErrorHandler());

app.listen(1337, () => {
  console.log('Server is listening on port 1337');
});

To use the translation with this module, you can use this key ROUTE_NOT_FOUND

Error(message, name, code, extra, devMsg): Function

Example:

throw WebuxApp.Error('My error Message', 'JEST_TEST', 400, { foo: 'bar' }, 'Occured while testing with jest');

Quick Start

Complete example

Step 1. Directories creation

The application is split like this:

api/
  v1/
    actions/
      user/
        find.js
        findOne.js
        remove.js
        update.js
        create.js
    constants/
      user.js
    helpers/
      user.js
    middlewares/
      isAuthenticated.js
    validations/
      user.js

For more details, see the example here : examples/utils/api/v1

Step 2. The application

app.js

const path = require('path');

const WebuxApp = require('../../src/index');
const app = require('express')();

let webuxApp = new WebuxApp({
  configuration: path.join(__dirname, '..', 'config'),
});

/**
 * The express application
 */
webuxApp.app = app;

webuxApp.LoadConfiguration();
webuxApp.ConfigureLanguage();

// Add other modules, variables and others ...

module.exports = webuxApp;

That way the application is exported and can be imported in the project file to manage everything easily.

Step 3. The server

index.js

const webuxApp = require('./app');
const { app, ErrorHandler } = webuxApp;

app.use(webuxApp.I18nOnRequest());

app.get('/hello', (req, res) => {
  return res.status(200).send({
    msg: res.__('MSG_BONJOUR'),
    lang: webuxApp.i18n.getLocale(),
    from: webuxApp.GetIP(req),
  });
});

app.get('/error', (req, res) => {
  throw ErrorHandler(400, res.__('BAD_REQUEST'), { test: 'An object to add extra information' }, 'Message for the dev. team');
});

app.use(webuxApp.NotFoundErrorHandler());
app.use(webuxApp.GlobalErrorHandler());

app.listen(1337, () => {
  console.log('Server is listening on port 1337');
});

This method allows to manage a complex application using a centralized configuration.

The actions directory

/api/v1/actions/user/
  find.js
  findOne.js
  remove.js
  update.js
  create.js

Those files have a specific structure:

// Global webuxApp
const Webux = require('../../../app');

// action
const finduser = () => {
  return new Promise(async (resolve, reject) => {
    try {
      const users = await Webux.db.user
        .find()
        .lean()
        .catch((e) => {
          return reject(Webux.errorHandler(422, e));
        });
      if (!users || users.length === 0) {
        return reject(Webux.ErrorHandler(404, 'users not found'));
      }

      users.map((user) => {
        user._id = Webux.IdToUrl(user._id, 'user', 'http://localhost');
      });

      return resolve({
        msg: 'Success !',
        users: users,
      });
    } catch (e) {
      throw e;
    }
  });
};

// route
const route = async (req, res, next) => {
  try {
    const obj = await finduser();
    if (!obj) {
      return next(Webux.ErrorHandler(404, 'user not found.'));
    }
    return res.status(200).json(obj);
  } catch (e) {
    next(e);
  }
};

// socket.IO
const socket = (client) => {
  return async () => {
    try {
      const obj = await finduser();
      if (!obj) {
        client.emit('gotError', 'user not found');
      }

      client.emit('userFound', obj);
    } catch (e) {
      client.emit('gotError', e);
    }
  };
};

module.exports = {
  findUser,
  socket,
  route,
};

Videos and other resources

Contribution

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

license

SEE LICENSE IN license.txt