Skip to content

Commit ac10229

Browse files
committed
fix: check injected request option types (#95)
1 parent 73028a1 commit ac10229

File tree

7 files changed

+47
-21
lines changed

7 files changed

+47
-21
lines changed

src/BaseService.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { Clock } from 'src/utils/Clock';
1414
import { JsonPath } from 'src/utils/JsonPath';
1515
import { dictToMap } from 'src/utils/Map';
1616
import { MathFactory } from 'src/utils/Math';
17+
import { RequestFactory } from 'src/utils/Request';
1718

1819
/**
1920
* TODO: these should be optional and must be included in the decorator to be available
@@ -24,6 +25,7 @@ export interface InjectedServiceOptions {
2425
logger: Logger;
2526
math: MathFactory;
2627
metrics: Registry;
28+
request: RequestFactory;
2729
schema: Schema;
2830
services: ServiceModule;
2931
}

src/controller/SearchController.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { Container, Inject } from 'noicejs';
1+
import { Inject } from 'noicejs';
22

33
import { BaseController } from 'src/controller/BaseController';
44
import { Controller, ControllerData, ControllerOptions } from 'src/controller/Controller';
55
import { Command } from 'src/entity/Command';
6+
import { RequestFactory } from 'src/utils/Request';
67
import { Template } from 'src/utils/Template';
78
import { TemplateCompiler } from 'src/utils/TemplateCompiler';
89

@@ -19,15 +20,16 @@ export interface SearchControllerOptions extends ControllerOptions<SearchControl
1920
compiler: TemplateCompiler;
2021
}
2122

22-
@Inject('compiler')
23+
export const NOUN_SEARCH = 'search';
24+
25+
@Inject('compiler', 'request')
2326
export class SearchController extends BaseController<SearchControllerData> implements Controller {
24-
protected container: Container;
25-
protected url: Template;
27+
protected readonly request: RequestFactory;
28+
protected readonly url: Template;
2629

2730
constructor(options: SearchControllerOptions) {
28-
super(options, 'isolex#/definitions/service-controller-search');
31+
super(options, 'isolex#/definitions/service-controller-search', [NOUN_SEARCH]);
2932

30-
this.container = options.container;
3133
this.url = options.compiler.compile(options.data.request.url);
3234
}
3335

@@ -40,7 +42,7 @@ export class SearchController extends BaseController<SearchControllerData> imple
4042
const requestUrl = this.url.render({ data });
4143
this.logger.debug({ requestUrl }, 'searching at url');
4244

43-
const response = await this.container.create<any, any>('request', {
45+
const response = await this.request.create({
4446
json: true,
4547
method: this.data.request.method,
4648
uri: requestUrl,

src/controller/WeatherController.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import { Container, Inject } from 'noicejs';
2-
import { BaseOptions } from 'noicejs/Container';
3-
import { CoreOptions, RequiredUriUrl } from 'request';
1+
import { Inject } from 'noicejs';
42

53
import { BaseController } from 'src/controller/BaseController';
64
import { Controller, ControllerData, ControllerOptions } from 'src/controller/Controller';
75
import { Command } from 'src/entity/Command';
6+
import { RequestFactory } from 'src/utils/Request';
87
import { TemplateCompiler } from 'src/utils/TemplateCompiler';
98

109
export interface WeatherControllerData extends ControllerData {
@@ -20,13 +19,14 @@ export interface WeatherControllerOptions extends ControllerOptions<WeatherContr
2019

2120
export const NOUN_WEATHER = 'weather';
2221

23-
@Inject('compiler')
22+
@Inject('compiler', 'request')
2423
export class WeatherController extends BaseController<WeatherControllerData> implements Controller {
25-
protected readonly container: Container;
24+
protected readonly request: RequestFactory;
2625

2726
constructor(options: WeatherControllerOptions) {
2827
super(options, 'isolex#/definitions/service-controller-weather', [NOUN_WEATHER]);
29-
this.container = options.container;
28+
29+
this.request = options.request;
3030
}
3131

3232
public async handle(cmd: Command): Promise<void> {
@@ -50,7 +50,7 @@ export class WeatherController extends BaseController<WeatherControllerData> imp
5050
this.logger.debug({ location, query, root: this.data.api.root }, 'requesting weather data from API');
5151

5252
try {
53-
return this.container.create<WeatherReply, BaseOptions & CoreOptions & RequiredUriUrl>('request', {
53+
return this.request.create({
5454
json: true,
5555
method: 'GET',
5656
qs: query,

src/module/BotModule.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { kebabCase } from 'lodash';
22
import { Container, Logger, Module, Provides } from 'noicejs';
33
import { ModuleOptions } from 'noicejs/Module';
44
import { Registry } from 'prom-client';
5-
import * as request from 'request-promise';
65
import { Connection } from 'typeorm';
76

87
import { Bot } from 'src/Bot';
@@ -11,6 +10,7 @@ import { GraphSchema } from 'src/schema/graph';
1110
import { Clock } from 'src/utils/Clock';
1211
import { JsonPath } from 'src/utils/JsonPath';
1312
import { MathFactory } from 'src/utils/Math';
13+
import { RequestFactory } from 'src/utils/Request';
1414
import { TemplateCompiler } from 'src/utils/TemplateCompiler';
1515

1616
export interface BotModuleOptions {
@@ -41,6 +41,7 @@ export class BotModule extends Module {
4141
this.bind(kebabCase(GraphSchema.name)).toConstructor(GraphSchema);
4242
this.bind('jsonpath').toConstructor(JsonPath);
4343
this.bind('math').toConstructor(MathFactory);
44+
this.bind('request').toConstructor(RequestFactory);
4445
}
4546

4647
public setBot(bot: Bot) {
@@ -71,9 +72,4 @@ export class BotModule extends Module {
7172
public async getStorage(): Promise<Connection> {
7273
return this.bot.getStorage();
7374
}
74-
75-
@Provides('request')
76-
public async createRequest(options: any): Promise<Request> {
77-
return request(options);
78-
}
7975
}

src/utils/Math.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ export function clamp(v: number, min: number, max: number) {
7777
return Math.max(Math.min(v, min), max);
7878
}
7979

80+
/**
81+
* Since each user needs to create a math environment with typed options, the container needs to inject an instance of
82+
* something (this).
83+
*/
8084
export class MathFactory {
8185
public create(options: mathjs.ConfigOptions): mathjs.MathJsStatic {
8286
return ((mathjs as unknown) as MathCreate).create(options); // thanks mathjs types

src/utils/Request.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import * as request from 'request';
2+
3+
export type RequestOptions = request.CoreOptions & request.UriOptions;
4+
5+
/**
6+
* Work around for the lack of existing create method (default export is the function).
7+
*
8+
* Since each user needs to create requests with typed options, the container needs to inject an instance of
9+
* something (this).
10+
*/
11+
export class RequestFactory {
12+
public create(options: RequestOptions): Promise<any> {
13+
return new Promise((res, rej) => {
14+
request(options, (error: Error, response: request.Response, body: unknown) => {
15+
res(body);
16+
});
17+
});
18+
}
19+
}

test/controller/TestWeatherController.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { Message } from 'src/entity/Message';
99
import { ServiceModule } from 'src/module/ServiceModule';
1010
import { TransformModule } from 'src/module/TransformModule';
1111
import { Transform } from 'src/transform/Transform';
12+
import { RequestFactory } from 'src/utils/Request';
1213
import { Template } from 'src/utils/Template';
1314
import { TemplateCompiler } from 'src/utils/TemplateCompiler';
1415

@@ -21,7 +22,9 @@ describeAsync('weather controller', async () => {
2122
const { container, module } = await createContainer(...modules);
2223

2324
const data = { test: 'test' };
24-
module.bind('request').toFactory(async () => data);
25+
module.bind('request').toInstance(ineeda<RequestFactory>({
26+
create: async () => data,
27+
}));
2528

2629
const sent: Array<Message> = [];
2730
const bot = ineeda<Bot>({

0 commit comments

Comments
 (0)