# katrine

> Light weight framework for microservices

Latest version **1.4.4** (published 2019-05-21) · ISC license · 0 weekly downloads

## Install

```sh
npm install katrine
pnpm add katrine
yarn add katrine
bun add katrine
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 1.4.4 |
| Published | 2019-05-21 |
| First published | 2018-07-22 |
| Weekly downloads | 0 |
| License | ISC |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 7 |
| Unpacked size | 33.7 KB |
| Known vulnerabilities | 0 (+2 in 1 direct dependencies) |
| Install scripts | no |
| Author | Alex Baranezky |
| Maintainers | asterai.com |
| Keywords | web, mcv, framework, kate, typescript |

## Links

- npm: https://www.npmjs.com/package/katrine
- npm.io page: https://npm.io/package/katrine

## Dependencies (7)

- [pug](https://npm.io/package/pug.md) ^2.0.3
- [express](https://npm.io/package/express.md) ^4.16.3
- [typescript](https://npm.io/package/typescript.md) ^3.3.3
- [@types/node](https://npm.io/package/@types/node.md) 9.6.7
- [body-parser](https://npm.io/package/body-parser.md) ^1.18.3
- [express-session](https://npm.io/package/express-session.md) ^1.15.6
- [reflect-metadata](https://npm.io/package/reflect-metadata.md) ^0.1.12

## Alternatives

- [@opentelemetry/exporter-zipkin](https://npm.io/package/@opentelemetry/exporter-zipkin.md) — 14.8M weekly downloads
- [pusher-js](https://npm.io/package/pusher-js.md) — 2.0M weekly downloads
- [browserify](https://npm.io/package/browserify.md) — 1.7M weekly downloads
- [sqs-consumer](https://npm.io/package/sqs-consumer.md) — 1.7M weekly downloads
- [@sanity/eventsource](https://npm.io/package/@sanity/eventsource.md) — 930.8K weekly downloads

## Recent versions

- 1.4.4 (latest) — 2019-05-21
- 1.4.3 — 2019-04-23
- 1.4.2 — 2019-04-23
- 1.4.0 — 2019-04-23
- 1.3.2 — 2019-04-19
- 1.3.1 — 2019-04-19
- 1.3.0 — 2019-04-18
- 1.2.2 — 2019-04-13
- 1.2.1 — 2019-03-18
- 1.2.0 — 2019-03-17
- 1.1.9 — 2019-03-15
- 1.1.8 — 2018-09-23
- 1.1.7 — 2018-09-22
- 1.1.6 — 2018-09-22
- 1.1.5 — 2018-09-22
- … 6 more at https://npm.io/package/katrine/versions

## README

# Typescript based node.js framework
For development lightweight server apps.


## Table of Contents
* [Related links](#related-links)
* [Documentation](#documentation)
    * [Installation](#installation)
    * [Bootstrap Katrine](#bootstrap-katrine)
    * [Controllers and actions](#controllers-and-actions)
    * [View](#view)
    * [Login or logout user](#login-or-logout-user)
    * [Access control](#access-control)

### Related links
* Boilerplate project https://github.com/AsterAInpm/katrine-hello-world/
* Github project https://github.com/AsterAInpm/katrine
* npmjs.org https://www.npmjs.com/package/katrine


## Documentation

### Installation 
Add following dependencies, in your project
```json 
  "dependencies": {
    "@types/node": "9.6.7",
    "katrine": "^1.4.2",
    "typescript": "^3.3.3"
  }
``` 

### Bootstrap Katrine
To start app you need just 2 necessary actions:
  1. Load atleast one valid Katrine controller with valid action
  2. Run the app

```typescript

import { KatrineApp } from 'katrine';

/**
 * Katrine requires directories by absolute path or relative path
 * if dir path start with '.' (dot) Katrine will require relatively
 * Else Katrine will require dirs by absolute path
 *
 * Any controllers must be annotated by @controller decorator
 */
KatrineApp.loadControllers([
  './controller/IndexController',
  './controller/UserController',
  './controller/AdminController',
]);

// public folder optionally 
KatrineApp.setPublicFolder('public'); // express.js compatible public folder

// run with default settings
KatrineApp.run({});

```
### Controllers and actions

To define controller use a `@controller` decorator. Framework will require the file. When you call 
```typescript KatrineApp.loadControllers ``` and if class has `@controller` decorator Katrine will recognize class 
as actions holder. 

`KatrineController` is userfull class that contains few methods of rendering. And you will be able to render content by 
different methods. `KatrineController` is unnecessary, but strongly recommended for using. 
Also without `KatrineController` you could't use internal pug rendering system ([View component](#view))
 
```typescript

import { KatrineController, controller } from 'katrine';

@controller
export default class IndexController extends KatrineController {
  
}

```
#### Actions

`@action` annotation receives 2 params 
  1. route: `string`, express.js compatible route
  2. requestType: `HTTPRequestType`, POST or GET type
  
Actions can return `Promise` or `string` as result.
 
```typescript
import { KatrineController, controller, action, HTTPRequestType } from 'katrine';

@controller
export default class SomeController extends KatrineController {
      
    @action('/api/v1/*/delete', HTTPRequestType.POST)
    delete(req): string {
      const id = req.body.id;
      return JSON.stringify({
        status: 'success',
        data: id
      });    
    }
    
    // example of async action
    @action('/user/random')
    async getRandomUserAction(req): Promise<any> {
      const userData = await User.findRandomUser();
      return JSON.stringify({
        status: 'success',
        userId: userData.id
      });
    }
}
``` 


### View

Framework uses  [pug](https://pugjs.org/api/getting-started.html) as template engine. All render methods gathered in 
`KatrineController` 
```typescript
    // Pug file. Which you prefer to use when method render is called 
    protected getLayout(): string;
    
    // renders pug file with layout `getLayout()` 
    protected render(viewPath: any, params?: {}): any;
    
    // renders plain string. Method usefull when you don't need to use separete pug template for action 
    protected renderString(content: string, params?: {}): any;
    
    // renders particular pug template in particular layout
    protected renderLyout(viewPath: string, layoutPath: string, params: any): any;
```

Example of real controller. 

```typescript
import { action, KatrineController, controller } from 'katrine';

@controller
export default class IndexController extends KatrineController {

  /**
   *  Method used by KatrineController to define layout for any render* methods. 
   */
  getLayout() : string {
    return './view/layout/main.pug';
  }

  @action('/') // express compatible route
  homePageIndexAction(req): string {
    return this.render('./view/actions/index.pug', {});
  }


  @action('404') // Will call this action when route doesn't match on any valid actions
  pageNotFound(req): string {
    return this.render('./view/system/404.pug',{});
  }

  @action('403') // Will call this action when RBAC system rejects request by access rules. 
  accessDenied(req): string {
    return this.render('./view/system/403.pug',{});
  }
}

```

### Login or logout user

There are 2 methods to login and logout user. 

```typescript
  KatrineApp.auth(requestSession);
  KatrineApp.authLogoutUser(requestSession);
```

Full example of posible UserController within your app.
 
```typescript

@controller
export default class UserController extends KatrineController {
  private createUser(userData) : UserInterface {
    const user = new UserObject(userData.id, userData.role, userData);
    user.setSigned();

    return user;
  }
  
  @accessByAuth(AuthStatus.NOT_LOGGED_IN)
  @action('/user/login', HTTPRequestType.POST)
  async loginUserAction(req) {
    const email = req.body.email;
    const password = req.body.password;

    try {
      const userData = await User.findByEmailAndPassword(email, password);

      if (userData) {
        const userObject = this.createUser(userData);
        KatrineApp.auth(req.session, userObject);
      } else {
        throw 'User Email or password incorrect';
      }

      return JSON.stringify({
        status: 'success',
        messsage: '',
        data: {
          role: userData.role,
          id: userData.id
        }
      });
    } catch (e) {

      console.error(e);

      return JSON.stringify({
        status: 'error',
        message: typeof e === 'string' ? e : 'User Email or password incorrect'
      })
    }

  }

  @accessByAuth(AuthStatus.LOGGED_IN)
  @action('/user/logout')
  logOutAction(req): string {
    KatrineApp.authLogoutUser(req.session);
    
    return JSON.stringify({
      status : 'success'
    });
  }
}
```

### Access control

To restrict access to actions there are two decorators. Decorators works by OR logic
e.g: `if (!rule_1 || !rule_n) reject ...`, so you can combine them to make more complex logic of access control flow

```typescript
    // allows user to call action if his role equals `roles` param
    @accessByRole(roles: string | string[]) 
    
    // allows user to call action according to his Auth state `signed in / not signed in`
    @accessByAuth(auth: AuthStatus)
```

[Fill free to make issue reports, or request a features](https://github.com/AsterAInpm/katrine/issues)

My email [asterai.com@gmail.com](mailto:asterai.com@gmail.com)

Alex.

---
_Source: https://npm.io/package/katrine · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
