Frequently Asked Questions
You can send bulk SMS messages by creating a RedwoodJS application that integrates with AWS SNS. This involves setting up a GraphQL API endpoint connected to a service function that interacts with the AWS SDK. This function handles sending messages in batches to contacts stored in your database.
RedwoodJS is the core framework for building the bulk SMS application. It provides structure, routing, GraphQL API capabilities, and integration with Prisma ORM for database interactions. This simplifies development and provides a cohesive full-stack experience.
AWS SNS is chosen for its scalability and reliability in handling message delivery. It's a fully managed service, meaning AWS handles the infrastructure, allowing developers to focus on application logic. SNS also provides direct SMS sending capabilities.
First, create a new RedwoodJS project using `yarn create redwood-app`. Then, install the necessary AWS SDK modules and configure your database connection in `schema.prisma`. Finally, set up authentication using Redwood's built-in dbAuth and define a GraphQL mutation to trigger the SMS sending process.
Prisma acts as the Object-Relational Mapper (ORM) allowing RedwoodJS to interact with the database. It simplifies database operations by providing a type-safe and easy-to-use API for querying and managing data, such as fetching contact information.
The `PublishBatch` API is ideal for sending messages to multiple recipients simultaneously. This optimizes the sending process and is more efficient than individual API calls for each message. However, keep in mind that SNS limits batch sizes to 10 recipients.
Yes, Prisma supports other databases besides PostgreSQL. You can configure the database connection by editing the `provider` field in your `schema.prisma` file and updating the `DATABASE_URL` environment variable accordingly.
Store your AWS credentials (Access Key ID and Secret Access Key) as environment variables in a `.env` file. RedwoodJS loads these variables automatically in development. Never hardcode credentials directly in your code.
The maximum batch size for the `PublishBatch` API in AWS SNS is 10. The provided code enforces this with a `MAX_BATCH_SIZE` constant. Exceeding this limit will cause errors.
The example code provides error handling at multiple levels: input validation for empty messages, individual message failures within a batch using the SNS response's `Failed` array, batch-level error handling with retries, and overall process errors using try-catch blocks. Ensure logging is configured for monitoring.
The recommended format is E.164, which includes a plus sign (+) followed by the country code, area code, and local number. The code includes a basic regular expression, and Section 8 in the original article was meant to have better validation. For robust validation, consider a dedicated library like libphonenumber-js.
Using dedicated IAM users with limited permissions is crucial for security. It reduces the potential damage from compromised credentials and ensures least privilege access. In production, create custom IAM policies to restrict access only to essential SNS actions (like Publish and PublishBatch).
The dbAuth setup protects the bulk SMS sending functionality. It ensures that only authorized users can access and trigger the GraphQL mutation responsible for sending messages, preventing unauthorized access.
While the code provides a basic regular expression for E.164 validation, consider using a specialized library like libphonenumber-js to enhance this process. A library handles various number formats and provides more accurate validation than regex alone.
Centralizing SNS client initialization in a separate library (`snsClient.js`) improves code organization and modularity. It makes it easier to manage and update the SNS client configuration across your application.
This guide provides a complete walkthrough for building a production-ready bulk SMS broadcasting system using the RedwoodJS framework and Amazon Simple Notification Service (AWS SNS).
We'll build an application that enables authenticated users to send a single message to a list of contacts stored in a database. This solves the common need for businesses to efficiently distribute notifications, alerts, or marketing messages via SMS.
Technologies Used:
System Architecture:
Final Outcome:
By the end of this guide, you will have a RedwoodJS application with:
Prerequisites:
1. Setting up the RedwoodJS Project
Let's initialize a new RedwoodJS project and install necessary dependencies.
Create RedwoodJS App: Open your terminal and run the following command. Choose TypeScript when prompted.
Navigate to Project Directory:
Install AWS SDK v3 for SNS: We need the specific client package for SNS.
Why
@aws-sdk/client-sns
? The AWS SDK v3 is modular. Installing only the SNS client keeps our dependency footprint smaller compared to installing the entire SDK.Setup Database: RedwoodJS uses Prisma. By default, it's configured for SQLite. Let's switch to PostgreSQL (adjust connection string for your setup).
Edit
api/db/schema.prisma
: Change theprovider
in thedatasource
block.Create a
.env
file in the project root (if it doesn't exist) and add your PostgreSQL connection string:Explanation: The
schema.prisma
file defines our database connection and data models. The.env
file stores sensitive information like database credentials, keeping them out of version control.Initial Database Migration: Apply the initial schema setup to your database.
Your basic RedwoodJS project structure is now ready. The
api
directory contains backend code (GraphQL API, services, database schema), and theweb
directory contains frontend code (React components, pages).2. Implementing Core Functionality (Backend Service & SNS Client)
We'll create a reusable SNS client and a service function to handle the logic of sending bulk messages.
Configure AWS Credentials Securely: The AWS SDK needs credentials to interact with your account. We'll use environment variables, which RedwoodJS automatically loads from the
.env
file in development. Never hardcode credentials in your source code.Add the following to your
.env
file (obtain these from your AWS IAM user setup - see Section 4):Explanation: The SDK automatically detects
AWS_ACCESS_KEY_ID
,AWS_SECRET_ACCESS_KEY
, andAWS_REGION
(orAWS_DEFAULT_REGION
) environment variables. Storing them here keeps them secure and environment-specific.Create an SNS Client Library: This centralizes the SNS client initialization.
Create a new file:
api/src/lib/snsClient.js
Explanation: We import the
SNSClient
, instantiate it (optionally passing the region), and export it. The Redwood logger is used for basic initialization feedback.Define the Contact Data Model: We need a way to store the phone numbers we want to message.
Edit
api/db/schema.prisma
and add theContact
model:Explanation: Defines a simple
Contact
table with an ID, an optional name, a unique phone number, and timestamps. Using@unique
onphone
prevents duplicate entries.Apply Database Migration: Create and apply a migration for the new
Contact
model.Generate Contact Scaffolding (Optional but helpful): Redwood can generate basic CRUD operations (Create, Read, Update, Delete) for the
Contact
model. This gives us a service and SDL definitions automatically.api/src/graphql/contacts.sdl.js
(GraphQL schema definitions)api/src/services/contacts/contacts.js
(Service functions for DB interaction)web/src
(we won't focus on the UI here, but they are generated)Create the Messaging Service: This service will contain the core logic for fetching contacts and sending the bulk SMS via SNS.
Generate a new service:
Edit
api/src/services/messaging/messaging.js
:Explanation:
PublishBatchCommand
from AWS SDK,db
for database access,logger
, oursnsClient
, andUserInputError
for GraphQL validation errors.MAX_BATCH_SIZE
(SNS limit is 10 forPublishBatch
).sendBulkSms
function takes themessage
content as input.id
andphone
).E164_REGEX
before adding a number to a batch. Invalid numbers are skipped and logged. (Reminds user about Section 8 for better validation).PublishBatchRequestEntries
for each valid contact in the batch, ensuring a uniqueId
for each entry.PublishBatchCommand
usingsnsClient.send()
.Successful
andFailed
arrays from the SNS response, logging details about failures and updating counters. It attempts to map failure IDs back to phone numbers for better reporting.try...catch
blocks for both individual batch sends and the overall process.requireAuth()
is added (we'll set up auth next).3. Building the API Layer (GraphQL Mutation)
We need a way for the frontend (or external clients) to trigger the
sendBulkSms
service function. We'll use a GraphQL mutation.Define the GraphQL Mutation:
Edit
api/src/graphql/messaging.sdl.js
:Explanation:
SendBulkSmsFailure
type to structure failure details.SendBulkSmsResponse
type to structure the return value of our mutation, including success/failure counts and the detailed failures list.sendBulkSms
mutation within theMutation
type. It accepts a requiredmessage
string.@requireAuth
directive to ensure only authenticated users can call this mutation.Implement Basic Authentication (dbAuth): Redwood makes setting up simple database authentication straightforward.
Run the setup command:
This command:
User
,UserCredential
,UserRole
) toschema.prisma
.api/src/services/users
) and GraphQL definitions (api/src/graphql/users.sdl.js
).api/src/lib/auth.js
).web/src/pages/LoginPage
,web/src/pages/SignupPage
, etc.) and updates routing.Apply Auth Migrations: Run the migration to add the new auth tables to your database.
Create a Test User: You'll need a user to test the authenticated mutation. You can either:
yarn rw dev
) and navigate to the signup page (/signup
) in your browser.yarn rw prisma studio
to add a user directly to the database (remember to hash the password correctly if adding manually, or use the signup page).Link SDL to Service: Redwood automatically maps the
sendBulkSms
mutation inmessaging.sdl.js
to thesendBulkSms
function exported fromapi/src/services/messaging/messaging.js
because the names match. No extra resolver code is needed here.Testing the Mutation (GraphQL Playground):
Start the Redwood development server:
Open your browser to
http://localhost:8911/graphql
.Authentication Header: You need to simulate being logged in.
/login
).auth-provider
header (should bedbAuth
).authorization
header (should beBearer <session-token>
).Execute the Mutation: Run the following mutation in the Playground:
Check the response in the Playground and the logs in your terminal (
yarn rw dev
output) to see the outcome. You should see logs indicating contacts being fetched, batches being sent, and the final result.4. Integrating with AWS SNS (IAM & Setup)
Properly configuring AWS permissions is crucial for security and functionality.
Create an IAM User for Your Application: It's best practice to create a dedicated IAM user with the minimum necessary permissions rather than using your root AWS account credentials.
redwood-sns-app-user
).AmazonSNSFullAccess
policy. Note: For production, create a custom policy granting onlysns:Publish
andsns:PublishBatch
permissions, potentially restricted to specific regions or topics if applicable.AmazonSNSFullAccess
is simpler for this guide but too permissive for production.Generate Access Keys:
redwood-sns-bulk-sms-key
).Add Credentials to
.env
:Open your project's
.env
file.Paste the copied keys into the respective variables:
Restart Development Server: If your dev server (
yarn rw dev
) is running, stop it (Ctrl+C) and restart it to ensure it picks up the new environment variables from.env
.Your application is now configured to authenticate with AWS SNS using the dedicated IAM user's credentials.
5. Implementing Error Handling, Logging, and Retries
Robust error handling and logging are essential for production systems.
Error Handling (Already Implemented):
sendBulkSms
) already includes checks for an empty message (UserInputError
) and basic E.164 phone number format validation.Failed
array in thePublishBatch
response, logs each specific failure, and includes details in the mutation response.try...catch
block insendBulkSms
catches unexpected errors during the process (e.g., database connection issues, SDK client errors).@requireAuth
directive handles unauthorized access attempts.Logging (Already Implemented):
api/src/lib/logger.js
) is used throughout thesendBulkSms
service.api/src/lib/logger.js
. For production, you'd typically set the level toinfo
orwarn
and potentially log to a file or a log aggregation service.Retry Mechanisms:
SNS Internal Retries: AWS SNS itself has built-in retry mechanisms for transient delivery issues when sending SMS messages. You generally don't need to implement complex retry logic for the final delivery attempt from SNS to the carrier.
Application-Level Retries (for
PublishBatch
): ThePublishBatch
API call itself might fail due to transient network issues or AWS throttling. Our current code logs batch errors but doesn't automatically retry the entire batch.Implementing Retries (Optional Enhancement): To add retries for failed
PublishBatch
calls, you could wrap thesnsClient.send(command)
call within a loop with exponential backoff:Consideration: Adding retries increases complexity. Evaluate if the potential benefits outweigh the added code, especially given SNS's own reliability. For critical messages, retrying might be necessary. Also consider idempotency if retrying.
6. Creating Database Schema and Data Layer
This was largely covered during the setup and core functionality implementation.
Schema Definition (
api/db/schema.prisma
): We defined theContact
model and thedbAuth
models.Data Access Layer:
db
object imported fromsrc/lib/db
provides typed access to your database models.messaging.js
:await db.contact.findMany(...)
contacts
service (api/src/services/contacts/contacts.js
) generated by the scaffold command provides standard CRUD operations.Migrations:
yarn rw prisma migrate dev
to apply schema changes. This command:schema.prisma
file to the database state.api/db/migrations
.yarn rw prisma migrate deploy
.Sample Data Population (Seeding): To easily add test contacts, you can use Prisma's seeding feature.
Create a seed file:
api/db/seed.js
Run the seed command (this automatically runs after
migrate dev
or can be run manually):7. Adding Security Features
Security is paramount, especially when dealing with potentially sensitive contact information and incurring costs via AWS services.