1.2.0 • Published 4 years ago

nautilus-nodejs-api-core v1.2.0

Weekly downloads
2
License
ISC
Repository
github
Last release
4 years ago

Nautilustar API Core

NautilusStar API Core is a standard feature set of an api

It serves as a core module for building api for microservices

It has all integration with http server, routes, database, logs and injection dependency

To facilitate integration and development, the Clean architecture concept is used, but you can use any type of architecture.

It is possible to make declarations from Mappers, Entities, Model, Repositories, UseCase, Controllers etc.

Installation

Install with npm

npm i nautilus-nodejs-api-core --save

Npm Package https://www.npmjs.com/package/nautilus-nodejs-api-core

Sample

Repo https://github.com/charleston10/nautilus-nodejs-api-users-sample.git

git clone https://github.com/charleston10/nautilus-nodejs-api-users-sample.git

Usage

This configuration based in Clean Architecture

(input request http) Presentration -> Domain -> Data

(output response htttp) Data -> Domain -> Presentation

import path from "path"

import {
    container,
    application,
    database,
    logger
} from 'nautilus-nodejs-api-core';

//create register database
//is used sequelize for create the configuration
//the config database is .env
database
    .register(container)
    .loadEntity(path.join(`data`, `local`, `entities`), __dirname);//import entities of datbase

//create all config the application
//register mappers, model, repository, usecase and controllers
//all classes and files will be available to be injected in context of application
application
    .register(container)
    .loadMiddleware([
        path.join(`core`, `middleware`)
    ], __dirname
    )
    .loadValues([
        path.join(`data`, `mappers`), 
        path.join(`domain`, `model`)
    ], __dirname)//declare functions and files for inject 
    .loadModules([
        path.join(`data`, `repository`, `*.*`),
        path.join(`domain`, `usecase`, `**`, `*.*`)
    ], __dirname)//load modules core of your application to inject
    .loadRoutes(
        path.join(`presentation`, `controllers`, `*.*`)
    , __dirname)//declares routes from api to server
    .loadDatabase(
        database
            .register(container)
            .configure({...})//connection sequelize
            .loadEntity(
                path.join(`data`, `local`, `entities`),
                __dirname
            )
    )
    .start(process.env.PORT || 3000)//get informations by .env
    .catch((e: any) => {
        logger.error(e.stack);//log all error stack
        process.exit();
    })

Quick start

All classes is enable for inject named with first letter in lowerCase Example: GetUserUseCase is enabled how getUserUseCase

How to config routes

The configuration of the controllers is the entire gateway to the application, where it is found in the Presentation layer of our architecture Here we can process input and output, searching the data through UseCase that will execute the necessary rule for the operation

import { route, GET, POST } from 'awilix-express';
import HTTP_STATUS from 'http-status';

@route('/users')
export default class UserController {

    //variable injected using UserUseCase
    //classes registered in container in loadModules(domain)
    private _getAll: any;
    private _create: any;

    constructor({ getAll, create }: any) {
        this._getAll = getAll;
        this._create = create;
    }

    @GET()
    async get(req: any, res: any, next: any) {
        const { SUCCESS, ERROR } = this._getAll.outputs;

        this._getAll
            .on(SUCCESS, (listResult: Array<Object>) => {
                res
                    .status(HTTP_STATUS.OK)
                    .json(listResult);
            })
            .on(ERROR, next);

        this._getAll.execute();
    }

    @POST()
    async create(req: any, res: any, next: any) {
        const { SUCCESS, ERROR } = this._create.outputs;

        this._create
            .on(SUCCESS, (result: Object) => {
                res
                    .status(HTTP_STATUS.OK)
                    .json(result);
            })
            .on(ERROR, next);

        this._create.execute(req.body);
    }
}

How to config UseCase

The UseCase component is responsible for executing all business rules of the project It has an asynchronous execution and can emit any result through events The usecase event in this case and the SUCCESS and ERROR event can be customized according to the need

Create User UseCase

import { UseCase } from 'nautilus-nodejs-api-core'

class Create extends UseCase {

    //variable injected using UserRepository and UserModel
    //classes registered in container in loadModules(repository) and loadValues(model)
    private repository: any;
    private Model: any;

    constructor({ userRepository, userModel }: any) {
        super()
        this.repository = userRepository;
        this.Model = userModel;
    }

    async execute(data: any) {
        const { SUCCESS, ERROR } = this.outputs;

        const model = new this.Model(data);

        try {
            const newData = await this.repository.add(model);
            this.emit(SUCCESS, newData);
        } catch (error) {
            this.emit(ERROR, error);
        }
    }
}

Create.setOutputs(['SUCCESS', 'ERROR']);

export default Create;

Get All User UseCase

import { UseCase } from 'nautilus-nodejs-api-core'

class GetAll extends UseCase {

    private repository: any;

    //variable injected using UserRepository
    //classes registered in container in loadModules(repository)
    constructor({ userRepository }: any) {
        super()
        this.repository = userRepository;
    }

    async execute() {
        const { SUCCESS, ERROR } = this.outputs;

        try {
            const data = await this.repository.getAll();
            
            this.emit(SUCCESS, data);
        } catch (error) {
            this.emit(ERROR, error);
        }
    }
}

GetAll.setOutputs(['SUCCESS', 'ERROR']);

export default GetAll;

How to config Repository

All repositories are responsible for obtaining access data, in this case, entering the database

Within our core module, there are some standard data access and writing functions that make it easier in our daily lives Using the class extension, it offers the functions

GetAll, GetByIDd, Add, Remove, Update, Count and even Transaction

The transaction you can use to make multiple inserts and rollback if needed

And the methods can be overridden if necessary

Create User Repostiory

import { BaseRepository } from 'nautilus-nodejs-api-core'

class UserRepository extends BaseRepository {

    constructor({ userEntity, userMapper }: any) {
        super(userEntity, userMapper);
    }
}

export default UserRepository;

How to config Middlewares

Most of the time, we need to add middleware to our api In a simple case, add Middleware to add an ID to identify a request made.

Observation: An order that is being executed is an order that is in the folder (alphabetical order)

Example

const crypto = require("crypto");
 
export = (req: any, res: any, next: any) => {
    const id = crypto.randomBytes(10).toString("hex");
    req.requestId = id;
    next()
}

Add this middleware in our application

import path from 'path';
 
application
    .register(container)
    .loadMiddleware([
        path.join(`core`, `middlewares`),//or [core//middlewares]
    ], __dirname)//add any middlewares

How to config Database

All database configuration is based on Sequelize, so the use of any database is dynamic and there is a working pattern

To specify the bank registration data, it is necessary to use the settings in environment variables The module itself can see the values and make the connection normally

application.loadDatabase(
        database
            .register(container)
            .configure({
                host: process.env.DB_HOST,
                dialect: process.env.DB_DIALECT,
                database: process.env.DB_NAME,
                username: process.env.DB_USERNAME,
                password: process.env.DB_PASSWORD,
                options: { logging: false }
            })
            .loadEntity(
                path.join(`data`, `local`, `entities`),
                __dirname
            )
    )

Dependencies

Special thanks

Culture for innovation time in my project TraceFacil and inspired in boilerplate nodejs

1.2.0

4 years ago

1.1.0

4 years ago

1.0.27

4 years ago

1.0.26

4 years ago

1.0.25

4 years ago

1.0.24

4 years ago

1.0.23

4 years ago

1.0.22

4 years ago

1.0.21

4 years ago

1.0.20

4 years ago

1.0.19

4 years ago

1.0.18

4 years ago

1.0.17

4 years ago

1.0.16

4 years ago

1.0.15

4 years ago

1.0.9

4 years ago

1.0.8

4 years ago

1.0.11

4 years ago

1.0.10

4 years ago

1.0.14

4 years ago

1.0.13

4 years ago

1.0.12

4 years ago

1.0.7

4 years ago

1.0.6

4 years ago

1.0.5

4 years ago

1.0.4

4 years ago

1.0.3

4 years ago

1.0.2

4 years ago

1.0.1

4 years ago

1.0.0

4 years ago