Serverless CRUD for Amazon SNS with Node.js and Serverless Framework. Allows you to create, list, publish, and subscribe to SNS topics, with API Key authentication, local persistence in JSON files, debugging endpoints, and webhook simulation. Includes integration with SSM Parameter Store and support for local development with serverless-offline.
View
- 1.0) Project Description.
- 1.1) Project Execution.
- 1.2) Configure the serverless project from scratch
- 1.3) Technologies.
1.0) Description 🔝
View
This project implements a complete CRUD system for Amazon Simple Notification Service (SNS) using Node.js and the Serverless Framework. The system allows you to manage SNS topics, including their creation, listing, message publishing, and subscription management.
Key features:
- Implementation of a serverless architecture using AWS Lambda
- Integration with Amazon SNS for pub/sub messaging
- RESTful API protected with API Key
- Configuration management via SSM Parameter Store
- Support for local development with serverless-offline
- Handling of SNS events and HTTP
- Implementation of design patterns for asynchronous messaging
- Webhooks System: Endpoints to receive SNS notifications in offline mode
- Data Persistence: Storage in JSON files for topics, subscriptions, and notifications
- Debugging Endpoints: Tools for troubleshooting and monitoring system status
/debug-topics: Full state of topics with file statistics/debug-subscriptions: Full state of subscriptions with grouping by topic/list-notifications: Received notifications with filtering and grouping
- Topic Management: Endpoints to create and list topics
/create-manual-topic: Create new SNS topics/list-topics: List all available topics/debug-topics: Full debug state of topics
- Subscription Management: Endpoints to subscribe and list subscriptions
/subscribe-topic: Subscribe to a specific topic/list-all-subscriptions: All subscriptions with filtering and statistics/list-subscription-topic/{topicName}: Subscriptions for a specific topic
- Message Publishing: Endpoints to publish messages
/publish-topic: Publish messages to a specific topic
- Webhooks and Notifications: Endpoints to receive and list notifications
/webhook/{topicName}: Receive SNS notifications (offline mode)
- Enhanced Validations: Topic existence check and parameter validation
- Realistic Simulation: Behavior closer to the real SNS with persistence between restarts
- Improved Error Handling: More descriptive messages and available resources list
The system consists of the following main components:
-
API Gateway
- Entry point for all HTTP requests
- Implements authentication via API Key
- Routes requests to corresponding Lambda functions
-
Lambda Functions
- Topic Management
createManualTopic: Creates new SNS topicslistTopics: Lists all available topicsdebugTopics: Full debug state of topics (offline mode)
- Publication
publishTopic: Publishes messages to specific topics
- Subscriptions
subscribeTopic: Manages subscriptions to topicslistSubscriptionTopic: Lists subscriptions by topicdebugSubscriptions: Full debug state of subscriptions (offline mode)
- Webhooks and Notifications
webhookReceiver: Receives SNS notifications (offline mode)listNotifications: Lists received notifications with filtering
- Topic Management
-
Amazon SNS
- Pub/sub messaging service
- Manages topics and subscriptions
- Distributes messages to subscribers
-
SSM Parameter Store
- Stores sensitive configuration
- Manages environment variables
- Endpoint and credential configuration
- Create Topic → Get TopicArn
- List Topics → Verify creation
- Debug Topics → Verify full state (optional)
- Subscribe → Get SubscriptionArn
- Debug Subscriptions → Verify full state (optional)
- Publish Message → Send message to topic
- Receive Notification → Webhook processes the notification
- List Notifications → Verify received notifications
- List Subscriptions → Verify subscriptions
The project includes configuration for local development:
- Serverless Offline to simulate AWS Lambda
- SNS Offline to simulate Amazon SNS
- SSM Offline to simulate Parameter Store
- Configurable ports for each service
The project includes specialized endpoints for debugging in offline mode:
- Debug Topics:
/debug-topics- Full state of topics with statistics - Debug Subscriptions:
/debug-subscriptions- Full state of subscriptions with grouping - Data Persistence: JSON files to maintain state between restarts
- Automatic Webhooks: Endpoints to receive simulated SNS notifications
- Authentication via API Key
- Environment variables managed by SSM
- Secure AWS credentials
- Protected endpoints in API Gateway
- Framework: Serverless v3
- Runtime: Node.js 18.x
- Region: us-east-1
- Lambda Memory: 512MB
- Timeout: 10 seconds
- Debugging Endpoints: Only available in offline mode for troubleshooting
- Local Persistence: JSON files in
.serverless/to maintain state - Realistic Simulation: Similar behavior to the real SNS
- Enhanced Validations: Resource existence check
- Error Handling: More descriptive messages and facilitated debugging
1.1) Project Execution 🔝
View
- We create a working environment through some ide, we can or cannot create a root folder for the project, we position ourselves on it
cd 'projectRootName'
- Once a working environment is created through some ide, we clone the project
git clone https://github.com/andresWeitzel/SNS_NodeJS_AWS
- We position ourselves on the project
cd 'projectName'
- We install the LTS version of Nodejs(v18)
- We install the Serverless Framework globally if we haven't done it yet. I recommend version three as it's free and doesn't require credentials. You can use the latest version (four) without problems, although it's paid.
npm install -g serverless@3
- We verify the Serverless version installed
sls -v
- We install all necessary packages
npm i
- The ssm variables used in the project are kept to simplify the configuration process of the same. It is recommended to add the corresponding file (serverless_ssm.yml) to the .gitignore.
- The following script configured in the project's package.json is responsible for
- Levantar serverless-offline (serverless-offline)
"scripts": {
"serverless-offline": "sls offline start",
"start": "npm run serverless-offline"
},
- We execute the app from the terminal.
npm start
- If a message indicating that port 4567 is already in use is presented, we can terminate all dependent processes and re-execute the app
npx kill-port 4567
npm start
1.2) Configure the serverless project from scratch 🔝
View
- We create a working environment through some ide, we can or no create a root folder for the project, we position ourselves on it
cd 'projectRootName'
- Once a working environment is created through some ide, we clone the project
git clone https://github.com/andresWeitzel/SNS_NodeJS_AWS
- We position ourselves on the project
cd 'projectName'
- We install the latest LTS version of Nodejs(v18)
- We install Serverless Framework globally if it hasn't been done yet
npm install -g serverless
- We verify the Serverless version installed
sls -v
- We initialize a serverles template
serverless create --template aws-nodejs
- We initialize an npm project
npm init -y
- We install serverless offline
npm i serverless-offline --save-dev
- We add the plugin to the .yml
plugins:
- serverless-offline
- We install serverless ssm
npm i serverless-offline-ssm --save-dev
- We add the plugin to the .yml
plugins:
- serverless-offline-ssm
- serverless-offline
- We install serverless sns
npm i serverless-offline-sns --save-dev
- We add the plugin to the .yml
plugins:
- serverless-offline-sns
- serverless-offline-ssm
- serverless-offline
- We install serverless, this should be necessary for SNS use
npm i serverless --save-dev
- We install the plugin for sns use (aws-sdk-v3)
npm i @aws-sdk/client-sns --save-dev
- For port configuration, topics, etc., (of this plugin) refer to the serverless, plugins section and for SNS resources serverless, sns events section
- The ssm variables used in the project are kept to simplify the configuration process of the same. It is recommended to add the corresponding file (serverless_ssm.yml) to the .gitignore.
- We install the dependency for parallel script execution
npm i concurrently
- The following script configured in the project's package.json is responsible for
- Levantar serverless-offline (serverless-offline)
"scripts": {
"serverless-offline": "sls offline start",
"start": "npm run serverless-offline"
},
- We execute the app from the terminal.
npm start
- If a message indicating that port 4567 is already in use is presented, we can terminate all dependent processes and re-execute the app
npx kill-port 4567
npm start
Important:This is an initial configuration, steps for simplification are omitted. For more information, refer to the official serverless, plugins page
1.3) Technologies 🔝
View
| Technologies | Version | Purpose |
|---|---|---|
| SDK | 4.3.2 | Automatic Module Injection for Lambdas |
| Serverless Framework Core v3 | 3.23.0 | Core AWS Services |
| Serverless Plugin | 6.2.2 | Modular Definition Libraries |
| Systems Manager Parameter Store (SSM) | 3.0 | Environment Variable Management |
| Amazon Simple Queue Service (SQS) | 7.0 | Distributed Message Queue Service |
| Elastic MQ | 1.3 | Compatible Interface with SQS (msg memory) |
| Amazon Api Gateway | 2.0 | API Manager, Authentication, Control, and Processing |
| NodeJS | 14.18.1 | JS Library |
| VSC | 1.72.2 | IDE |
| Postman | 10.11 | HTTP Client |
| CMD | 10 | System Symbol for Command Line |
| Git | 2.29.1 | Version Control |
| Plugin | Download |
|---|---|
| serverless-offline | https://www.serverless.com/plugins/serverless-offline |
| serverless-offline-ssm | https://www.npmjs.com/package/serverless-offline-ssm |
| serverless-offline-sqs | https://www.npmjs.com/package/serverless-offline-sqs |
| Extension |
|---|
| Prettier - Code formatter |
| YAML - Autoformatter .yml (alt+shift+f) |
| DotENV |
2.0) Endpoints and resources 🔝
View
The project implements a complete CRUD for Amazon SNS with the following endpoints:
| Endpoint | Method | Description | Authentication |
|---|---|---|---|
/create-manual-topic |
POST | Creates a new SNS topic | Requires API Key |
/list-topics |
GET | Lists all available SNS topics | Requires API Key |
/publish-topic |
POST | Publishes a message to a specific topic | Requires API Key |
/subscribe-topic |
POST | Subscribes an endpoint to a specific topic | Requires API Key |
/list-subscription-topic/{topicName} |
GET | Lists all subscriptions for a specific topic | Requires API Key |
/list-all-subscriptions |
GET | Lists all subscriptions for all topics | Requires API Key |
| Endpoint | Method | Description | Authentication |
|---|---|---|---|
/webhook/{topicName} |
POST | Receives SNS notifications (offline mode) | Public |
/list-notifications |
GET | Lists all received notifications | Requires API Key |
| Endpoint | Method | Description | Authentication |
|---|---|---|---|
/debug-topics |
GET | Full debug state of topics | Requires API Key |
/debug-subscriptions |
GET | Full debug state of subscriptions | Requires API Key |
- Endpoint: POST
/create-manual-topic - Description: Creates a new SNS topic with persistence
- Handler:
src/lambdas/topic/createManualTopic.handler - Functionality:
- Saves topic to JSON file
- Validates topic name
- Returns simulated ARN
- Endpoint: GET
/list-topics - Description: Lists topics from JSON file
- Handler:
src/lambdas/topic/listTopics.handler - Functionality:
- Reads from persistent file
- Does not include automatically generated topics
- Shows only topics created by the user
- Endpoint: POST
/publish-topic - Description: Publishes a message with topic validation
- Handler:
src/lambdas/publish/publishTopic.handler - Functionality:
- Validates that the topic exists
- Simulates delivery to subscribers
- Returns delivery information
- Endpoint: POST
/subscribe-topic - Description: Subscribes with validation and automatic webhook
- Handler:
src/lambdas/subscribe/subscribeTopic.handler - Functionality:
- Validates topic existence
- Uses automatic webhook:
http://127.0.0.1:4000/dev/webhook/{topicName} - Saves subscription to JSON file
- Endpoint: GET
/list-subscription-topic/{topicName} - Description: Lists subscriptions for a specific topic
- Handler:
src/lambdas/subscribe/listSubscriptionTopic.handler - Characteristics:
- Path Parameter: The topic name is specified in the URL
- Validation: Verifies that topicName is present in the URL
- Persistence: Reads subscriptions from JSON file
- Detailed Information: Shows complete data for each subscription
- Count: Provides the total number of subscriptions for the topic
- Endpoint: GET
/list-all-subscriptions - Description: Lists all subscriptions for all topics
- Handler:
src/lambdas/subscribe/listAllSubscriptions.handler - Functionality:
- Lists all subscriptions in the system
- Optional filtering by topic:
?topicName=X - Optional filtering by protocol:
?protocol=Y - Combined filtering:
?topicName=X&protocol=Y - Grouping by topic and protocol
- Detailed system statistics
- File persistence information
- Endpoint: POST
/webhook/{topicName} - Description: Receives SNS notifications
- Handler:
src/lambdas/webhook/webhookReceiver.handler - Functionality:
- Receives HTTP notifications
- Saves to JSON file
- Responds 200 OK to avoid retries
- Endpoint: GET
/list-notifications - Description: Lists received notifications
- Handler:
src/lambdas/webhook/listNotifications.handler - Functionality:
- Filtered by topic
- Grouped by topic
- Detailed information for each notification
- Endpoints:
/debug-topics,/debug-subscriptions,/list-all-subscriptions,/list-notifications - Description: Debugging and monitoring tools
- Characteristics:
- Current system state
- Detailed file information
- Usage statistics
- Filtered and grouped data
- Only available in offline mode
All endpoints are protected with API Key. Configuration is done via:
- API Gateway with API Key (
xApiKey) - Environment variables managed by SSM Parameter Store
3.0) Functionality Testing 🔝
View
-
Environment Variables in Postman
Variable Value Description base_urlhttp://localhost:4000/devBase URL for requests x-api-keyf98d8cd98h73s204e3456998ecl9427jAPI Key for authentication bearer_tokenBearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5cBearer Token for authentication -
Required Headers
{ "x-api-key": "{{x-api-key}}", "Authorization": "{{bearer_token}}", "Content-Type": "application/json" }
curl --location 'http://localhost:4000/dev/create-manual-topic' \
--header 'x-api-key: f98d8cd98h73s204e3456998ecl9427j' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c' \
--header 'Content-Type: application/json' \
--data '{
"name": "MyTestTopic"
}'
{
"statusCode": 200,
"body": {
"message": "Topic created successfully (Offline)",
"topicArn": "arn:aws:sns:us-east-1:123456789012:MyTestTopic",
"topicName": "MyTestTopic",
"note": "Topic is now available in the list-topics endpoint"
}
}{
"statusCode": 400,
"body": "Bad request, check request body attributes. Missing or incorrect"
}{
"statusCode": 401,
"body": "Not authenticated, check x_api_key"
}curl --location 'http://localhost:4000/dev/list-topics' \
--header 'x-api-key: f98d8cd98h73s204e3456998ecl9427j' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
{
"statusCode": 200,
"body": {
"message": "Topics retrieved successfully (Offline)",
"topics": [
{
"TopicArn": "arn:aws:sns:us-east-1:123456789012:MyTestTopic",
"TopicName": "MyTestTopic"
}
],
"totalTopics": 1
}
}{
"statusCode": 401,
"body": "Not authenticated, check x_api_key"
}curl --location 'http://localhost:4000/dev/debug-topics' \
--header 'x-api-key: f98d8cd98h73s204e3456998ecl9427j' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
{
"statusCode": 200,
"body": {
"message": "Debug information retrieved successfully",
"stats": {
"totalTopics": 2,
"fileExists": true,
"fileSize": "1.2 KB",
"lastModified": "2025-07-16T14:05:12.193Z"
},
"topics": [
{
"TopicArn": "arn:aws:sns:us-east-1:123456789012:MyTestTopic",
"TopicName": "MyTestTopic",
"createdAt": "2025-07-16T14:05:12.193Z"
},
{
"TopicArn": "arn:aws:sns:us-east-1:123456789012:AnotherTopic",
"TopicName": "AnotherTopic",
"createdAt": "2025-07-16T14:05:12.200Z"
}
],
"fileInfo": {
"filePath": "/path/to/.serverless/offline-topics.json",
"fileExists": true,
"fileSize": "1.2 KB",
"lastModified": "2025-07-16T14:05:12.193Z"
}
}
}{
"statusCode": 401,
"body": "Not authenticated, check x_api_key"
}curl --location 'http://localhost:4000/dev/subscribe-topic' \
--header 'x-api-key: f98d8cd98h73s204e3456998ecl9427j' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c' \
--header 'Content-Type: application/json' \
--data '{
"topicName": "MyTestTopic",
"protocol": "http",
"endpoint": "http://127.0.0.1:4000/dev/webhook/MyTestTopic"
}'
{
"statusCode": 200,
"body": {
"message": "Successfully subscribed to topic (Offline)",
"subscriptionArn": "arn:aws:sns:us-east-1:123456789012:MyTestTopic:1752674712193",
"topicName": "MyTestTopic",
"topicArn": "arn:aws:sns:us-east-1:123456789012:MyTestTopic",
"protocol": "http",
"endpoint": "http://127.0.0.1:4000/dev/webhook/MyTestTopic"
}
}{
"statusCode": 400,
"body": {
"message": "Topic does not exist",
"requestedTopic": "NonExistentTopic",
"availableTopics": ["MyTestTopic", "AnotherTopic"]
}
}{
"statusCode": 400,
"body": "Bad request, check request body attributes. Missing or incorrect"
}curl --location 'http://localhost:4000/dev/webhook/Topic1' \
--header 'Content-Type: application/json' \
--data '{
"Type": "Notification",
"MessageId": "msg_1752674712193_abc123def",
"TopicArn": "arn:aws:sns:us-east-1:123456789012:Topic1",
"Message": "This is a test message",
"Subject": "Test Subject",
"Timestamp": "2025-07-16T14:05:12.193Z",
"SignatureVersion": "1",
"Signature": "example-signature",
"SigningCertURL": "https://sns.us-east-1.amazonaws.com/SimpleNotificationService-0000000000000000000000.pem"
}'
{
"statusCode": 200,
"body": {
"message": "Notification received successfully",
"topicName": "Topic1",
"messageId": "msg_1752674712193_abc123def",
"receivedAt": "2025-07-16T14:05:12.200Z"
}
}{
"statusCode": 400,
"body": "Invalid notification format"
}curl --location 'http://localhost:4000/dev/list-all-subscriptions' \
--header 'x-api-key: f98d8cd98h73s204e3456998ecl9427j' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
{
"statusCode": 200,
"body": {
"message": "All subscriptions retrieved successfully",
"filters": {
"topicName": "none",
"protocol": "none"
},
"stats": {
"totalSubscriptions": 3,
"filteredSubscriptions": 3,
"totalTopics": 2,
"topicsWithSubscriptions": 2,
"protocolsUsed": ["http"],
"subscriptionsByTopicCount": {
"Topic1": 2,
"Topic2": 1
},
"subscriptionsByProtocolCount": {
"http": 3
}
},
"subscriptions": [...],
"subscriptionsByTopic": {...},
"subscriptionsByProtocol": {...},
"allTopics": [...]
}
}curl --location 'http://localhost:4000/dev/list-subscription-topic/Topic1' \
--header 'x-api-key: f98d8cd98h73s204e3456998ecl9427j' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
{
"statusCode": 200,
"body": {
"message": "Subscriptions retrieved successfully (Offline)",
"topicName": "Topic1",
"topicArn": "arn:aws:sns:us-east-1:123456789012:Topic1",
"subscriptions": [
{
"SubscriptionArn": "arn:aws:sns:us-east-1:123456789012:Topic1:1752674712193",
"TopicArn": "arn:aws:sns:us-east-1:123456789012:Topic1",
"Protocol": "http",
"Endpoint": "http://127.0.0.1:4000/dev/webhook/Topic1",
"Attributes": {
"Enabled": "true"
},
"createdAt": "2025-07-16T14:05:12.193Z"
}
],
"totalSubscriptions": 1
}
}curl --location 'http://localhost:4000/dev/debug-subscriptions' \
--header 'x-api-key: f98d8cd98h73s204e3456998ecl9427j' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
{
"statusCode": 200,
"body": {
"message": "Debug information retrieved successfully",
"stats": {
"totalSubscriptions": 3,
"totalTopics": 2,
"fileExists": true,
"fileSize": "2.1 KB",
"lastModified": "2025-07-16T14:05:12.193Z"
},
"subscriptions": [...],
"topics": [...],
"subscriptionsByTopic": {
"Topic1": [...],
"Topic2": [...]
},
"fileInfo": {
"filePath": "/path/to/.serverless/offline-subscriptions.json",
"fileExists": true,
"fileSize": "2.1 KB",
"lastModified": "2025-07-16T14:05:12.193Z"
}
}
}curl --location 'http://localhost:4000/dev/publish-topic' \
--header 'x-api-key: f98d8cd98h73s204e3456998ecl9427j' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c' \
--header 'Content-Type: application/json' \
--data '{
"topicName": "MyTestTopic",
"message": "This is a test message",
"subject": "Test Subject"
}'
{
"statusCode": 200,
"body": {
"message": "Message published successfully (Offline)",
"messageId": "msg_1752674712193_abc123def",
"topicName": "MyTestTopic",
"topicArn": "arn:aws:sns:us-east-1:123456789012:MyTestTopic",
"deliveredToSubscriptions": 1,
"note": "Notifications were simulated. Check webhook endpoint for actual delivery."
}
}{
"statusCode": 400,
"body": {
"message": "Topic does not exist",
"requestedTopic": "NonExistentTopic",
"availableTopics": ["MyTestTopic", "AnotherTopic"]
}
}curl --location 'http://localhost:4000/dev/list-notifications' \
--header 'x-api-key: f98d8cd98h73s204e3456998ecl9427j' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
curl --location 'http://localhost:4000/dev/list-notifications?topicName=Topic1' \
--header 'x-api-key: f98d8cd98h73s204e3456998ecl9427j' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
{
"statusCode": 200,
"body": {
"message": "Notifications retrieved successfully",
"filters": {
"topicName": "none"
},
"stats": {
"totalNotifications": 3,
"filteredNotifications": 3,
"topicsWithNotifications": 2
},
"notifications": [
{
"id": "notif_1752674712193_abc123",
"topicName": "Topic1",
"topicArn": "arn:aws:sns:us-east-1:123456789012:Topic1",
"message": "This is a test message",
"subject": "Test Subject",
"messageId": "msg_1752674712193_abc123def",
"timestamp": "2025-07-16T14:05:12.193Z",
"receivedAt": "2025-07-16T14:05:12.200Z"
}
],
"notificationsByTopic": {...}
}
}- Total number of topics
- Complete list of topics with ARNs
- Available topic names
- File persistence path
- File status (exists/does not exist)
- File JSON content
- File statistics (size, dates)
- Total number of subscriptions
- Total number of topics
- Complete list of subscriptions
- Complete list of topics
- Subscription grouping by topic
- Available topic names
- File persistence information
- Detailed statistics
# Verify which topics are available
curl -X GET "http://localhost:4000/dev/debug-topics" \
-H "x-api-key: f98d8cd98h73s204e3456998ecl9427j"# Verify subscription state
curl -X GET "http://localhost:4000/dev/debug-subscriptions" \
-H "x-api-key: f98d8cd98h73s204e3456998ecl9427j"
# List all subscriptions
curl -X GET "http://localhost:4000/dev/list-all-subscriptions" \
-H "x-api-key: f98d8cd98h73s204e3456998ecl9427j"
# List subscriptions for a specific topic
curl -X GET "http://localhost:4000/dev/list-subscription-topic/Topic1" \
-H "x-api-key: f98d8cd98h73s204e3456998ecl9427j"# Verify received notifications
curl -X GET "http://localhost:4000/dev/list-notifications" \
-H "x-api-key: f98d8cd98h73s204e3456998ecl9427j"# Verify file persistence
curl -X GET "http://localhost:4000/dev/debug-topics" \
-H "x-api-key: f98d8cd98h73s204e3456998ecl9427j"- Create topic → Verify with
/debug-topics - Subscribe → Verify with
/debug-subscriptionsor/list-all-subscriptions - Publish message → Verify with
/list-notifications - If there are issues → Use debug endpoints to diagnose
- Subscriptions:
/list-all-subscriptionsor/list-subscription-topic/{topicName} - Topics:
/debug-topics - Notifications:
/list-notifications
- Subscriptions:
- Only offline mode: Do not work in production
- Require API Key: Need authentication
- Only for development: Do not use in production
- Sensitive information: May show file paths
-
Enhanced Local Development
- Ensure the local server is running (
npm start) - Verify that the configured ports are available
- SNS messages are simulated locally with persistence in JSON files
- Data persists between server restarts
- Ensure the local server is running (
-
Webhooks System
- Automatic webhooks use:
http://127.0.0.1:4000/dev/webhook/{topicName} - Notifications are saved in
.serverless/offline-notifications.json - You can view received notifications with
/list-notifications
- Automatic webhooks use:
-
Data Persistence
- Topics:
.serverless/offline-topics.json - Subscriptions:
.serverless/offline-subscriptions.json - Notifications:
.serverless/offline-notifications.json - Files are created automatically when using endpoints
- Topics:
-
Debugging and Monitoring Endpoints
/debug-topics: Full state of topics with statistics/debug-subscriptions: Full state of subscriptions with grouping/list-all-subscriptions: All subscriptions with filtering and statistics/list-subscription-topic: Subscriptions for a specific topic/list-notifications: Received notifications with filtering- Only available in offline mode
- Useful for troubleshooting and monitoring
-
Enhanced Error Handling
- Common error codes:
- 400: Bad Request (invalid data, topic does not exist)
- 401: Unauthorized (invalid API Key)
- 404: Not Found (resource not found)
- 500: Internal Server Error
- More descriptive error messages
- List of available topics in errors
- Common error codes:
-
Validations
- Check for topic existence before subscribing
- Validate input parameters
- Prevent duplicate topics
-
Recommended Workflow
- Create topic with
/create-manual-topic - Verify with
/list-topicsor/debug-topics - Subscribe with
/subscribe-topic - Verify subscription with
/list-subscription-topic/{topicName}or/list-all-subscriptions - Publish message with
/publish-topic - View notifications with
/list-notifications
- Create topic with
-
Limitations in Local Development
- Email subscriptions do not send real emails
- ARNs are simulated but consistent
- Notifications are simulated but saved for debugging
- HTTP webhooks function completely
3.1) References 🔝
View
- Serverless Framework Documentation
- AWS SNS Documentation
- AWS SDK for JavaScript v3
- AWS Lambda Documentation
- API Gateway Documentation
- Tutorial aws-sdk v2
- Amazon Simple Notification Service (SNS) JavaScript SDK v3 code examples
- Serverless Framework Examples
- AWS SNS Best Practices
- Serverless Offline Plugin
- Postman Documentation
- Node.js Documentation
- AWS CloudFormation Documentation
- AWS Systems Manager Parameter Store
- Serverless Framework Forum
- AWS Developer Forums
- Stack Overflow - Serverless Framework
- GitHub Issues - Serverless Framework
