Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion docs/migration/v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ The `MarketingPreference` model is removed, as this is application-specific and

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

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

### `StatusModel`

Expand Down Expand Up @@ -211,3 +211,7 @@ async function checkStatus(): Promise<ServiceStatus> {
```

Note that we can keep `status` unset initially, and TypeScript will complain if you forget to set it before `checkStatus` returns.

### `SQSMessageModel`

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.
22 changes: 18 additions & 4 deletions src/models/SQSMessageModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,24 @@ export default class Message {
metadata: Record<string, any> = {};

constructor(message: SQS.Message) {
// todo: validate rather than assert the type
this.messageId = message.MessageId!;
this.receiptHandle = message.ReceiptHandle!;
this.body = JSON.parse(message.Body!);
if (!message.MessageId) {
throw new TypeError('Message does not have a MessageId');
}
if (!message.ReceiptHandle) {
throw new TypeError('Message does not have a ReceiptHandle');
}
if (!message.Body) {
throw new TypeError('Message does not have a Body');
}

this.messageId = message.MessageId;
this.receiptHandle = message.ReceiptHandle;

try {
this.body = JSON.parse(message.Body);
} catch (error) {
throw new TypeError('Message body is not valid JSON');
}
}

/**
Expand Down
34 changes: 34 additions & 0 deletions tests/unit/models/SQSMessageModel.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { SQS } from 'aws-sdk';

import { SQSMessageModel as Message } from '@/src';

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

const messageModel = new Message(mockedMessage);

describe('constructor', () => {
it('should throw if message is missing MessageId', () => {
const message: SQS.Message = { ...mockedMessage };
delete message.MessageId;

expect(() => new Message(message)).toThrowError(TypeError);
});

it('should throw if message is missing ReceiptHandle', () => {
const message: SQS.Message = { ...mockedMessage };
delete message.ReceiptHandle;

expect(() => new Message(message)).toThrowError(TypeError);
});

it('should throw if message is missing Body', () => {
const message: SQS.Message = { ...mockedMessage };
delete message.Body;

expect(() => new Message(message)).toThrowError(TypeError);
});

it('should throw if message body is not valid JSON', () => {
const message: SQS.Message = {
...mockedMessage,
Body: 'This is not JSON!',
};

expect(() => new Message(message)).toThrowError(TypeError);
});
});

describe('getMessageId', () => {
it('should return the message ID', () => {
expect(messageModel.getMessageId()).toEqual(mockedMessage.MessageId);
Expand Down