Skip to content

Commit 6e152da

Browse files
authored
Fix/controller no methods (#471)
* Fix getControllerMethodMetadata to return an empty array for undefined metadata * Adds test for handling controllers without methods and implements utility for retrieving controller method metadata * updated the changelog file
1 parent dd55abc commit 6e152da

File tree

4 files changed

+152
-6
lines changed

4 files changed

+152
-6
lines changed

CHANGELOG.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,48 +13,54 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313

1414
### Fixed
1515

16+
- Added explicit check for when both `genericMetadata` and `methodMetadata` are `undefined` in the `getControllerMethodMetadata` function, preventing potential errors when no metadata is available.
17+
1618
## [6.5.0]
1719

1820
### Added
1921

2022
### Changed
23+
2124
- Updated `BaseMiddleware.handler` to allow async handlers.
2225
- Updated `Middleware` to allow include any `ServiceIdentifier`.
2326
- Updated `JsonContent` with no generic.
2427

2528
### Fixed
29+
2630
- Updated `BaseController.ok` to no longer return `text/plain` responses when non string content is passed.
2731

2832
## [6.4.10]
2933

3034
### Fixed
31-
- Fixed `Controller` without wrong constraints (#417).
35+
36+
- Fixed `Controller` without wrong constraints (#417).
3237

3338
## [6.4.9]
3439

3540
### Fixed
36-
- Fixed wrong emited typescript delclaration files (#1668).
41+
42+
- Fixed wrong emited typescript delclaration files (#1668).
3743

3844
## [6.4.8]
3945

4046
### Fixed
4147

42-
- Fixed can't set headers after they are sent (#255 / #412).
48+
- Fixed can't set headers after they are sent (#255 / #412).
4349

4450
## [6.4.7]
4551

4652
### Fixed
4753

48-
- Updated `inversify` and `express` dependencies to be peer dependnecies as stated in the docs.
54+
- Updated `inversify` and `express` dependencies to be peer dependnecies as stated in the docs.
4955

5056
## [6.4.4]
5157

5258
### Added
5359

5460
### Changed
5561

56-
- Update dependencies (`minimist`, `json5`, `@babel/traverse`, `tough-cookie`, `ansi-regex`, `cookiejar`, `express`, `decode-uri-component`).
62+
- Update dependencies (`minimist`, `json5`, `@babel/traverse`, `tough-cookie`, `ansi-regex`, `cookiejar`, `express`, `decode-uri-component`).
5763

5864
### Fixed
5965

60-
- Change JsonContent to return object rather than string (#379 / #378).
66+
- Change JsonContent to return object rather than string (#379 / #378).

src/test/debug.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,28 @@ describe('Debug utils', () => {
134134
expect(routeInfo[0]?.endpoints[1]?.route).toBe('POST /api/order/');
135135
expect(routeInfo[0]?.endpoints[1]?.args).toBeUndefined();
136136
});
137+
138+
it('should handle controllers without methods', () => {
139+
const container: Container = new Container();
140+
141+
@controller('/api/empty')
142+
class EmptyController extends BaseHttpController {
143+
// empty Controller
144+
}
145+
146+
// eslint-disable-next-line @typescript-eslint/typedef
147+
const TYPES = {
148+
EmptyController: EmptyController.name,
149+
};
150+
151+
const server: InversifyExpressServer = new InversifyExpressServer(
152+
container,
153+
);
154+
server.build();
155+
156+
const routeInfo: RouteInfo[] = getRouteInfo(container);
157+
158+
expect(routeInfo[0]?.controller).toBe(TYPES.EmptyController);
159+
expect(routeInfo[0]?.endpoints).toEqual([]);
160+
});
137161
});

src/test/utils.test.ts

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/* eslint-disable @typescript-eslint/typedef */
2+
import { describe, expect, it } from '@jest/globals';
3+
4+
import { METADATA_KEY } from '../constants';
5+
import { getControllerMethodMetadata } from '../utils';
6+
7+
describe('Utils', () => {
8+
describe('getControllerMethodMetadata', () => {
9+
it('should return an empty array when controller has no methods', () => {
10+
class EmptyController {}
11+
12+
const result = getControllerMethodMetadata(EmptyController);
13+
14+
expect(result).toEqual([]);
15+
});
16+
17+
it('should return metadata from controller own methods', () => {
18+
class TestController {}
19+
const methodMetadata = [
20+
{
21+
key: 'get',
22+
method: 'testMethod',
23+
middleware: [],
24+
path: '/test',
25+
target: TestController,
26+
},
27+
];
28+
29+
Reflect.defineMetadata(
30+
METADATA_KEY.controllerMethod,
31+
methodMetadata,
32+
TestController,
33+
);
34+
35+
const result = getControllerMethodMetadata(TestController);
36+
37+
expect(result).toEqual(methodMetadata);
38+
});
39+
40+
it('should return metadata from inherited methods', () => {
41+
class BaseController {}
42+
class ChildController extends BaseController {}
43+
44+
const genericMetadata = [
45+
{
46+
key: 'get',
47+
method: 'baseMethod',
48+
middleware: [],
49+
path: '/base',
50+
target: BaseController,
51+
},
52+
];
53+
54+
Reflect.defineMetadata(
55+
METADATA_KEY.controllerMethod,
56+
genericMetadata,
57+
BaseController,
58+
);
59+
60+
const result = getControllerMethodMetadata(ChildController);
61+
62+
expect(result).toEqual(genericMetadata);
63+
});
64+
65+
it('should concatenate own and inherited metadata', () => {
66+
class BaseController {}
67+
class ChildController extends BaseController {}
68+
69+
const ownMetadata = [
70+
{
71+
key: 'post',
72+
method: 'childMethod',
73+
middleware: [],
74+
path: '/child',
75+
target: ChildController,
76+
},
77+
];
78+
79+
const genericMetadata = [
80+
{
81+
key: 'get',
82+
method: 'baseMethod',
83+
middleware: [],
84+
path: '/base',
85+
target: BaseController,
86+
},
87+
];
88+
89+
Reflect.defineMetadata(
90+
METADATA_KEY.controllerMethod,
91+
ownMetadata,
92+
ChildController,
93+
);
94+
95+
Reflect.defineMetadata(
96+
METADATA_KEY.controllerMethod,
97+
genericMetadata,
98+
BaseController,
99+
);
100+
101+
const result = getControllerMethodMetadata(ChildController);
102+
103+
expect(result).toEqual([...ownMetadata, ...genericMetadata]);
104+
});
105+
106+
it('should handle undefined metadata correctly', () => {
107+
class TestController {}
108+
const result = getControllerMethodMetadata(TestController);
109+
expect(result).toEqual([]);
110+
});
111+
});
112+
});

src/utils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ export function getControllerMethodMetadata(
7171
Reflect.getPrototypeOf(constructor) as NewableFunction,
7272
) as ControllerMethodMetadata[];
7373

74+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
75+
if (genericMetadata === undefined && methodMetadata === undefined) {
76+
return [];
77+
}
7478
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
7579
if (genericMetadata !== undefined && methodMetadata !== undefined) {
7680
return methodMetadata.concat(genericMetadata);

0 commit comments

Comments
 (0)