Skip to content

Commit 678781f

Browse files
committed
Switch to dependency injection framework
1 parent 089eec2 commit 678781f

File tree

11 files changed

+117
-90
lines changed

11 files changed

+117
-90
lines changed

lambdas/api-handler/src/config/__tests__/deps.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11

2+
import { MIRepository } from '../../../../../internal/datastore/src';
23
import type { Deps } from '../deps';
34

45
describe('createDependenciesContainer', () => {
@@ -24,6 +25,7 @@ describe('createDependenciesContainer', () => {
2425
// Repo client
2526
jest.mock('../../../../../internal/datastore', () => ({
2627
LetterRepository: jest.fn(),
28+
MIRepository: jest.fn(),
2729
}));
2830

2931
// Env

lambdas/api-handler/src/config/__tests__/env.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ describe('lambdaEnv', () => {
1616
process.env.SUPPLIER_ID_HEADER = 'x-supplier-id';
1717
process.env.APIM_CORRELATION_HEADER = 'x-correlation-id';
1818
process.env.LETTERS_TABLE_NAME = 'letters-table';
19+
process.env.MI_TABLE_NAME = 'mi-table';
1920
process.env.LETTER_TTL_HOURS = '24';
2021
process.env.DOWNLOAD_URL_TTL_SECONDS = '3600';
2122

@@ -25,6 +26,7 @@ describe('lambdaEnv', () => {
2526
SUPPLIER_ID_HEADER: 'x-supplier-id',
2627
APIM_CORRELATION_HEADER: 'x-correlation-id',
2728
LETTERS_TABLE_NAME: 'letters-table',
29+
MI_TABLE_NAME: 'mi-table',
2830
LETTER_TTL_HOURS: 24,
2931
DOWNLOAD_URL_TTL_SECONDS: 3600
3032
});
@@ -34,7 +36,7 @@ describe('lambdaEnv', () => {
3436
process.env.SUPPLIER_ID_HEADER = 'x-supplier-id';
3537
process.env.APIM_CORRELATION_HEADER = 'x-correlation-id';
3638
process.env.LETTERS_TABLE_NAME = undefined; // simulate missing var
37-
process.env.LETTER_TTL_HOURS = '24';
39+
process.env.MI_TABLE_NAME = 'mi-table'; process.env.LETTER_TTL_HOURS = '24';
3840
process.env.DOWNLOAD_URL_TTL_SECONDS = '3600';
3941

4042
expect(() => require('../env')).toThrow(ZodError);

lambdas/api-handler/src/config/deps.ts

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,23 @@ import { S3Client } from "@aws-sdk/client-s3";
22
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
33
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
44
import pino from 'pino';
5-
import { LetterRepository } from '../../../../internal/datastore';
5+
import { LetterRepository, MIRepository } from '../../../../internal/datastore';
66
import { envVars, EnvVars } from "../config/env";
77

88
export type Deps = {
99
s3Client: S3Client;
1010
letterRepo: LetterRepository;
11-
logger: pino.Logger,
11+
miRepo: MIRepository;
12+
logger: pino.Logger;
1213
env: EnvVars
1314
};
1415

15-
function createLetterRepository(log: pino.Logger, envVars: EnvVars): LetterRepository {
16+
function createDocumentClient(): DynamoDBDocumentClient {
17+
const ddbClient = new DynamoDBClient({});
18+
return DynamoDBDocumentClient.from(ddbClient);
19+
}
20+
21+
function createLetterRepository(documentClient: DynamoDBDocumentClient, log: pino.Logger, envVars: EnvVars): LetterRepository {
1622
const ddbClient = new DynamoDBClient({});
1723
const docClient = DynamoDBDocumentClient.from(ddbClient);
1824
const config = {
@@ -23,13 +29,26 @@ function createLetterRepository(log: pino.Logger, envVars: EnvVars): LetterRepos
2329
return new LetterRepository(docClient, log, config);
2430
}
2531

32+
function createMIRepository(documentClient: DynamoDBDocumentClient, log: pino.Logger, envVars: EnvVars): MIRepository {
33+
const ddbClient = new DynamoDBClient({});
34+
const docClient = DynamoDBDocumentClient.from(ddbClient);
35+
const config = {
36+
miTableName: envVars.MI_TABLE_NAME,
37+
ttlHours: envVars.LETTER_TTL_HOURS
38+
};
39+
40+
return new MIRepository(docClient, log, config);
41+
}
42+
2643
export function createDependenciesContainer(): Deps {
2744

2845
const log = pino();
46+
const documentClient = createDocumentClient();
2947

3048
return {
3149
s3Client: new S3Client(),
32-
letterRepo: createLetterRepository(log, envVars),
50+
letterRepo: createLetterRepository(documentClient, log, envVars),
51+
miRepo: createMIRepository(documentClient, log, envVars),
3352
logger: log,
3453
env: envVars
3554
};

lambdas/api-handler/src/config/env.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const EnvVarsSchema = z.object({
44
SUPPLIER_ID_HEADER: z.string(),
55
APIM_CORRELATION_HEADER: z.string(),
66
LETTERS_TABLE_NAME: z.string(),
7+
MI_TABLE_NAME: z.string(),
78
LETTER_TTL_HOURS: z.coerce.number().int(),
89
DOWNLOAD_URL_TTL_SECONDS: z.coerce.number().int()
910
});

lambdas/api-handler/src/handlers/__tests__/get-letter-data.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import * as errors from '../../contracts/errors';
2020
import { createGetLetterDataHandler } from '../get-letter-data';
2121
import { S3Client } from '@aws-sdk/client-s3';
2222
import pino from 'pino';
23-
import { LetterRepository } from '../../../../../internal/datastore/src';
23+
import { LetterRepository, MIRepository } from '../../../../../internal/datastore/src';
2424
import { EnvVars } from '../../config/env';
2525
import { Deps } from "../../config/deps";
2626

@@ -37,7 +37,7 @@ describe('API Lambda handler', () => {
3737
LETTER_TTL_HOURS: 1,
3838
DOWNLOAD_URL_TTL_SECONDS: 1
3939
} as unknown as EnvVars
40-
}
40+
} as Deps;
4141

4242
beforeEach(() => {
4343
jest.clearAllMocks();

lambdas/api-handler/src/handlers/__tests__/get-letters.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { ValidationError } from '../../errors';
2020
import * as errors from '../../contracts/errors';
2121
import { S3Client } from '@aws-sdk/client-s3';
2222
import pino from 'pino';
23-
import { LetterRepository } from '../../../../../internal/datastore/src';
23+
import { LetterRepository, MIRepository } from '../../../../../internal/datastore/src';
2424
import { createGetLettersHandler } from "../get-letters";
2525
import { Deps } from "../../config/deps";
2626
import { EnvVars } from '../../config/env';
@@ -38,7 +38,7 @@ describe('API Lambda handler', () => {
3838
LETTER_TTL_HOURS: 1,
3939
DOWNLOAD_URL_TTL_SECONDS: 1
4040
} as unknown as EnvVars
41-
}
41+
} as Deps;
4242

4343
const originalEnv = process.env;
4444

lambdas/api-handler/src/handlers/__tests__/patch-letter.test.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { ValidationError } from '../../errors';
2121
import * as errors from '../../contracts/errors';
2222
import { S3Client } from '@aws-sdk/client-s3';
2323
import pino from 'pino';
24-
import { LetterRepository } from '../../../../../internal/datastore/src';
24+
import { LetterRepository, MIRepository } from '../../../../../internal/datastore/src';
2525
import { EnvVars } from '../../config/env';
2626
import { createPatchLetterHandler } from '../patch-letter';
2727
import { Deps } from "../../config/deps";
@@ -47,17 +47,17 @@ describe('patchLetter API Handler', () => {
4747
});
4848

4949
const mockedDeps: jest.Mocked<Deps> = {
50-
s3Client: {} as unknown as S3Client,
51-
letterRepo: {} as unknown as LetterRepository,
52-
logger: { info: jest.fn(), error: jest.fn() } as unknown as pino.Logger,
53-
env: {
54-
SUPPLIER_ID_HEADER: 'nhsd-supplier-id',
55-
APIM_CORRELATION_HEADER: 'nhsd-correlation-id',
56-
LETTERS_TABLE_NAME: 'LETTERS_TABLE_NAME',
57-
LETTER_TTL_HOURS: 1,
58-
DOWNLOAD_URL_TTL_SECONDS: 1
59-
} as unknown as EnvVars
60-
}
50+
s3Client: {} as unknown as S3Client,
51+
letterRepo: {} as unknown as LetterRepository,
52+
logger: { info: jest.fn(), error: jest.fn() } as unknown as pino.Logger,
53+
env: {
54+
SUPPLIER_ID_HEADER: 'nhsd-supplier-id',
55+
APIM_CORRELATION_HEADER: 'nhsd-correlation-id',
56+
LETTERS_TABLE_NAME: 'LETTERS_TABLE_NAME',
57+
LETTER_TTL_HOURS: 1,
58+
DOWNLOAD_URL_TTL_SECONDS: 1
59+
} as unknown as EnvVars
60+
} as Deps;
6161

6262
it('returns 200 OK with updated resource', async () => {
6363
const event = makeApiGwEvent({

lambdas/api-handler/src/handlers/__tests__/post-mi.test.ts

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,15 @@ import { mockDeep } from "jest-mock-extended";
33
import { makeApiGwEvent } from "./utils/test-utils";
44
import { PostMIRequest, PostMIResponse } from "../../contracts/mi";
55
import * as miService from '../../services/mi-operations';
6-
import { postMi } from '../../index';
6+
import pino from 'pino';
7+
import { LetterRepository, MIRepository } from "../../../../../internal/datastore/src";
8+
import { Deps } from "../../config/deps";
9+
import { EnvVars } from "../../config/env";
10+
import { createPostMIHandler } from "../post-mi";
711

812
jest.mock('../../services/mi-operations');
913

10-
jest.mock('../../config/lambda-config', () => ({
11-
lambdaConfig: {
12-
SUPPLIER_ID_HEADER: 'nhsd-supplier-id',
13-
APIM_CORRELATION_HEADER: 'nhsd-correlation-id'
14-
}
15-
}));
16-
17-
const postMiRequest : PostMIRequest = {
14+
const postMIRequest : PostMIRequest = {
1815
data: {
1916
type: 'ManagementInformation',
2017
attributes: {
@@ -27,37 +24,50 @@ const postMiRequest : PostMIRequest = {
2724
}
2825
}
2926
};
30-
const requestBody = JSON.stringify(postMiRequest, null, 2);
27+
const requestBody = JSON.stringify(postMIRequest, null, 2);
3128

32-
const postMiResponse : PostMIResponse = {
29+
const postMIResponse : PostMIResponse = {
3330
data: {
3431
id: 'id1',
35-
...postMiRequest.data
32+
...postMIRequest.data
3633
}
3734
};
3835

39-
const mockedPostMiOperation = jest.mocked(miService.postMI);
36+
const mockedPostMIOperation = jest.mocked(miService.postMI);
4037

4138
beforeEach(() => {
4239
jest.clearAllMocks();
4340
});
4441

4542

4643
describe('postMI API Handler', () => {
44+
45+
const mockedDeps: jest.Mocked<Deps> = {
46+
miRepo: {} as unknown as MIRepository,
47+
logger: { info: jest.fn(), error: jest.fn() } as unknown as pino.Logger,
48+
env: {
49+
SUPPLIER_ID_HEADER: 'nhsd-supplier-id',
50+
APIM_CORRELATION_HEADER: 'nhsd-correlation-id',
51+
DOWNLOAD_URL_TTL_SECONDS: 1
52+
} as unknown as EnvVars
53+
} as Deps;
54+
55+
4756
it('returns 200 OK with updated resource', async () => {
4857
const event = makeApiGwEvent({
4958
path: '/mi',
5059
body: requestBody,
5160
headers: {'nhsd-supplier-id': 'supplier1', 'nhsd-correlation-id': 'correlationId'}
5261
});
5362

54-
mockedPostMiOperation.mockResolvedValue(postMiResponse);
63+
mockedPostMIOperation.mockResolvedValue(postMIResponse);
5564

56-
const result = await postMi(event, mockDeep<Context>(), jest.fn());
65+
const postMI = createPostMIHandler(mockedDeps);
66+
const result = await postMI(event, mockDeep<Context>(), jest.fn());
5767

5868
expect(result).toEqual({
5969
statusCode: 201,
60-
body: JSON.stringify(postMiResponse, null, 2)
70+
body: JSON.stringify(postMIResponse, null, 2)
6171
});
6272
});
6373

@@ -72,7 +82,8 @@ describe('postMI API Handler', () => {
7282
headers: {'nhsd-supplier-id': 'supplier1', 'nhsd-correlation-id': 'correlationId'}
7383
});
7484

75-
const result = await postMi(event, mockDeep<Context>(), jest.fn());
85+
const postMI = createPostMIHandler(mockedDeps);
86+
const result = await postMI(event, mockDeep<Context>(), jest.fn());
7687

7788
expect(result).toEqual(expect.objectContaining({
7889
statusCode: 400
@@ -85,7 +96,8 @@ describe('postMI API Handler', () => {
8596
headers: {'nhsd-supplier-id': 'supplier1', 'nhsd-correlation-id': 'correlationId'}
8697
});
8798

88-
const result = await postMi(event, mockDeep<Context>(), jest.fn());
99+
const postMI = createPostMIHandler(mockedDeps);
100+
const result = await postMI(event, mockDeep<Context>(), jest.fn());
89101

90102
expect(result).toEqual(expect.objectContaining({
91103
statusCode: 400
@@ -100,9 +112,10 @@ describe('postMI API Handler', () => {
100112
pathParameters: {id: 'id1'},
101113
headers: {'nhsd-supplier-id': 'supplier1', 'nhsd-correlation-id': 'correlationId'}
102114
});
103-
mockedPostMiOperation.mockRejectedValue(new Error());
115+
mockedPostMIOperation.mockRejectedValue(new Error());
104116

105-
const result = await postMi(event, mockDeep<Context>(), jest.fn());
117+
const postMI = createPostMIHandler(mockedDeps);
118+
const result = await postMI(event, mockDeep<Context>(), jest.fn());
106119

107120
expect(result).toEqual(expect.objectContaining({
108121
statusCode: 500
@@ -116,7 +129,8 @@ describe('postMI API Handler', () => {
116129
headers: {'nhsd-correlation-id': 'correlationId'}
117130
});
118131

119-
const result = await postMi(event, mockDeep<Context>(), jest.fn());
132+
const postMI = createPostMIHandler(mockedDeps);
133+
const result = await postMI(event, mockDeep<Context>(), jest.fn());
120134

121135
expect(result).toEqual(expect.objectContaining({
122136
statusCode: 400
@@ -130,7 +144,8 @@ describe('postMI API Handler', () => {
130144
headers: {'nhsd-supplier-id': 'supplier1'}
131145
});
132146

133-
const result = await postMi(event, mockDeep<Context>(), jest.fn());
147+
const postMI = createPostMIHandler(mockedDeps);
148+
const result = await postMI(event, mockDeep<Context>(), jest.fn());
134149

135150
expect(result).toEqual(expect.objectContaining({
136151
statusCode: 500
@@ -144,7 +159,8 @@ describe('postMI API Handler', () => {
144159
headers: {'nhsd-supplier-id': 'supplier1', 'nhsd-correlation-id': 'correlationId'}
145160
});
146161

147-
const result = await postMi(event, mockDeep<Context>(), jest.fn());
162+
const postMI = createPostMIHandler(mockedDeps);
163+
const result = await postMI(event, mockDeep<Context>(), jest.fn());
148164

149165
expect(result).toEqual(expect.objectContaining({
150166
statusCode: 400
@@ -158,7 +174,8 @@ describe('postMI API Handler', () => {
158174
headers: {'nhsd-supplier-id': 'supplier1', 'nhsd-correlation-id': 'correlationId'}
159175
});
160176

161-
const result = await postMi(event, mockDeep<Context>(), jest.fn());
177+
const postMI = createPostMIHandler(mockedDeps);
178+
const result = await postMI(event, mockDeep<Context>(), jest.fn());
162179

163180
expect(result).toEqual(expect.objectContaining({
164181
statusCode: 400
@@ -175,7 +192,8 @@ describe('postMI API Handler', () => {
175192
throw 'Unexpected error';
176193
})
177194

178-
const result = await postMi(event, mockDeep<Context>(), jest.fn());
195+
const postMI = createPostMIHandler(mockedDeps);
196+
const result = await postMI(event, mockDeep<Context>(), jest.fn());
179197

180198
expect(result).toEqual(expect.objectContaining({
181199
statusCode: 500

0 commit comments

Comments
 (0)