Skip to content

Latest commit

 

History

History
269 lines (193 loc) · 5.31 KB

CoreConcepts.md

File metadata and controls

269 lines (193 loc) · 5.31 KB

Core concepts | nodester

Client

Client is an entity that interacts with your application using HTTP or any other request methods.

Controller

Controller is a gatekeeper to a Facade.

It manages or directs the flow of data between the Client and a Facade.

Example of the Controller which has methods

getOne(req, res)
getMany(req, res)
createOne(req, res)
updateOne(req, res)
deleteOne(req, res)
const {
  withDefaultCRUD,
  withDefaultErrorProcessing
} = require('nodester/controllers/mixins');

const countriesFacade = require('#facades/countries');


module.exports = function CountriesController() {
  withDefaultCRUD(this, {
    facade: countriesFacade
  });
  withDefaultErrorProcessing(this);
}

Facade

Facade is a wrapper around model.

Example of the Facade which has methods

getOne(params)
getMany(params)
createOne(params)
updateOne(params)
deleteOne(params)
const {
  withDefaultCRUD
} = require('nodester/facades/mixins');

// Model.
const Country = require('#models/Country');


module.exports = function CountriesFacade() {
  withDefaultCRUD(this, {
    model: Country
  });
}

Filter

Filter is a set of rules on how to process Client's input.

Model

Model is a high-level definition of a database table.

// ORM.
const DatabaseConnection = require('#db');
// Definition (nodester).
const defineModel = require('nodester/models/define');


const city = defineModel(DatabaseConnection, 'City',
  (DataTypes) => ({
    id: {
      type: DataTypes.INTEGER.UNSIGNED,
      allowNull: false,
      primaryKey: true,
      autoIncrement: true,
      _autoGenerated: true
    },
    
    country_id: {
      type: DataTypes.INTEGER.UNSIGNED,
      allowNull: false,
    },

    name: {
      type: DataTypes.STRING(255),
      allowNull: false,
    }
  }),
  {
    // Allow only "soft" delete.
    paranoid: true
  }
);

city.associate = ({ City, ...models }) => {
  City.belongsTo(models.Country, {
    foreignKey: 'country_id',
    as: 'country'
  });

  City.hasMany(models.Area, {
    foreignKey: 'city_id',
    as: 'areas'
  });
}

module.exports = city;

Markers

Marker is a functional condition that returns true | false, based on data in request/response.

Markers are more powerful indicators than simple route definitions, as any parameter in request/response can be used.

For example: our application has 2 domains: admin.awesomeapp.com api.awesomeapp.com

You add markers and handlers specifically for those domains:

app.add.marker('ADMIN', (req) => req.get('host') === 'admin.awesomeapp.com');
app.add.marker('API', (req) => req.get('host') === 'api.awesomeapp.com');

And then use them:

app.only('ADMIN').route('get /payments', <handler/>);
app.only('API').route('get /payments', <handler/>);
// Or:
app.only('ADMIN').use(<handler/>);
app.only('API').use(<handler/>);

More examples →

Router

Router is a built-in middleware.

const Router = require('nodester/router');

const controllersPath = <path_to_controllers_directory/>;
const router = new Router({ controllersPath });

router.add.route('get /books', function(req, res) { ... } );
// Or:
router.add.route('get /books', { controlledBy: 'BooksController.getMany' } );
router.add.route('get /books/:id', { controlledBy: 'BooksController.getOne' } );

Middleware for a specific route

You can add custom middleware which will run when a specific route is requested.

const Router = require('nodester/router');

const controllersPath = <path_to_controllers_directory/>;
const router = new Router({ controllersPath });

const subscriptionPass = require('#middlewares/subscriptionPass');

router.add.route('get /books', {
  before: subscriptionPass,
  controlledBy: 'BooksController.getMany'
});

You can also provide an array of middlewares:

const middleware1 = require('...');
const middleware2 = require('...');

router.add.route('get /books', {
  before: [ middleware1, middleware2 ],
  controlledBy: 'BooksController.getMany'
});

Filters for specific routes

Set specific Filter middleware before request hits Controller:

const Filter = require('nodester/filter');
const traverse = require('nodester/query/traverse');

const City = require('#models/City');

const filter = new Filter(City, {
  attributes: [
    'id',
    'country_id'
    'name',
  ],
  statics: {
    attributes: {
      country_id: 17
    },
  }
};

function cityFilter(req, res, next) {
  const resultQuery = traverse(req.nquery, filter);
  req.query = resultQuery;
  return next();
}

...

router.add.route('get /cities', { 
  before: cityFilter,
  controlledBy: 'CitiesController.getMany'
});

Using Router in the app

const nodester = require('nodester');
const router = require(<path_to_router_definition/>);

const app = new nodester();
app.use(router());

Provider

Provider manages interactions between application and other APIs. Other APIs include:

  • Third-party APIs;
  • API of node_modules;
  • API of modules inside your application.

Util

Util is a self-sufficient code snippet.

You can find all available utils under nodester/utils.

Copyright

Copyright 2021-present Mark Khramko