# Eazy package
*Eazy package is supposed to be used easily. It provides some frames to do tasks in server side, for example: api endpoint input validation, Email service, Logsystem, Database connector, Html generator with ejs,  custom routing, property validator*

---
### Logger
*This class is used to create logs to the console, furthermore it can be set up to send email on error.*

Example:
```typescript
Logger.error( 'Error message!', 'Err_code', true); // last parameter is optional. if it set to true, empty lines will appear before and after the message. default=false
Logger.warning("Warning message!",true);
Logger.info('Info message!');
Logger.trace("Trace message!");      
Logger.success("Task successfully completed!");
```

Logging to console can be disabled via
```typescript
Logger.writeconsole = false;
```

Sending email message on error can be enabled by
```typescript
Logger.sendmail = true;
```

A callback can be attached in case of error. So if you want to implement a different email system or send an http request you can do so.
```typescript
Logger.errorCallbackFunction = myFunction;
```

Log level can be set via
```typescript
Logger.level=Loglevel.trace;

...

export enum LogLevel {
  none = 0,
  error = 1,
  warning = 2,
  info = 3,
  trace = 4,
}

```
---

## How to use the api endpoint input validation feature?

First of all, you should create fields which implement the `IField` interface
e.g.:
```typescript
export class DateField implements IField{

   public type: FieldType = FieldType.date;
   public min: Date;
   public max: Date;
   public validators: Validator[] = [];

   constructor(public name: string, public optional : boolean = false) {
      this.min = new Date('1900/01/01');
      this.max = new Date('2100/01/01');
      this.validators = [DefaultValidators.basicDateFormat];
   }
}
```

*- Tip: It is a good practice to let the name property to be changed dinamically, because you might want to use 2 DateField as input in 1 endpoint*
*- Tip: It is a good practice to let the optional property to be changed dinamically, because you might want to reuse the DateField in different models*

After that you should define a model which describes an endpoint. eg.:
```typescript
export class EndpointModel implements IModel {

    fromDate : IField = new DateField('from');
    toDate : IField = new DateField('to');

    groups: IField[][] = [];
    public interfaceHelpMessage = () : string => {
        return 'Test interface : 2 field is required. to and from Date field.';
    }

    constructor(){
        this.groups= [
            [this.fromDate,this.toDate],
        ]
    }
}
```
*As you can see, Models should implements `IModel` interface!*
*`interfaceHelpMessage()` should be described correctly, because it is useful when debugging is enabled.*
<b style="color:red; font-size: 2em;">!!! </b>`groups` should be assigned!

 In the example above, `fromDate` and `toDate` always have to be present when you request this endpoint! If you want to make `fromDate` optional you should set the optional flag:
```typescript
export class EndpointModel implements IModel {

    fromDate : IField = new DateField('from', true);
    // ...
}
```
**In the groups you always declare what is a valid request made of!**

Now you have the fields and an endpoint model now it's time connect it with a `Controller` e.g.:

```typescript
export class TestController extends Controller {
    
    constructor(){
        super();
        this.registerRequestValidator({get: new EndpointModel()}, true);
    }

    async get(req: Request, res: Response): Promise<void> {
      throw new Error("Method not implemented.");
   }

   async post(req: Request, res: Response): Promise<void> {
      throw new Error("Method not implemented.");
   }

   async patch(req: Request, res: Response): Promise<void> {
      throw new Error("Method not implemented.");
   }

   async put(req: Request, res: Response): Promise<void> {
      throw new Error("Method not implemented.");
   }

   async delete(req: Request, res: Response): Promise<void> {
      throw new Error("Method not implemented.");
   }
}
```
Your controller should extends `Controller` class, in this way you can use your Models in the controller.
```typescript
this.registerRequestValidator({get: new EndpointModel()}, true);
```
This function register your Model to the Controller. `registerRequestValidator(...)` requires 1 parameter (and 1 optional):
The first parameter should be an object of `IValidators` interface which looks like this:
```typescript
export interface IValidators {
  get?: IModel;
  patch?: IModel;
  post?: IModel;
  put?: IModel;
  delete?: IModel;
}
``` 
The optional paramęter `helpMessage` should be used only in development phase. It returns an http site with useful, detailed information, if model validation fails. In this way, you can debug your endpoint easily.


As you can see, you can either use one `IModel` with different groups for all method or you can declare different `IModel` for different method. It's up to you.

---
## Guard
Another great security feature to use. For example, you can create a `Guard` for your protected endpoint, in this way you check permissions, rights, users, whatever you want... Guards have to extend the `Guard` baseclass.
e.g.:
```typescript
export class MyGuard extends Guard{
    protected checkGet(req: Request, res: Response): boolean {
        res.status(HttpCodes.forbidden).send();
        return false;
    }
    protected checkPost(req: Request, res: Response): boolean {
        return true;
    }
    protected checkPatch(req: Request, res: Response): boolean {
        return true;
    }
    protected checkDelete(req: Request, res: Response): boolean {
        return true;
    }
    protected checkPut(req: Request, res: Response): boolean {
        return true;
    }
}
```
*You can use the `HttpCodes` enum to get the proper http status code.*

**- Please note:** If your check functions return true, then the `Guard` baseclass will call then `next()` function. If it returns false or does not return, then nothing happens. If your customGuard returns false, then you should send a response also. 

---
# Routing

Router handler is also available in order to register Guards and Model validation correctly. 
You should first create a Routes.ts file. e.g.:
```typescript
export class Routes {
    public static all : IRoute[] =
    [
        {path: '/test', guard: new MyGuard(), controller: new TestController()}
    ]
}
```
*guard is an optional paramter.*

After your routes are up, you should register them into the `express` app. e.g.:
```typescript
const app : Application = express();
app.use('/api',RoutesHandler.register(Routes.all));
```
---

*- Tip: You can use the `Logger.errorCallbackFunction(...)` which is called at the end of `Logger.error(...)`. In this way you can declare what should happen on error. E.g.:*

*You could send a custom email (via `EmailService.sendMail(...)`) generated by `HtmlGenerator`*

*You could save error message to a custom file*

*You can terminate the process*

*You can make an http call to a custom website*

---
## Validator
*`Validator`(please don't confuse with `IValidators`) Is used in `IField` interface, in order to create custom validators. E.g.: phone,mail,only letter and so on.*

You can create a `Validator` like
```typescript
new Validator(/^[A-Za-z]+$/, 'It must contains letters only.');
```
In the `DefaultValidators` class there are some validators provided already. I will add more in future.
```typescript
export class DefaultValidators {
  public static readonly containsNumber: Validator = new Validator(/\d+/, 'It must contains a digit.');
  public static readonly containsAlphabet: Validator = new Validator(/[a-zA-Z]/, 'It must contains an english letter.');

  public static readonly onlyLetters: Validator = new Validator(/^[A-Za-z]+$/, 'It must contains letters only.');
  public static readonly onlyNumbers: Validator = new Validator(/^[0-9]+$/, 'It must contains numbers only.');
  public static readonly onlyMixOfAlphaNumeric: Validator = new Validator(
    /^([a-zA-Z0-9])+$/,
    'It must be a mixture of english letters and digits!',
  );
  public static readonly basicDateFormat: Validator = new Validator(
    /^([0-9]){4}([-/]){1}[0-9]{2}([-/])[0-9]{2}/,
    'It must be a date formatted like YYYY-MM-DD or YYYY/MM/DD',
  );
}

```