0.0.64 • Published 5 years ago

zodora-backend-core v0.0.64

Weekly downloads
2
License
MIT
Repository
github
Last release
5 years ago

Zodora-backend-core

The zodoro backend core facilitates the creation of a backend. It is a template for tables/models, validation, services and endpoints. The core manages the eccosystem and controls the state of the endpoint, services or database. Data changes execute triggers via the listener and allow a proper data flow in two directions.

Install

Install via npm:

$ npm install zodora-backend-core

Install via yarn:

$ yarn add zodora-backend-core

Quick Start

// Create Database
const mongoDB = new MongoDB(27017, 'MyDatabase');

// Start the builing of core
const core: Core = new Core(mongoDB);

// Init model
core.addModel((core: Core): Model => {
    return new Model('User', {
        id: {
            type: 'Id',
            name: '_id'
        },
        firstName: {
            type: 'String',
        },
        lastName: {
            type: 'String',
        },
        age:{
            type: 'Number',
            min: 0,
            max: 150
        }
    });

// Here init models, endpoints or services
const restApi: RestApi = new RestApi();
enpoint.generateApiRequest({
    core,
    paths:[{
        path:"api",
        middleware: new RequestCounter(core),
        children:[{
            path:"users",
            async (core: Core, args: ApiRequestArgument): Promise<Result> => {
                // TODO Something
               return {}
            }
        }]
    }]
});
core.addEndpoint("RestAPI", restApi);

// Create and start core
core.createAndStart();

Table of Content

  1. Core
  2. Model
  3. Endpoint
  4. Service
  5. Database
  6. Trigger

Core

The core managed all adding components and connect the complete system of parts.

The core must be created with a database, because the model gives them the task of what they do.

const core: Core = new Core(database);

The second step is to add of models which require a function of returning a model.

core.addModel((core: Core): Model => {
    return new Model('User', {
        id: {
            type: 'Id',
            name: '_id'
        }
    });

After that can be add an endpoint. There are two implementations of endpoints (Restfull and WebSocket)

core.addEndpoint("RestAPI", new RestApi());

If you need a service, you can now add a service. As Example a cleanup service or a auto start service.

core.addService(new StopService(24 * 60 * 60 * 1000));

If you need a trigger of changing data, you can now add a trigger. As Example a logger trigger.

core.addTrigger(TriggerLogger);

It a ready to start than create and start the core. Now managed the core all things and controller the state.

core.createAndStart();

Should the application be stopped, only the core needs to be stopped.

core.stopAndDestroy();

Model

The model has an exact scheme of this and works with their rules.

Create a new Model with that name and the schema

const userModel = new Model('User',schema);

The schema is a object of SchemaType and it has many of entry.When you add a new entry, the name of the child object is the name you see. Then the type of entry must be set.

{
    firstName: {
        type: 'String'
    }
}

Types:

  • String
  • Number
  • Id Id of the own object
  • Refs A reference to a other model

General Options

NameTypeDescription
requirebooleanMust be a always a value
namestringThat is the name for the database
exportbooleanIf export this entry or make it invisible
exportNamestringSet the export name
set(data : number/string/boolean) => number/string/booleanChange the value before it save in the database
get(data : number/string/boolean) => number/string/booleanChange the value after read from the database
protectionbooleanThe value is write protection for the default way

String Option

NameTypeDescription
minnumberMin length of string
maxnumberMax length of string
validate(data:string) => booleanA function of own validation
defaultstring or ()= > stringIf the value not defined than set this value by the inserting

Number Option

NameTypeDescription
minnumberMin value
maxnumberMax value
validate(data:number) => booleanA function of own validation
defaultnumber or ()= > numberIf the value not defined than set this value by the inserting

Refs Option

NameTypeDescription
modelstringModel to the depend reference
idNamestringName of entry which are the reference
dependbooleanDelete the complete entry when don't a reference (true) or set only this null (false)

Boolean Option

NameTypeDescription
defaultbooleanIf the value not defined than set this value by the inserting

Endpoint

The endpoints are a interface to outside of system and can be control the data flow. The main function are the manage api request. For the normal request can be generate this functions which have some settings or you write simple a own method. Permission or other middleware can be set between many layers or request.

Schema of Api-Request

Arguments

NameTypeDescription
metaobjectValues of id or other meta / header information
dataobjectValues of insert, update, delete or reading data

Result

NameTypeDescription
dataobjectResult of data
errorError[]List of errors

Exist endpoints

WsServer
NameTypeDescription
httpsbooleanUse https
portnumberPort number
keystring or BufferKey of certificate
certstring or BufferKey of certificate

Connection with JSON

NameTypeDescription
idnumberId of request and answer id
pathstringExecute function path.
argsobjectArgument for the request
RestApi
NameTypeDescription
httpsbooleanUse https
portnumberPort number
keystring or BufferKey of certificate
certstring or BufferKey of certificate

Own endpoint

class MyEnpoint extends Endpoint {

    async create(): Promise<void> {
        // Create the endpoint
    }

    async start(): Promise<void> {
        // Start the endpoint
    }

    async stop(): Promise<void> {
        // Stop the endpoint
    }

    async destroy(): Promise<void> {
        // Destroy the endpoint
    }

    protected useRequest(request: ApiRequest): void {
        // Implemention of api request
    }
}

Api-Request Generator

enpoint.generateApiRequest({
    core,
    paths:[{
        path:"api",
        middleware: new RequestCounter(core),
        descriptor: [
            param('userId', 'string', true, false),
            result(true,"Return the user values with the 'userId'.")
        ],
        children:[{
            path:"users",
            async (core: Core, args: ApiRequestArgument): Promise<Result> => {
                // TODO Something
               return {}
            }
        }]
    }]
});

Path Option

NameTypeDescription
pathstringCurrently path
middlewareMiddleware or Middleware[]Changing/ checking or modification of arguments or throw errors
descriptorArray of param(name: string, type: string, metaData?: boolean , require?: boolean, description?: string ) or result(success: boolean, message: string, details?: any)Generate for a request all used params at path, permission and middleware and the result. Generate docs via endpoint.generateApiRequest(): ApiRequest[]
childrenPath[]Sub paths of this path
execute(core: Core, args: ApiRequestArgument) => Promise<ApiRequestResult>Execute function on this path

Middleware

Middleware is an interface between a default request and special modification layer. As an example can you create a middleware for the api key management.

class RequestCounter extends Middleware{

    private counter = 0;

    async pre(args: ApiRequestArgument): Promise<RequestError[]> {

        counter++;

        // Exist error
        return [];
    }

    async post(args: ApiRequestArgument): Promise<RequestError[]> {

        counter--;

        // Exist error
        return [];
    }

}

Api-Doc Generator

Generate a Api documentation via PathConfig with easy entries. Use the Description-Object in the Path, Middleware or at Permission. It exits simple function for entries (param(...),result(...),resultAsError(...),meta(...),group(...)).

Adding Option
path = {
    descriptor: [
        ...
    ]
}
class RequestCounter extends Middleware{

    description(): Descriptor {
            return [
                ...
            ];
    }
}
permission = {
    descriptor: [
        ...
    ]
}
Description function
  • Add all inside request into this group: group(name: string, details: string)
  • Create Api-Entry: request(name: string, details: string)
  • Add Param: param(name: string, type: string, metaData: boolean = true, require: boolean = true, description = '')
  • Add Error: resultAsError(error: Error)
  • Add default result: result(success: boolean, message: string, details?: any)
Generate Doc
  • Read only the Api-Tree DocBuilder(name: string, url: string, option: PathConfig)
  • Build to a README text MDGenerator(name: string, url: string, option: PathConfig)

Api-Request Tests

This eccosystem have an own integration test system of testing api request. An TestEndpoint simulate a normal endpoints and extends with test function.

Quick Using

const endpoint: Endpoint = new TestEndpoint();

// Do something ...

// Load tests object
const test = {
    path: "/login",
    arguments: async (core: Core, store: ArgumentStore): Promise<ApiRequestArgument> => {

        // Load and init Arguments
        return {
            meta: {},
            data: {
                email: "abc@def.com",
                password: "HelloWorld"
            }
        };
    },
    result: async (core: Core, store: ArgumentStore, result: Result): Promise<boolean> => {

        // Check the result
        return result.error && result.error.length > 0;
    }
}


// Added
endpoint.addTest(test);

// Execute
endpoint.executeTests();
TestGroup
  • The ArgumentStore is a cache inside a test group.
NameTypeDescription
namestringName of the testing group
before(core: Core, store: ArgumentStore) => Promise<void>Execute before the test at this group starts
after(core: Core, store: ArgumentStore) => Promise<void>Execute before the test at this group starts
tests(TestGroup / TestRequest)[]The tests at this group.
TestRequest
  • The ArgumentStore is a cache inside a test group.
NameTypeDescription
pathstringRequest path
namestringName of Test
arguments(core: Core, store: ArgumentStore) => Promise<ApiRequestArgument>Init the arguments for the request
result(core: Core, store: ArgumentStore, result: Result) => Promise<boolean>Checking the result of request

Service

A service is a external process and work in an interval of time. A own process may be an auto stop service of the core.

class StopService extends Service {

    constructor(lifeTime: number) {
        super("StopService", lifeTime);
    }

    async onEvent(core: Core): Promise<void> {
        return core.stopAndDestroy();
    }
}

Database

The core hasn't only one database but have a default construct of a database. Have you a new used database than can you add this into the core.

Implements databases

  • MongoDB
  • VirtualDB (for simple and fast testing)
class MyDataBase extends DataBase {

    async connect(): Promise<void> {
        // Connect with the database
    }

    async disconnect(): Promise<void> {
        // Disconnect with the database
    }

    async createTable(model: Model): Promise<void> {
       // Create a new table of model
    }

    async deleteByModel(model: Model, filter: DBFilter): Promise<void> {
        // Delete data
    }

    async findByModel(model: Model, filter: DBFilter, option: FindOption = {}): Promise<DataValue[]> {
        // Find many data
    }

    async insertByModel(data: DataValue, model: Model): Promise<DataValue> {
        // Insert a new data
    }

    async updateByModel(data: DataValue, model: Model, filter: DBFilter): Promise<void> {
       // Update the data
    }
}

Trigger

A trigger call if insert, update or delete a data. A core can be have many trigger listener.

core.addTrigger({
    async insert(model, values): Promise<void> {
        // A data value was insert
    },
    async update(model, data, updates): Promise<void> {
        // A data value was update
    },
    async delete(model, data): Promise<void> {
        // A data value was delete
    }
});
0.0.64

5 years ago

0.0.63

5 years ago

0.0.62

5 years ago

0.0.61

5 years ago

0.0.60

5 years ago

0.0.59

5 years ago

0.0.58

5 years ago

0.0.51

5 years ago

0.0.52

5 years ago

0.0.53

5 years ago

0.0.54

5 years ago

0.0.55

5 years ago

0.0.56

5 years ago

0.0.57

5 years ago

0.0.50

5 years ago

0.0.49

5 years ago

0.0.46

5 years ago

0.0.47

5 years ago

0.0.48

5 years ago

0.0.45

5 years ago

0.0.40

5 years ago

0.0.41

5 years ago

0.0.42

5 years ago

0.0.43

5 years ago

0.0.44

5 years ago

0.0.37

5 years ago

0.0.38

5 years ago

0.0.39

5 years ago

0.0.35

5 years ago

0.0.36

5 years ago

0.0.34

5 years ago

0.0.33

5 years ago

0.0.30

5 years ago

0.0.31

5 years ago

0.0.32

5 years ago

0.0.28

5 years ago

0.0.29

5 years ago

0.0.27

5 years ago

0.0.26

5 years ago

0.0.25

5 years ago

0.0.23

5 years ago

0.0.24

5 years ago

0.0.21

5 years ago

0.0.22

5 years ago

0.0.20

5 years ago

0.0.19

5 years ago

0.0.18

5 years ago

0.0.16

5 years ago

0.0.17

5 years ago

0.0.15

5 years ago

0.0.10

5 years ago

0.0.11

5 years ago

0.0.12

5 years ago

0.0.13

5 years ago

0.0.14

5 years ago

0.0.9

5 years ago

0.0.8

5 years ago

0.0.7

5 years ago

0.0.6

5 years ago

0.0.5

5 years ago

0.0.4

5 years ago

0.0.3

5 years ago

0.0.2

5 years ago

0.0.1

5 years ago