Frequently Asked Questions
Use RedwoodJS's GraphQL API, integrated with the Sinch SMS API, to schedule and send SMS reminders. Create a Redwood service that interacts with both the Sinch API and your database to manage reminder scheduling and data storage. Build a frontend form in RedwoodJS to collect user input and trigger the reminder scheduling process via the GraphQL API.
The Sinch SMS API enables your RedwoodJS application to send SMS messages. It handles the complexities of SMS delivery, allowing you to focus on application logic. Specifically, the 'send_at' feature allows scheduling SMS messages for future delivery without managing background jobs within RedwoodJS itself.
RedwoodJS offers a full-stack, serverless-friendly framework that simplifies development by providing integrated frontend (React), backend (GraphQL API, Prisma), and database access. This structure makes it easier to handle user interactions, data management, and external API integrations like Sinch.
Luxon is highly beneficial when working with dates and times, especially when dealing with different time zones. It's used to parse, manipulate, and format dates/times accurately in your RedwoodJS application, avoiding common time zone issues. In this SMS reminder app, Luxon ensures accurate calculation of the reminder time based on the user's specified time zone and converts it to UTC for consistent storage and Sinch API interaction.
Yes, you can use SQLite for local development and simpler projects. RedwoodJS defaults to SQLite and handles the basic setup automatically if you use provider = "sqlite" in your schema.prisma file. For production environments, PostgreSQL is generally recommended for its scalability and robustness, requiring you to configure the DATABASE_URL environment variable appropriately.
RedwoodJS uses .env files for environment variables. Create a .env file in your project's root directory and add your sensitive information, such as API keys and database URLs. Ensure .env is added to .gitignore to prevent committing secrets to version control.
Prisma acts as an Object-Relational Mapper (ORM) for your database. It simplifies database interactions by allowing you to work with data using JavaScript objects and methods. In this application, Prisma facilitates storing and retrieving reminder details like patient name, appointment time, and phone number.
The user interacts with a React frontend, which communicates with a GraphQL API. The API interacts with a Redwood service that handles logic, using Prisma to manage data in a database (PostgreSQL/SQLite) and the Sinch API to schedule SMS messages. Sinch sends the SMS at the designated time.
You need Node.js (v20 or higher recommended), Yarn v1, a Sinch account (with API credentials and a provisioned number), access to a terminal, and basic understanding of JavaScript, React, GraphQL, and databases.
The Sinch SMS API expects times in UTC for the send_at parameter. Use a library like Luxon to convert user-provided times (along with their time zone) into UTC before passing to the Sinch API. Ensure your database also stores all DateTime fields in UTC for consistency.
Define a 'Reminder' model in your api/db/schema.prisma file specifying fields like patientName, phoneNumber, appointmentTime, reminderTime, and status. Use appropriate data types and consider an index on status and reminderTime for efficient querying.
The 'PENDING' status indicates that an SMS reminder has been scheduled but has not yet been sent by Sinch. Other status options could be SENT or FAILED for enhanced tracking and reporting.
E.164 is an international standard format for phone numbers (e.g., +15551234567) that ensures consistency and compatibility with global communication systems. Using E.164 simplifies validation and reduces ambiguity when sending SMS messages internationally.
Implement try...catch blocks around API calls and database operations to handle potential errors gracefully. Log errors using Redwood's logger and provide user feedback through toasts or other notification mechanisms. Consider retry mechanisms for API calls and compensation logic for database errors to enhance robustness.
This guide provides a step-by-step walkthrough for building a RedwoodJS application capable of scheduling and sending SMS reminders using the Sinch SMS API. We'll create a simple appointment reminder system where users can input appointment details, and the application will automatically schedule an SMS reminder to be sent via Sinch at a specified time before the appointment.
This solves the common need for automated, time-sensitive notifications without requiring complex background job infrastructure within the application itself, leveraging Sinch's built-in scheduling capabilities.
Key Technologies:
send_at
feature for scheduling.System Architecture:
The system follows this general data flow:
Prerequisites:
Final Outcome:
A RedwoodJS application with a simple UI to schedule appointment reminders. The backend will validate input, store appointment details, and use the Sinch Node SDK to schedule an SMS to be sent 2 hours before the scheduled appointment time.
1. Setting up the RedwoodJS Project
Let's initialize a new RedwoodJS project and configure the necessary environment.
Create Redwood App: Open your terminal and navigate to the directory where you want to create your project. Run the following command, replacing
<your-app-name>
with your desired project name (e.g.,redwood-sinch-reminders
):--typescript
for enhanced type safety, which is recommended for production applications.yes
(recommended)Initial commit
(or your preferred message)yes
Navigate to Project Directory:
Install Additional Dependencies: We need the Sinch SDK and
luxon
for robust date/time manipulation.@sinch/sdk-core
: The official Sinch Node.js SDK.luxon
: A powerful library for handling dates, times, and time zones.Environment Variable Setup: Redwood uses
.env
files for environment variables. The Sinch SDK requires credentials. Create a.env
file in the root of your project:Add the following variables to your
.env
file, replacing the placeholder values with your actual Sinch credentials and configuration:SINCH_KEY_ID
,SINCH_KEY_SECRET
,SINCH_PROJECT_ID
: Find these in your Sinch Dashboard under your project's API credentials/Access Keys section. TreatSINCH_KEY_SECRET
like a password – never commit it to Git.SINCH_FROM_NUMBER
: A virtual number you've acquired through Sinch, enabled for SMS, and associated with your Project ID. Must be in E.164 format (e.g.,+12025550187
).SINCH_SMS_REGION
: The regional endpoint for the Sinch API (e.g.,us
,eu
). Use the region closest to your user base or where your account is homed. This is essential for the SDK to connect to the correct API endpoint.DEFAULT_COUNTRY_CODE
: Used as a fallback if the user enters a local number format. It's best practice to require E.164 format input.Add
.env
to.gitignore
: Ensure your.env
file (containing secrets) is not committed to version control. Open your project's root.gitignore
file and add.env
if it's not already present.Initial Commit (if not done during creation): If you didn't initialize Git during
create redwood-app
:2. Creating the Database Schema and Data Layer
We need a database table to store the details of the scheduled reminders.
Define Prisma Schema: Open
api/db/schema.prisma
and define a model forReminder
:DateTime
fields should ideally be stored in UTC to avoid time zone issues.status
tracks the state of the reminder (PENDING
means scheduled but not yet sent).sinchBatchId
can be useful for tracking the message status within Sinch later.status
andreminderTime
could be useful for querying pending jobs or cleanup tasks.Set up Database Connection: Ensure your
DATABASE_URL
in the.env
file points to your database (e.g.,postgresql://user:password@host:port/database
). For local development, Redwood defaults to SQLite, which requires no extra setup if you stick with the defaultprovider = ""sqlite""
.Run Database Migration: Apply the schema changes to your database:
schema.prisma
changes and applies it to your development database. Provide a name for the migration when prompted (e.g.,create reminder model
).3. Implementing Core Functionality (Reminder Service)
Now, let's create the RedwoodJS service that handles the logic for scheduling reminders.
Generate Service Files: Use the Redwood generator to create the necessary service and GraphQL files:
This creates:
api/src/services/reminders/reminders.ts
(Service logic)api/src/services/reminders/reminders.scenarios.ts
(Seed data for testing)api/src/services/reminders/reminders.test.ts
(Unit tests)api/src/graphql/reminders.sdl.ts
(GraphQL schema definition)Implement the
scheduleReminder
Service Function: Openapi/src/services/reminders/reminders.ts
and add the logic to create a reminder record and schedule the SMS via Sinch.validate
and custom logic for the phone number and date/time. The phone number normalization explicitly notes its limitations and recommendslibphonenumber-js
for production.luxon
to parse the input date/time with the provided time zone_ calculate the reminder time_ and convert both to UTC for storage and the API call. Crucially validates that the reminder time is in the future.sinchClient.sms.batches.send
method (we'll definesinchClient
next).send_at
: Passes the calculatedreminderTimeUtc
in ISO 8601 format to Sinch'ssend_at
parameter.'PENDING'
and thesinchBatchId
.try...catch
blocks. The database error handling after a successful Sinch call has been enhanced with stronger warnings and suggestions for compensation logic.Create Sinch Client Library: It's good practice to centralize the Sinch SDK client initialization.
Create a new file:
api/src/lib/sinch.ts
SinchClient
using the environment variables.SINCH_SMS_REGION
environment variable for correct API endpoint targeting and advises checking Sinch SDK docs for the specific mechanism if needed.4. Building the API Layer (GraphQL)
Define the GraphQL mutation to expose the
scheduleReminder
service function.Define GraphQL Schema: Open
api/src/graphql/reminders.sdl.ts
. Redwood generators created a basic structure. Modify it to define theScheduleReminderInput
and thescheduleReminder
mutation.!
marks fields as required.Reminder
type that mirrors our Prisma model and will be returned by the mutation on success.scheduleReminder
mutation_ taking the input and returning aReminder
.@requireAuth
: Initially added by the generator. It has been removed here for easier initial testing. Important: Removing authentication is only for initial development convenience. You MUST re-enable or implement proper authentication before deploying to any non-local environment.Testing the API Endpoint: Once the development server is running (
yarn rw dev
)_ you can test the mutation using the Redwood GraphQL Playground (usually athttp://localhost:8911/graphql
) or a tool likecurl
or Postman.GraphQL Playground Mutation:
Curl Example:
appointmentDate
andappointmentTime
result in areminderTime
(2 hours prior) that is in the future from when you run the test.Reminder
record.yarn rw dev
output) for logs from the service function.5. Implementing the Frontend UI (Basic Form)
Let's create a simple React page with a form to schedule reminders.
Generate Page: Create a new page component for the reminder form.
This creates
web/src/pages/ReminderSchedulerPage/ReminderSchedulerPage.tsx
.Build the Form: Open
web/src/pages/ReminderSchedulerPage/ReminderSchedulerPage.tsx
and implement the form using Redwood Form components.useMutation
hook to call thescheduleReminder
GraphQL mutation.<Form>
,<TextField>
,<DateField>
,<TimeField>
,<SelectField>
,<Submit>
,<FieldError>
,<FormError>
) for structure, validation, and error handling.required
,pattern
). More complex validation happens in the service.Toaster
for displaying success/error messages.<SelectField>
for selecting the appointment's time zone, crucial for correct calculation. It attempts to default to the user's browser time zone.Add Route: Ensure the route is defined in
web/src/Routes.tsx
:Run and Test: Start the development server:
Navigate to
http://localhost:8910/schedule
(or your configured port). Fill out the form with valid data (ensure the appointment is far enough in the future) and submit. Check the browser console, API server logs, and Sinch dashboard for confirmation. You should receive the SMS 2 hours before the specified appointment time.6. Error Handling, Logging, and Retries
FieldError
andFormError
,useMutation
'sonError
callback, andtoast
notifications.try...catch
blocks around critical operations (validation, date/time parsing, API calls, database writes). Includes specific error messages and logs errors using Redwood's logger. Highlights the critical failure case where the SMS is scheduled but the database write fails, suggesting robust compensation logic for production.logger
on the API side (src/lib/logger.ts
). Logs key events like receiving requests, preparing data, successful API calls, database writes, and errors. Avoid logging sensitive data likeSINCH_KEY_SECRET
.async-retry
) for transient network errors when calling the Sinch API. For database write failures after successful scheduling, implement compensation logic (as mentioned in the service code comments) or a background job to reconcile states. Consider using a message queue for more robust job handling.