Skip to content
This repository was archived by the owner on Feb 2, 2018. It is now read-only.

Commit ce16d6a

Browse files
committed
feat: add a basic decorator
Implement a `@txIdFromHeader()` decorator that can annotate a controller operation to receive the value of `X-Trasaction-Id` Header.
1 parent 6e59627 commit ce16d6a

File tree

8 files changed

+129
-14
lines changed

8 files changed

+129
-14
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"tslint:fix": "npm run lint -- --fix",
2222
"prepublish": "npm run build",
2323
"pretest": "npm run clean && npm run build",
24-
"test": "mocha",
24+
"test": "/bin/bash -c '[[ $(node -v) =~ [[:digit:]]+ ]] && [[ ${BASH_REMATCH[0]} -gt 6 ]]' && mocha dist/test || mocha dist6/test",
2525
"posttest": "npm run lint",
2626
"test:dev": "mocha && npm run lint"
2727
},

src/decorators/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Decorators
2+
3+
## Overview
4+
5+
Decorators provide annotations for class methods and arguments. Decorators use the form `@decorator` where `decorator` is the name of the function that will be called at runtime.
6+
7+
## Basic Usage
8+
9+
### txIdFromHeader
10+
11+
This simple decorator allows you to annotate a `Controller` method argument. The decorator will annotate the method argument with the value of the header `X-Transaction-Id` from the request.
12+
13+
**Example**
14+
```
15+
class MyController {
16+
@get('/')
17+
getHandler(@txIdFromHeader() txId: string) {
18+
return `Your transaction id is: ${txId}`;
19+
}
20+
}
21+
```
22+
23+
## Related Resources
24+
25+
You can check out the following resource to learn more about decorators and how they are used in LoopBack Next.
26+
27+
- [TypeScript Handbook: Decorators](https://www.typescriptlang.org/docs/handbook/decorators.html)
28+
- [Decorators in LoopBack](http://loopback.io/doc/en/lb4/Decorators.html)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright IBM Corp. 2017. All Rights Reserved.
2+
// Node module: loopback-next-extension-starter
3+
// This file is licensed under the MIT License.
4+
// License text available at https://opensource.org/licenses/MIT
5+
6+
import {param} from '@loopback/rest';
7+
8+
/**
9+
* Decorator to inject the current transaction-id from a request's
10+
* 'X-Transaction-Id' header into the decorated function.
11+
*/
12+
export function txIdFromHeader() {
13+
return param.header.string('X-Transaction-Id');
14+
}

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@
22
// Node module: loopback-next-extension-starter
33
// This file is licensed under the MIT License.
44
// License text available at https://opensource.org/licenses/MIT
5+
6+
export * from './decorators/txIdFromHeader.decorator';
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright IBM Corp. 2017. All Rights Reserved.
2+
// Node module: loopback-next-hello-extension
3+
// This file is licensed under the MIT License.
4+
// License text available at https://opensource.org/licenses/MIT
5+
6+
import {Application} from '@loopback/core';
7+
import {get, RestComponent, RestServer} from '@loopback/rest';
8+
import {txIdFromHeader} from '../../..';
9+
import {Client, createClientForHandler} from '@loopback/testlab';
10+
11+
describe('@txIdFromHeader() (acceptance)', () => {
12+
let app: Application;
13+
let server: RestServer;
14+
15+
beforeEach(createApp);
16+
beforeEach(createController);
17+
beforeEach(getServerFromApp);
18+
19+
it('works with header set', async () => {
20+
const client: Client = createClientForHandler(server.handleHttp);
21+
22+
await client
23+
.get('/')
24+
.set('X-Transaction-Id', 'testid123')
25+
.expect(200, 'Your id is testid123');
26+
});
27+
28+
it('works without header', async () => {
29+
const client: Client = createClientForHandler(server.handleHttp);
30+
31+
await client.get('/').expect(200, 'Your id is undefined');
32+
});
33+
34+
async function createApp() {
35+
app = new Application({
36+
components: [RestComponent],
37+
rest: {
38+
port: 3000,
39+
},
40+
});
41+
}
42+
43+
function createController() {
44+
class MyController {
45+
@get('/')
46+
test(@txIdFromHeader() txId: string) {
47+
return `Your id is ${txId}`;
48+
}
49+
}
50+
51+
app.controller(MyController);
52+
}
53+
54+
async function getServerFromApp() {
55+
server = await app.getServer(RestServer);
56+
}
57+
});

test/mocha.opts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
--recursive
22
--reporter dot
3-
dist/test

test/smoke.test.ts

Lines changed: 0 additions & 12 deletions
This file was deleted.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright IBM Corp. 2017. All Rights Reserved.
2+
// Node module: loopback-next-hello-extension
3+
// This file is licensed under the MIT License.
4+
// License text available at https://opensource.org/licenses/MIT
5+
6+
import {expect} from '@loopback/testlab';
7+
import {get, getControllerSpec} from '@loopback/rest';
8+
import {txIdFromHeader} from '../../..';
9+
10+
describe('@txHeaderFromId() (unit)', () => {
11+
it('defines a parameter for X-Transaction-Id', () => {
12+
class MyController {
13+
@get('/')
14+
hello(@txIdFromHeader() txId: string) {}
15+
}
16+
17+
const actualSpec = getControllerSpec(MyController);
18+
19+
expect(actualSpec.paths['/']['get'].parameters).to.eql([
20+
{
21+
name: 'X-Transaction-Id',
22+
type: 'string',
23+
in: 'header',
24+
},
25+
]);
26+
});
27+
});

0 commit comments

Comments
 (0)