Skip to content

Commit daf2da8

Browse files
authored
Merge pull request #3 from mrdck/feature/di
Introduce dependency injection
2 parents c8bf150 + 9484a02 commit daf2da8

File tree

13 files changed

+114
-7
lines changed

13 files changed

+114
-7
lines changed

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- [Lint](#lint)
99
- [Deployment](#deployment)
1010
- [Project Structure](#project-structure)
11+
- [Dependency Injection (IoC)](#dependency-injection-ioc)
1112
- [License](#license)
1213

1314
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
@@ -88,5 +89,29 @@ yarn deploy
8889
├── tsconfig.json
8990
└── yarn.lock
9091
```
92+
93+
### Dependency Injection (IoC)
94+
Following template leverage Dependency Injection on inversify package that introduces Inversion of Control container.
95+
In `src/common/container` there is container component that serve purpose of Root Composite that hooks and instantiate all dependencies with container.
96+
97+
This approach allow easy access on handler level
98+
```typescript
99+
// container with dependencies is available in context
100+
export async function handler(_: APIGatewayProxyEvent, { container }: Context): Promise<APIGatewayProxyResult> {
101+
// get dependency bound to container
102+
const config = container.get<Config>(Config)
103+
104+
if (config.foo) {
105+
// some foo logic
106+
}
107+
108+
return response(StatusCodes.OK, ReasonPhrases.OK)
109+
}
110+
111+
// handler needs to be decorated with middleware otherwise container is not bound
112+
export const health = middleware(handler)
113+
```
114+
115+
91116
## License
92117
MIT

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"aws-lambda": "^1.0.6",
2525
"doctoc": "^2.1.0",
2626
"dotenv": "^14.2.0",
27+
"env-var": "^7.1.1",
2728
"eslint": "^7.32.0",
2829
"eslint-config-standard": "^16.0.3",
2930
"eslint-plugin-import": "^2.25.2",
@@ -32,8 +33,10 @@
3233
"eslint-plugin-standard": "^5.0.0",
3334
"http-status-codes": "^2.1.4",
3435
"husky": "^7.0.4",
36+
"inversify": "^6.0.1",
3537
"jest": "^27.3.1",
3638
"lint-staged": "^11.2.4",
39+
"reflect-metadata": "^0.1.13",
3740
"serverless": "^2.64.1",
3841
"serverless-bundle": "^5.0.2",
3942
"serverless-jest-plugin": "^0.4.0",

src/common/config.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import * as env from 'env-var'
2+
import { ContainerModule } from 'inversify'
3+
4+
export interface Config {
5+
foo: string
6+
}
7+
8+
export const Config = Symbol('Config')
9+
10+
const resolve = (): Config => ({
11+
foo: env.get('NODE_ENV').default('testing').asString(),
12+
})
13+
14+
export default new ContainerModule(bind => {
15+
bind<Config>(Config).toConstantValue(resolve())
16+
})

src/common/container.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import 'reflect-metadata'
2+
3+
import { Container } from 'inversify'
4+
5+
import config from './config'
6+
7+
/**
8+
* Root Composite component that instantiate and hooks Inversion of Control container
9+
*/
10+
export const compositeRoot = () => {
11+
const container = new Container()
12+
13+
container.load(config)
14+
15+
return container
16+
}
17+
18+
export const container = compositeRoot()
File renamed without changes.

src/common/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export * from './middleware'
2+
export * from './http'
3+
export * from './container'
4+
export * from './config'
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import errorHandler from '@middy/http-error-handler'
44

55
import type { Handler } from 'aws-lambda'
66

7+
import { container } from './container'
8+
79
/**
810
* No Operation logger
911
*/
@@ -16,4 +18,8 @@ export const middleware = <Event, Context>(handler: Handler<Event, Context>) =>
1618
return middy(handler)
1719
.use(bodyParser())
1820
.use(errorHandler({ logger: nullLogger }))
21+
.before(request => {
22+
// decorate context with container
23+
Reflect.set(request.context, 'container', container)
24+
})
1925
}

src/foo.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ import validator from '@middy/validator'
33
import type { APIGatewayProxyResult, APIGatewayProxyEvent } from 'aws-lambda'
44
import { StatusCodes } from 'http-status-codes'
55

6-
import { response } from './common'
7-
import { middleware } from './middleware'
6+
import { response, middleware } from './common'
87

98
const schema = {
109
type: 'object',

src/health.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
1-
import type { APIGatewayProxyResult } from 'aws-lambda'
1+
import type { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda'
22
import { StatusCodes, ReasonPhrases } from 'http-status-codes'
33

4-
import { response } from './common'
4+
import { response, Config, middleware } from './common'
5+
6+
export async function handler(_: APIGatewayProxyEvent, { container }: Context): Promise<APIGatewayProxyResult> {
7+
const config = container.get<Config>(Config)
8+
9+
/**
10+
* This code below serve example purpose for getting values out of container
11+
*/
12+
if (config.foo) {
13+
console.log('foo')
14+
}
515

6-
export async function health(): Promise<APIGatewayProxyResult> {
716
return response(StatusCodes.OK, ReasonPhrases.OK)
817
}
18+
19+
export const health = middleware(handler)

src/types/lamdba.d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import 'typesafe-api-gateway'
2+
3+
import { interfaces } from 'inversify'
4+
5+
declare module 'aws-lambda' {
6+
interface Context extends LambdaContext {
7+
container: interfaces.Container
8+
}
9+
}

0 commit comments

Comments
 (0)