Skip to content
This repository has been archived by the owner on May 8, 2020. It is now read-only.

Commit

Permalink
feat(middleware): Add documentation for middleware feature
Browse files Browse the repository at this point in the history
  • Loading branch information
zakhenry committed Jun 15, 2016
1 parent 9b17d1f commit 133cc7b
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 4 deletions.
Binary file added docs/assets/image/ubiquits-cli.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions docs/guide/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ collectionSort: 1
layout: guide.hbs
---

![CLI Screenshot](/assets/image/ubiquits-cli.png)

## Installation
To install the cli if you haven't done so in the [quickstart](/guide/quick-start), run the following:

Expand Down
91 changes: 90 additions & 1 deletion docs/guide/middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,94 @@ date: 2016-06-09
collection: guide
collectionSort: 1
layout: guide.hbs
pendingTask: true
---

Middleware are blocks of code that are executed before or after the main controller method is run. They take the
same arguments and return type as a controller route method, and are applied in order with each middleware
passing it's `Response` to the next in the stack.

The implementation is such that there is actually no difference between a middleware and a controller method - they all are
items in the call stack, the only difference being that the controller method is executed in the context of the controller
and so has access to all services injected by that controller.

## Usage
Middleware are applied with the method decorators `@Before(...middlewareFactories)` and `@After(...middlewareFactories)`.

### Order
Middleware is applied in left to right order of the decorator params.
For example:
```typescript
@Action('GET', '/example')
@Before(debugLog('Middleware ran 1'), debugLog('Middleware ran 2'))
@After(debugLog('Middleware ran 3'))
public exampleMethod(request: Request, response: Response): Response {
this.logger.info('Method ran');
return response.data('banana');
}
```
A `GET` request for the route will result in the following log
```
[server] [17:39:33] [Log middleware] Middleware ran 1
[server] [17:39:33] [Log middleware] Middleware ran 2
[server] [17:39:33] [controller] Method ran
[server] [17:39:33] [Log middleware] Middleware ran 3
```

## Registration
There are two types of middleware - isolated functions and injectable classes. Their usage is the same, but their registration differs.
The isolated functions are the simplest type; they just take a `Request` and `Response` object and return a `Response` or `Promise<Response>`.

Injectable class middleware are significantly more complex, but they gain the advantage of being able to use injected dependencies
and be substituted with other implementations with the dependency injector.

### Isolated function Middleware
If a middleware has simple requirements like basic request or response manipulation, a simple middlware factory is sufficient.

Here is an example of a basic middleware that defines a header to copy from the request to the response:
```typescript
function forwardHeader(headerName: string): IsolatedMiddlewareFactory {
return () => (request: Request, response: Response): Response => {
response.header(headerName, request.headers().get(headerName));
return response;
}
}
```

### `@Injectable` class Middleware
For more advanced Middleware that need to interact with other services a more complex pattern is available to use classes
that have injectable dependencies.

Here is an example of a middleware that is defined by a class that is `@Injectable()`
```typescript

export function authorize(claim:string): InjectableMiddlewareFactory {

return (injector: ReflectiveInjector): Middleware =>
injector.get(AuthorizationMiddleware).middlewareFactory();

}

@Injectable()
export class AuthorizationMiddleware implements InjectableMiddleware {

constructor(protected auth: Authorizor) {
}

public middlewareFactory(claim:string): Middleware {

return (request: Request, response: Response): Response => {
if (!this.auth.check(request, claim)) {
throw new UnauthorizedException('Forbidden');
}
return response;
}
}
}

```
Note that the `authorize` function returns a closure that takes a `ReflectiveInjector` param. The injector is passed
in when the middleware is registered from the route. This is handled within the `registerRoutes()` method of the `AbstractController`.

In future there may be a cleaner way of registering functions within decorators by retrieving the `injector` outside of class instances.
This is a [recognised issue](https://github.com/angular/angular/issues/4112) in the angular core, so once that is resolved this API may simplify.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@
"zone.js": "^0.6.12"
},
"devDependencies": {
"@ubiquits/toolchain": "^0.1.17"
"@ubiquits/toolchain": "^0.1.18"
},
"directories": {
"doc": "docs"
}
}
}
3 changes: 2 additions & 1 deletion src/server/middleware/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { ReflectiveInjector } from '@angular/core';
import { Response } from '../controllers/response';
import { Request } from '../controllers/request';

export interface Middleware {
(request: any, response: any): Response | Promise<Response>;
(request: Request, response: Response): Response | Promise<Response>;
}

export interface InjectableMiddleware {
Expand Down

0 comments on commit 133cc7b

Please sign in to comment.