Skip to content

Commit 6a14aca

Browse files
authored
feat: SQSMessageModel validates required fields of message (#1188)
Allows us to remove the non-null assertions, making this model more type-safe. This is unlikely to break any existing applications as this model is intended for _received_ messages, which have all required fields. Jira: [ENG-2733] BREAKING CHANGE: `SQSMessageModel` will throw if required fields (`MessageID`, `ReceiptHandle`, `Body`) are missing from the SQS message.
1 parent 141898e commit 6a14aca

3 files changed

Lines changed: 57 additions & 5 deletions

File tree

docs/migration/v2.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ The `MarketingPreference` model is removed, as this is application-specific and
168168

169169
The `StatusModel` model has been replaced by a simple object type. See the [StatusModel](#statusmodel) section below.
170170

171-
Other models (`ResponseModel`, `SQSMessageModel`) are unaffected except that they no longer inherit from a common `Model` class.
171+
Other models (`ResponseModel`, `SQSMessageModel`) are largely unaffected except that they no longer inherit from a common `Model` class.
172172

173173
### `StatusModel`
174174

@@ -211,3 +211,7 @@ async function checkStatus(): Promise<ServiceStatus> {
211211
```
212212

213213
Note that we can keep `status` unset initially, and TypeScript will complain if you forget to set it before `checkStatus` returns.
214+
215+
### `SQSMessageModel`
216+
217+
The model constructor will now validate that `message` has all fields required of a received SQS message. This should not break existing applications that are using this model correctly, but is included in the 2.0.0 release as a precaution.

src/models/SQSMessageModel.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,24 @@ export default class Message {
1515
metadata: Record<string, any> = {};
1616

1717
constructor(message: SQS.Message) {
18-
// todo: validate rather than assert the type
19-
this.messageId = message.MessageId!;
20-
this.receiptHandle = message.ReceiptHandle!;
21-
this.body = JSON.parse(message.Body!);
18+
if (!message.MessageId) {
19+
throw new TypeError('Message does not have a MessageId');
20+
}
21+
if (!message.ReceiptHandle) {
22+
throw new TypeError('Message does not have a ReceiptHandle');
23+
}
24+
if (!message.Body) {
25+
throw new TypeError('Message does not have a Body');
26+
}
27+
28+
this.messageId = message.MessageId;
29+
this.receiptHandle = message.ReceiptHandle;
30+
31+
try {
32+
this.body = JSON.parse(message.Body);
33+
} catch (error) {
34+
throw new TypeError('Message body is not valid JSON');
35+
}
2236
}
2337

2438
/**

tests/unit/models/SQSMessageModel.spec.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { SQS } from 'aws-sdk';
2+
13
import { SQSMessageModel as Message } from '@/src';
24

35
describe('unit.models.SQSMessageModel', () => {
@@ -13,6 +15,38 @@ describe('unit.models.SQSMessageModel', () => {
1315

1416
const messageModel = new Message(mockedMessage);
1517

18+
describe('constructor', () => {
19+
it('should throw if message is missing MessageId', () => {
20+
const message: SQS.Message = { ...mockedMessage };
21+
delete message.MessageId;
22+
23+
expect(() => new Message(message)).toThrowError(TypeError);
24+
});
25+
26+
it('should throw if message is missing ReceiptHandle', () => {
27+
const message: SQS.Message = { ...mockedMessage };
28+
delete message.ReceiptHandle;
29+
30+
expect(() => new Message(message)).toThrowError(TypeError);
31+
});
32+
33+
it('should throw if message is missing Body', () => {
34+
const message: SQS.Message = { ...mockedMessage };
35+
delete message.Body;
36+
37+
expect(() => new Message(message)).toThrowError(TypeError);
38+
});
39+
40+
it('should throw if message body is not valid JSON', () => {
41+
const message: SQS.Message = {
42+
...mockedMessage,
43+
Body: 'This is not JSON!',
44+
};
45+
46+
expect(() => new Message(message)).toThrowError(TypeError);
47+
});
48+
});
49+
1650
describe('getMessageId', () => {
1751
it('should return the message ID', () => {
1852
expect(messageModel.getMessageId()).toEqual(mockedMessage.MessageId);

0 commit comments

Comments
 (0)