Skip to content

Commit 830d2aa

Browse files
committed
lint api handler
1 parent c7531cf commit 830d2aa

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+2631
-1955
lines changed

lambdas/api-handler/package.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
{
22
"dependencies": {
3+
"@aws-sdk/client-dynamodb": "^3.925.0",
4+
"@aws-sdk/client-s3": "^3.925.0",
35
"@aws-sdk/client-sqs": "^3.925.0",
6+
"@aws-sdk/lib-dynamodb": "^3.925.0",
7+
"@aws-sdk/s3-request-presigner": "^3.925.0",
48
"@internal/datastore": "*",
59
"@internal/helpers": "*",
10+
"@types/aws-lambda": "^8.10.148",
611
"esbuild": "^0.25.11",
7-
"pino": "^9.7.0"
12+
"pino": "^9.7.0",
13+
"zod": "^4.1.11"
814
},
915
"devDependencies": {
10-
"@aws-sdk/s3-request-presigner": "^3.901.0",
1116
"@tsconfig/node22": "^22.0.2",
12-
"@types/aws-lambda": "^8.10.148",
1317
"@types/jest": "^29.5.14",
1418
"jest": "^30.2.0",
1519
"jest-mock-extended": "^3.0.7",

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

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
1-
import type { Deps } from '../deps';
2-
3-
describe('createDependenciesContainer', () => {
1+
import type { Deps } from "../deps";
42

3+
describe("createDependenciesContainer", () => {
54
const env = {
6-
LETTERS_TABLE_NAME: 'LettersTable',
7-
LETTER_TTL_HOURS: 12960,
8-
MI_TABLE_NAME: 'MITable',
5+
LETTERS_TABLE_NAME: "LettersTable",
6+
LETTER_TTL_HOURS: 12_960,
7+
MI_TABLE_NAME: "MITable",
98
MI_TTL_HOURS: 2160,
10-
SUPPLIER_ID_HEADER: 'nhsd-supplier-id',
11-
APIM_CORRELATION_HEADER: 'nhsd-correlation-id',
12-
DOWNLOAD_URL_TTL_SECONDS: 60
9+
SUPPLIER_ID_HEADER: "nhsd-supplier-id",
10+
APIM_CORRELATION_HEADER: "nhsd-correlation-id",
11+
DOWNLOAD_URL_TTL_SECONDS: 60,
1312
};
1413

1514
beforeEach(() => {
1615
jest.clearAllMocks();
1716
jest.resetModules();
1817

1918
// pino
20-
jest.mock('pino', () => ({
19+
jest.mock("pino", () => ({
2120
__esModule: true,
2221
default: jest.fn(() => ({
2322
info: jest.fn(),
@@ -27,36 +26,37 @@ describe('createDependenciesContainer', () => {
2726
})),
2827
}));
2928

30-
jest.mock('@aws-sdk/client-s3', () => ({
29+
jest.mock("@aws-sdk/client-s3", () => ({
3130
S3Client: jest.fn(),
3231
}));
3332

34-
jest.mock('@aws-sdk/client-sqs', () => ({
33+
jest.mock("@aws-sdk/client-sqs", () => ({
3534
SQSClient: jest.fn(),
3635
}));
3736

3837
// Repo client
39-
jest.mock('@internal/datastore', () => ({
38+
jest.mock("@internal/datastore", () => ({
4039
LetterRepository: jest.fn(),
4140
MIRepository: jest.fn(),
42-
DBHealthcheck: jest.fn()
41+
DBHealthcheck: jest.fn(),
4342
}));
4443

4544
// Env
46-
jest.mock('../env', () => ({envVars: env}));
45+
jest.mock("../env", () => ({ envVars: env }));
4746
});
4847

49-
test('constructs deps and wires repository config correctly', async () => {
48+
test("constructs deps and wires repository config correctly", async () => {
5049
// get current mock instances
51-
const { S3Client } = jest.requireMock('@aws-sdk/client-s3') as { S3Client: jest.Mock };
52-
const { SQSClient } = jest.requireMock('@aws-sdk/client-sqs') as { SQSClient: jest.Mock };
53-
const pinoMock = jest.requireMock('pino') as { default: jest.Mock };
54-
const { LetterRepository, MIRepository } = jest.requireMock('@internal/datastore') as {
55-
LetterRepository: jest.Mock,
56-
MIRepository: jest.Mock
57-
};
58-
59-
const { createDependenciesContainer } = require('../deps');
50+
const { S3Client } = jest.requireMock("@aws-sdk/client-s3");
51+
const { SQSClient } = jest.requireMock("@aws-sdk/client-sqs");
52+
const pinoMock = jest.requireMock("pino");
53+
const { LetterRepository, MIRepository } = jest.requireMock(
54+
"@internal/datastore",
55+
);
56+
57+
// allow re-import of deps to leverage mocks
58+
// eslint-disable-next-line @typescript-eslint/no-require-imports
59+
const { createDependenciesContainer } = require("../deps");
6060
const deps: Deps = createDependenciesContainer();
6161

6262
expect(S3Client).toHaveBeenCalledTimes(1);
@@ -66,17 +66,17 @@ describe('createDependenciesContainer', () => {
6666
expect(pinoMock.default).toHaveBeenCalledTimes(1);
6767

6868
expect(LetterRepository).toHaveBeenCalledTimes(1);
69-
const letterRepoCtorArgs = (LetterRepository as jest.Mock).mock.calls[0];
69+
const letterRepoCtorArgs = LetterRepository.mock.calls[0];
7070
expect(letterRepoCtorArgs[2]).toEqual({
71-
lettersTableName: 'LettersTable',
72-
lettersTtlHours: 12960
71+
lettersTableName: "LettersTable",
72+
lettersTtlHours: 12_960,
7373
});
7474

7575
expect(MIRepository).toHaveBeenCalledTimes(1);
76-
const miRepoCtorArgs = (MIRepository as jest.Mock).mock.calls[0];
76+
const miRepoCtorArgs = MIRepository.mock.calls[0];
7777
expect(miRepoCtorArgs[2]).toEqual({
78-
miTableName: 'MITable',
79-
miTtlHours: 2160
78+
miTableName: "MITable",
79+
miTtlHours: 2160,
8080
});
8181

8282
expect(deps.env).toEqual(env);
Lines changed: 45 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
import { ZodError } from 'zod';
1+
/* eslint-disable @typescript-eslint/no-require-imports */
2+
/* Allow require imports to enable re-import of modules */
23

3-
describe('lambdaEnv', () => {
4+
import { ZodError } from "zod";
5+
6+
describe("lambdaEnv", () => {
47
const OLD_ENV = process.env;
58

69
beforeEach(() => {
@@ -12,64 +15,64 @@ describe('lambdaEnv', () => {
1215
process.env = OLD_ENV; // Restore
1316
});
1417

15-
it('should load all environment variables successfully', () => {
16-
process.env.SUPPLIER_ID_HEADER = 'nhsd-supplier-id';
17-
process.env.APIM_CORRELATION_HEADER = 'nhsd-correlation-id';
18-
process.env.LETTERS_TABLE_NAME = 'letters-table';
19-
process.env.MI_TABLE_NAME = 'mi-table';
20-
process.env.LETTER_TTL_HOURS = '12960';
21-
process.env.MI_TTL_HOURS = '2160';
22-
process.env.DOWNLOAD_URL_TTL_SECONDS = '60';
23-
process.env.MAX_LIMIT = '2500';
24-
process.env.QUEUE_URL = 'url';
18+
it("should load all environment variables successfully", () => {
19+
process.env.SUPPLIER_ID_HEADER = "nhsd-supplier-id";
20+
process.env.APIM_CORRELATION_HEADER = "nhsd-correlation-id";
21+
process.env.LETTERS_TABLE_NAME = "letters-table";
22+
process.env.MI_TABLE_NAME = "mi-table";
23+
process.env.LETTER_TTL_HOURS = "12960";
24+
process.env.MI_TTL_HOURS = "2160";
25+
process.env.DOWNLOAD_URL_TTL_SECONDS = "60";
26+
process.env.MAX_LIMIT = "2500";
27+
process.env.QUEUE_URL = "url";
2528

26-
const { envVars } = require('../env');
29+
const { envVars } = require("../env");
2730

2831
expect(envVars).toEqual({
29-
SUPPLIER_ID_HEADER: 'nhsd-supplier-id',
30-
APIM_CORRELATION_HEADER: 'nhsd-correlation-id',
31-
LETTERS_TABLE_NAME: 'letters-table',
32-
MI_TABLE_NAME: 'mi-table',
33-
LETTER_TTL_HOURS: 12960,
32+
SUPPLIER_ID_HEADER: "nhsd-supplier-id",
33+
APIM_CORRELATION_HEADER: "nhsd-correlation-id",
34+
LETTERS_TABLE_NAME: "letters-table",
35+
MI_TABLE_NAME: "mi-table",
36+
LETTER_TTL_HOURS: 12_960,
3437
MI_TTL_HOURS: 2160,
3538
DOWNLOAD_URL_TTL_SECONDS: 60,
3639
MAX_LIMIT: 2500,
37-
QUEUE_URL: 'url'
40+
QUEUE_URL: "url",
3841
});
3942
});
4043

41-
it('should throw if a required env var is missing', () => {
42-
process.env.SUPPLIER_ID_HEADER = 'nhsd-supplier-id';
43-
process.env.APIM_CORRELATION_HEADER = 'nhsd-correlation-id';
44+
it("should throw if a required env var is missing", () => {
45+
process.env.SUPPLIER_ID_HEADER = "nhsd-supplier-id";
46+
process.env.APIM_CORRELATION_HEADER = "nhsd-correlation-id";
4447
process.env.LETTERS_TABLE_NAME = undefined; // simulate missing var
45-
process.env.MI_TABLE_NAME = 'mi-table';
46-
process.env.LETTER_TTL_HOURS = '12960';
47-
process.env.MI_TTL_HOURS = '2160';
48-
process.env.DOWNLOAD_URL_TTL_SECONDS = '60';
48+
process.env.MI_TABLE_NAME = "mi-table";
49+
process.env.LETTER_TTL_HOURS = "12960";
50+
process.env.MI_TTL_HOURS = "2160";
51+
process.env.DOWNLOAD_URL_TTL_SECONDS = "60";
4952

50-
expect(() => require('../env')).toThrow(ZodError);
53+
expect(() => require("../env")).toThrow(ZodError);
5154
});
5255

53-
it('should not throw if optional are not set', () => {
54-
process.env.SUPPLIER_ID_HEADER = 'nhsd-supplier-id';
55-
process.env.APIM_CORRELATION_HEADER = 'nhsd-correlation-id';
56-
process.env.LETTERS_TABLE_NAME = 'letters-table';
57-
process.env.MI_TABLE_NAME = 'mi-table';
58-
process.env.LETTER_TTL_HOURS = '12960';
59-
process.env.MI_TTL_HOURS = '2160';
60-
process.env.DOWNLOAD_URL_TTL_SECONDS = '60';
56+
it("should not throw if optional are not set", () => {
57+
process.env.SUPPLIER_ID_HEADER = "nhsd-supplier-id";
58+
process.env.APIM_CORRELATION_HEADER = "nhsd-correlation-id";
59+
process.env.LETTERS_TABLE_NAME = "letters-table";
60+
process.env.MI_TABLE_NAME = "mi-table";
61+
process.env.LETTER_TTL_HOURS = "12960";
62+
process.env.MI_TTL_HOURS = "2160";
63+
process.env.DOWNLOAD_URL_TTL_SECONDS = "60";
6164

62-
const { envVars } = require('../env');
65+
const { envVars } = require("../env");
6366

6467
expect(envVars).toEqual({
65-
SUPPLIER_ID_HEADER: 'nhsd-supplier-id',
66-
APIM_CORRELATION_HEADER: 'nhsd-correlation-id',
67-
LETTERS_TABLE_NAME: 'letters-table',
68-
MI_TABLE_NAME: 'mi-table',
69-
LETTER_TTL_HOURS: 12960,
68+
SUPPLIER_ID_HEADER: "nhsd-supplier-id",
69+
APIM_CORRELATION_HEADER: "nhsd-correlation-id",
70+
LETTERS_TABLE_NAME: "letters-table",
71+
MI_TABLE_NAME: "mi-table",
72+
LETTER_TTL_HOURS: 12_960,
7073
MI_TTL_HOURS: 2160,
7174
DOWNLOAD_URL_TTL_SECONDS: 60,
72-
MAX_LIMIT: undefined
75+
MAX_LIMIT: undefined,
7376
});
7477
});
7578
});
Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import { S3Client } from "@aws-sdk/client-s3";
2-
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
3-
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
2+
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
3+
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
44
import { SQSClient } from "@aws-sdk/client-sqs";
5-
import pino from 'pino';
6-
import { LetterRepository, MIRepository, DBHealthcheck } from '@internal/datastore';
7-
import { envVars, EnvVars } from "../config/env";
5+
import pino from "pino";
6+
import {
7+
DBHealthcheck,
8+
LetterRepository,
9+
MIRepository,
10+
} from "@internal/datastore";
11+
import { EnvVars, envVars } from "./env";
812

913
export type Deps = {
1014
s3Client: S3Client;
@@ -13,46 +17,48 @@ export type Deps = {
1317
miRepo: MIRepository;
1418
dbHealthcheck: DBHealthcheck;
1519
logger: pino.Logger;
16-
env: EnvVars
20+
env: EnvVars;
1721
};
1822

1923
function createDocumentClient(): DynamoDBDocumentClient {
2024
const ddbClient = new DynamoDBClient({});
2125
return DynamoDBDocumentClient.from(ddbClient);
2226
}
2327

24-
25-
function createLetterRepository(log: pino.Logger, envVars: EnvVars): LetterRepository {
26-
28+
function createLetterRepository(
29+
log: pino.Logger,
30+
environment: EnvVars,
31+
): LetterRepository {
2732
const config = {
28-
lettersTableName: envVars.LETTERS_TABLE_NAME,
29-
lettersTtlHours: envVars.LETTER_TTL_HOURS
33+
lettersTableName: environment.LETTERS_TABLE_NAME,
34+
lettersTtlHours: environment.LETTER_TTL_HOURS,
3035
};
3136

3237
return new LetterRepository(createDocumentClient(), log, config);
3338
}
3439

35-
function createDBHealthcheck(envVars: EnvVars): DBHealthcheck {
40+
function createDBHealthcheck(environment: EnvVars): DBHealthcheck {
3641
const config = {
37-
lettersTableName: envVars.LETTERS_TABLE_NAME,
38-
lettersTtlHours: envVars.LETTER_TTL_HOURS
42+
lettersTableName: environment.LETTERS_TABLE_NAME,
43+
lettersTtlHours: environment.LETTER_TTL_HOURS,
3944
};
4045

4146
return new DBHealthcheck(createDocumentClient(), config);
4247
}
4348

44-
function createMIRepository(log: pino.Logger, envVars: EnvVars): MIRepository {
45-
49+
function createMIRepository(
50+
log: pino.Logger,
51+
environment: EnvVars,
52+
): MIRepository {
4653
const config = {
47-
miTableName: envVars.MI_TABLE_NAME,
48-
miTtlHours: envVars.MI_TTL_HOURS
54+
miTableName: environment.MI_TABLE_NAME,
55+
miTtlHours: environment.MI_TTL_HOURS,
4956
};
5057

5158
return new MIRepository(createDocumentClient(), log, config);
5259
}
5360

5461
export function createDependenciesContainer(): Deps {
55-
5662
const log = pino();
5763

5864
return {
@@ -62,6 +68,6 @@ export function createDependenciesContainer(): Deps {
6268
miRepo: createMIRepository(log, envVars),
6369
dbHealthcheck: createDBHealthcheck(envVars),
6470
logger: log,
65-
env: envVars
71+
env: envVars,
6672
};
6773
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
import {z} from 'zod';
1+
import { z } from "zod";
22

33
const EnvVarsSchema = z.object({
44
SUPPLIER_ID_HEADER: z.string(),
55
APIM_CORRELATION_HEADER: z.string(),
66
LETTERS_TABLE_NAME: z.string(),
77
MI_TABLE_NAME: z.string(),
88
LETTER_TTL_HOURS: z.coerce.number().int(),
9-
MI_TTL_HOURS: z.coerce.number().int(),
9+
MI_TTL_HOURS: z.coerce.number().int(),
1010
DOWNLOAD_URL_TTL_SECONDS: z.coerce.number().int(),
1111
MAX_LIMIT: z.coerce.number().int().optional(),
12-
QUEUE_URL: z.coerce.string().optional()
12+
QUEUE_URL: z.coerce.string().optional(),
1313
});
1414

1515
export type EnvVars = z.infer<typeof EnvVarsSchema>;

0 commit comments

Comments
 (0)