npm package: @mbraun/koa-decorators
Description: Package for managing multiple routes on koa with a controller-structure
Author: Michael Braun
Latest version: 0.0.4

# koa-decorators

[![npm_version](https://img.shields.io/npm/v/@mbraun/koa-decorators.svg?style=flat-square)](https://www.npmjs.com/package/@mbraun/koa-decorators)
[![license](https://img.shields.io/npm/l/@mbraun/koa-decorators.svg?style=flat-square)](https://gitlab.com/michael-braun/npm/koa-decorators/blob/master/LICENSE)
![stability](https://img.shields.io/badge/stability-experimental-orange.svg?style=flat-square)
[![pipeline status](https://gitlab.com/michael-braun/npm/koa-decorators/badges/master/pipeline.svg)](https://gitlab.com/michael-braun/npm/koa-decorators/commits/master)
[![coverage report](https://gitlab.com/michael-braun/npm/koa-decorators/badges/master/coverage.svg)](https://gitlab.com/michael-braun/npm/koa-decorators/commits/master)

This package consists of decorator-functions that could
be used with [koajs](https://koajs.com/).

They are inspired by the [.NET WebApi attributes](https://docs.microsoft.com/de-de/aspnet/core/mvc/controllers/routing?view=aspnetcore-2.2#attribute-routing)
and should add routing information to a controller-class.

## Setup

To use this package you have to add support for stage-2 decorators to your preferred compiler.

When used with babeljs, use the [@babel/plugin-proposal-decorators](https://babeljs.io/docs/en/babel-plugin-proposal-decorators) plugin without ``legacy: true``.


## Getting Started

It is easy to create a controller with routes to an existing koajs-project:

### Create Controller

You have to create a Controller class first and add the decorators to it.

```javascript
import { Route, HttpGet } from '@mbraun/koa-decorators';

@Route('/examples')
class ExampleController {
    @HttpGet('/')
    static GetExamples(ctx) {
        ctx.body = 'Hello World';
        ctx.status = 200;

        return ctx;
    }
}
```

### Add Controller to Koa-Router

Then you have to connect it to a koa-router using the createRoutes function
of the koa-decorators package. 

```javascript
import Koa from 'koa';
import Router from 'koa-router';
import { createRoutes } from '@mbraun/koa-decorators';

const app = new Koa();
const router = new Router();

createRoutes(router, ExampleController);

app
  .use(router.routes())
  .use(router.allowedMethods());
```

## Decorators

This package consists of the following decorators:

| Name         | class | method |
| ------------ | ----- | ------ |
| Route        | x     | x      |
| AcceptVerbs  |       | x      |
| Http\<Verb\> |       | x      |
| Middleware   | x     | x      |

### Route
The Route-decorator could be used on class-level and method-level.
It is possible to set multiple Routes on the same element.

On class-level the decorator works as a prefix for each route that
is specified inside this class.

On method-level it has to be used with a AcceptVerbs or
Http\<Verb\>-decorator.

```javascript
import { AcceptVerbs, Route } from '@mbraun/koa-decorators';

@Route('/examples')
class ExampleController {
    @Route('/:id')
    static GetExampleById(ctx) {
        ctx.body = `Hello ${ctx.params.id}`;
        ctx.status = 200;

        return ctx;
    }
}
```

### AcceptVerbs

The AcceptVerbs-decorator could only be used on method-level.
It specifies the possible http-methods that could be handled by the route.

```javascript
import { AcceptVerbs } from '@mbraun/koa-decorators';

class ExampleController {
    @AcceptVerbs('GET', 'POST')
    static GetExampleById(ctx) {
        ctx.body = `Hello World!`;
        ctx.status = 200;

        return ctx;
    }
}
```

### Http\<Verb\>

Because most routes only work with one http-method and one route
this library contains shortcut-decorators too.

shortcut-decorators where created for the following http-methods:
- GET
- POST
- PUT
- PATCH
- DELETE

```javascript
import { HttpGet } from '@mbraun/koa-decorators';

class ExampleController {
    @HttpGet('/')
    static GetExampleById(ctx) {
        ctx.body = `Hello World!`;
        ctx.status = 200;

        return ctx;
    }
}
```

### Middleware

The middleware-decorator could be used on class-level and method-level.

It should be compatible with any existing middleware for koa.

On class-level, the middleware is used on any route inside this class.
On method-level, the middleware is only used on all routes that are
mapped to this method.

```javascript
import { Middleware } from '@mbraun/koa-decorators';

async function RequestTimeLogger(ctx, next) {
  const start = Date.now();
  await next();
  const ms = Date.now() - start;
  console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
}

class ExampleController {
    @Middleware(RequestTimeLogger)
    static GetExampleById(ctx) {
        // ...
    }
}
```

It is also possible to add multiple middlewares using only one
Middleware-decorator:

```javascript
import { Middleware } from '@mbraun/koa-decorators';

class ExampleController {
    @Middleware(Middleware1, Middleware2)
    static GetExampleById(ctx) {
        // ...
    }
}
```

### decorateMiddleware

The decorateMiddleware function creates a Middleware-Decorator with
a given middleware.
It could be used on a custom middleware that is required on multiple routes
across multiple controllers. It should make things a lot more easier:

__Middleware.js__
```javascript
import { decorateMiddleware } from '@mbraun/koa-decorators';

async function RequestTimeLogger(ctx, next) {
  const start = Date.now();
  await next();
  const ms = Date.now() - start;
  console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
}

export default decorateMiddleware(RequestTimeLogger);
```

__Controller.js__
```javascript
import RequestTimeLogger from './Middleware.js';

class ExampleController {
    @RequestTimeLogger
    static GetExampleById(ctx) {
        // ...
    }
}
```