Skip to content

Commit 9b4bca1

Browse files
authored
Merge pull request #67 from zoltantarcsay/master
Allow passing in a custom logger
2 parents 191e9b7 + 77f1b03 commit 9b4bca1

File tree

5 files changed

+64
-16
lines changed

5 files changed

+64
-16
lines changed

README.md

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ So far there are the following decorators available:
3333
| @POST | Decorator that indicates a HTTP POST method.|
3434
| @PUT | Decorator that indicates a HTTP PUT method.|
3535
| @DELETE | Decorator that indicates a HTTP DELETE method.|
36-
| @PathParam | A method parameter may be decorated with the `@PathParam` decorator. The decorator reuquires a string parameter - the name of the parameter. The name must be present within the Path. For example `/books/:id`. One can access the id parameter parameter with `@PathParam('id')`|
36+
| @PathParam | A method parameter may be decorated with the `@PathParam` decorator. The decorator requires a string parameter - the name of the parameter. The name must be present within the Path. For example `/books/:id`. One can access the id parameter parameter with `@PathParam('id')`|
3737
| @HeaderParam | You can access the http header information in the same way as a path parameter. The difference is, that the value will be determined by a http header entry at runtime. For example if you want to access a token that is stored in the http header use: `@HeaderParam('token)`|
3838
| @QueryParam | If you want to access url query parameters from your service use this decorator. For example in a url like this: `/books?readed=true` you can use `@QueryParam('readed')`|
3939
| @Context (HttpRequest, HttpResponse) | Sometime it may be necessary to play around with the original HttpRequest or the HttpResponse. In this case you can use the `@Context` decorator. For Example `@Context(ContextTpyes.HttpRequest)`|
@@ -109,7 +109,7 @@ DELETE /books/1 -> true
109109

110110
## Supported Return Types
111111

112-
So far we have seen that all servcie methods are synchronous. You can return simple javascript types or complex objects.
112+
So far we have seen that all service methods are synchronous. You can return simple javascript types or complex objects.
113113
If you simply return a boolean, number, string these values will be returned as text/plain. null or undefined are
114114
returned as text/plain if no HttpResponse-object is injected in the service method (in this case you have full control what should be returned to the client).
115115
If you returns a complex object the result will be send as application/json.
@@ -132,7 +132,7 @@ class TestService {
132132
}
133133
```
134134
If you access the url '/' you will get `[{foo:'bar'}]` as the result. May be this is too much code for you - for me it is :smirk: .
135-
Keep in mind that there are a lot of node modules that already use promisses. For example mongoose. With this you service could be as short as:
135+
Keep in mind that there are a lot of node modules that already use promises. For example mongoose. With this you service could be as short as:
136136

137137
```TypeScript
138138
import {Path, GET, RolesAllowed} from 'js-restful';
@@ -152,7 +152,7 @@ export class UserService {
152152

153153
## Providing a ISecurityContextFactory
154154
If you decorate your service with `@RolesAllowed`, `@PermitAll` or you are using `@SecurityContext` as a parameter
155-
decorator you need to provide a `ISecurityContextFactory`. js-rstful-express need this factory to create a `ISecurityContext` to decide who is permitted to access
155+
decorator you need to provide a `ISecurityContextFactory`. js-restful-express need this factory to create a `ISecurityContext` to decide who is permitted to access
156156
the service or service method.
157157

158158
This Factory must be registered at the `ExpressServiceRegistry` before you register your service classes:
@@ -211,11 +211,27 @@ export default class User implements IUser {
211211
}
212212
```
213213

214+
## Passing in a custom logger instance
215+
js-restful-express uses [winston](https://github.com/winstonjs/winston) for logging. You can override the default logger by initializing the registry with a config object before registering any services:
216+
217+
```TypeScript
218+
import { ExpressServiceRegistry } from 'js-restful-express';
219+
import * as express from 'express';
220+
import { Logger, transports } from 'winston';
221+
222+
const app = express();
223+
const logger = new Logger({...});
224+
225+
ExpressServiceRegistry.initJsRestfulRegistry(app, {logger});
226+
ExpressServiceRegistry.registerService(app, {...});
227+
228+
```
229+
214230
## Advantages
215231
You may ask: what is the advantage of using decorators and TypeScript for your app? Here are some thoughts why it is useful:
216232

217233
- You may write less code you need to maintain and test.
218234
- You can refactor your code with minimal impact at other parts of your application. Just move or rename your service class will not break how your service may be accessed.
219235
- You can change who is allowed to access your service or service method without modifying your code. You just change the decorator.
220-
- You can test your services more easily - if you do not use HttpReqest or HttpResponse directly you don't need to mock these objects.
236+
- You can test your services more easily - if you do not use HttpRequest or HttpResponse directly you don't need to mock these objects.
221237
- May be you have a background in Java and know what [JAX-RS](https://jax-rs-spec.java.net) is. In this case you will be familiar with this approach.

src/express/registry.spec.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { JsRestfulRegistry } from './registry';
22
import * as express from 'express';
33
import {expect} from 'chai';
44
import { PermitAll } from 'js-restful';
5+
import * as winston from 'winston';
56
import { Factory } from './test-util.spec';
67

78
class TestServiceC {
@@ -61,7 +62,7 @@ describe('service-registry', () => {
6162

6263
expect(fn).to.throw(Error);
6364
})
64-
65+
6566
it('should be possible to register a service with sec context if a factory is registered', ()=>{
6667

6768
var fn = () => {
@@ -72,4 +73,21 @@ describe('service-registry', () => {
7273

7374
expect(fn).to.not.throw(Error);
7475
})
76+
77+
it('should be possible to set a custom logger', () => {
78+
class SpyLogger extends winston.Logger {
79+
called = false;
80+
log = () => {
81+
this.called = true;
82+
return this;
83+
}
84+
}
85+
86+
const logger = new SpyLogger();
87+
const registry = new JsRestfulRegistry(app, { logger: logger });
88+
89+
registry.registerService(new TestServiceC());
90+
91+
expect(logger.called).to.be.true;
92+
});
7593
});

src/express/registry.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,20 @@ import * as winston from 'winston';
66
import * as namings from './namings';
77
import { ExpressContextType, ISecurityContextFactory } from './descriptions';
88

9+
export interface JsRestfulRegistryConfig {
10+
logger?: winston.Winston | winston.LoggerInstance;
11+
}
12+
913
export class JsRestfulRegistry {
1014

1115
private registeredServices:any[] = [];
1216
private securityContextFactory:ISecurityContextFactory = null;
1317

14-
constructor(private app:express.Application){}
18+
constructor(private app:express.Application, private config: JsRestfulRegistryConfig = {}){
19+
if (!config.logger) {
20+
config.logger = winston;
21+
}
22+
}
1523

1624
registerSecurityContextFactory(factory:ISecurityContextFactory){
1725
this.securityContextFactory = factory;
@@ -35,7 +43,7 @@ export class JsRestfulRegistry {
3543
}
3644
}
3745

38-
winston.log('info', `${service.constructor.name} will be registered`);
46+
this.config.logger.info(`${service.constructor.name} will be registered`);
3947
// store the service at the app
4048
this.registeredServices.push(service.constructor.name);
4149

@@ -48,7 +56,7 @@ export class JsRestfulRegistry {
4856

4957
let path = method.path ? method.path : '/';
5058

51-
winston.log('info', `register method ${method.methodName} for path ${path}`);
59+
this.config.logger.info(`register method ${method.methodName} for path ${path}`);
5260

5361
router[httpMethodName](path, (req: express.Request, res: express.Response, next: express.NextFunction) => {
5462
try{
@@ -106,7 +114,7 @@ export class JsRestfulRegistry {
106114

107115
let basePath = pathUtil.getPathFromString(descriptions.basePath);
108116
this.app.use(basePath, router);
109-
winston.log('info', `${service.constructor.name} published at ${basePath}`);
117+
this.config.logger.info(`${service.constructor.name} published at ${basePath}`);
110118
}
111119

112120
collectAndConvertArgs(req:express.Request, res: express.Response, next:express.NextFunction, service:Object, method:MethodDescription): any[]{

src/express/service-registry.spec.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ExpressServiceRegistry } from './service-registry';
2-
import { JsRestfulRegistry } from './registry';
2+
import { JsRestfulRegistryConfig } from './registry';
33
import * as express from 'express';
44
import {expect} from 'chai';
55
import { Factory } from './test-util.spec';
@@ -34,4 +34,10 @@ describe('service-registry', () => {
3434
expect(fn).to.not.throw(Error);
3535
})
3636

37+
it('should be possible to initialize the registry with a config object', () => {
38+
const config: JsRestfulRegistryConfig = {logger: null};
39+
ExpressServiceRegistry.initJsRestfulRegistry(app, config);
40+
expect(app.locals.jsResutfulRegistry.config).to.equal(config);
41+
});
42+
3743
});

src/express/service-registry.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
import * as express from "express";
2-
import { JsRestfulRegistry } from './registry';
2+
import { JsRestfulRegistry, JsRestfulRegistryConfig } from './registry';
33
import { ISecurityContext } from 'js-restful';
44
import { ISecurityContextFactory } from './descriptions';
55

66
export class ExpressServiceRegistry {
77

8-
private static initJsResutfulRegistry(app: express.Application){
9-
app.locals.jsResutfulRegistry = app.locals.jsResutfulRegistry || new JsRestfulRegistry(app);
8+
static initJsRestfulRegistry(app: express.Application, config?: JsRestfulRegistryConfig){
9+
app.locals.jsResutfulRegistry = app.locals.jsResutfulRegistry || new JsRestfulRegistry(app, config);
1010
}
1111

1212
static registerSecurityContextFactory(app: express.Application, factory:ISecurityContextFactory){
1313

14-
this.initJsResutfulRegistry(app);
14+
this.initJsRestfulRegistry(app);
1515

1616
app.locals.jsResutfulRegistry.registerSecurityContextFactory(factory);
1717
}
1818

1919
static registerService(app: express.Application, service:any){
2020

21-
this.initJsResutfulRegistry(app);
21+
this.initJsRestfulRegistry(app);
2222

2323
app.locals.jsResutfulRegistry.registerService(service);
2424
}

0 commit comments

Comments
 (0)