Frequently Asked Questions
Integrate the Vonage SMS API into your RedwoodJS application. This involves setting up a backend GraphQL endpoint to handle SMS details, a service function using the Vonage Server SDK, and frontend elements for user input. The provided step-by-step guide outlines the complete process.
The Vonage SMS API, a robust Communication Platform as a Service (CPaaS), enables sending and receiving SMS messages globally. It's known for reliability, scalability, and easy-to-use SDKs, making it ideal for various communication needs.
RedwoodJS offers a full-stack, serverless-first framework with integrated API and web sides, simplifying development. Its opinionated structure, generators, and built-in components like forms and cells enhance developer experience.
Always use environment variables for sensitive information like API keys. Store your Vonage API Key, API Secret, and Sender ID in a `.env` file. This crucial security practice keeps credentials out of your source code.
The Vonage SMS API supports sending messages globally. Ensure the recipient numbers are in E.164 format (e.g., +14155550100). Be mindful of trial account limitations, which may require verifying recipient numbers.
Implement robust error handling in your service function by checking the Vonage API response status. Log errors using Redwood's logger and return informative error messages to the frontend for user feedback.
The RedwoodJS web frontend collects user input and triggers a GraphQL mutation. The backend API resolver calls a service function which uses the Vonage Node.js SDK to send the SMS via the Vonage API, which then delivers the SMS to the recipient.
Install the Vonage Server SDK specifically within the API workspace of your Redwood project using the command `yarn workspace api add @vonage/server-sdk`. This ensures the SDK is correctly placed in your project structure.
You need Node.js (v18.x or 20.x), Yarn (v1.x), the RedwoodJS CLI, a Vonage API account (with API Key, API Secret, and a Vonage phone number), and a basic grasp of JavaScript, React, and command-line interfaces.
Define a `Mutation` type with a `sendSms` field that accepts a `SendSmsInput` object containing `to` (recipient number) and `text` (message content). It should return a `SendSmsResponse` indicating success/failure, message ID, and any errors.
The Sender ID is the "from" number or name displayed to the SMS recipient. It's usually your purchased Vonage virtual number (in E.164 format), but can also be an alphanumeric Sender ID if pre-registered and approved by Vonage.
Store your Vonage API Key and API Secret as environment variables in a `.env` file at your project's root. RedwoodJS automatically loads these during development. This practice is essential for preventing accidental exposure of sensitive information.
While Prisma is part of the RedwoodJS stack, this initial tutorial doesn't utilize complex database interactions. However, Prisma can be used later to store SMS campaign details, logs, or user information, enhancing project functionality.
Create a new RedwoodJS project using `yarn create redwood-app `. Navigate to the project directory, install the Vonage Server SDK (`yarn workspace api add @vonage/server-sdk`), and configure your Vonage API credentials in the `.env` file.
Your Vonage API Key and API Secret are available on the Vonage API Dashboard homepage after you sign up for an account. These credentials are essential for authenticating your application with Vonage.
This guide provides a step-by-step walkthrough for integrating the Vonage SMS API into a RedwoodJS application to send SMS messages programmatically. We'll build a simple interface to trigger messages, focusing on a robust backend implementation suitable for marketing campaigns, notifications, or other communication needs.
By the end of this tutorial, you will have a functional RedwoodJS application capable of sending SMS messages via Vonage, complete with essential configurations, error handling, and security considerations. This serves as a solid foundation for building more complex SMS campaign features.
Project Overview and Goals
What We're Building:
Problem Solved:
This project enables developers to programmatically send targeted SMS messages directly from their web application, facilitating communication for:
Technologies Used:
System Architecture:
The flow is straightforward:
send
method to dispatch the SMS message via the Vonage platform.Prerequisites:
npm install -g @redwoodjs/cli
oryarn global add @redwoodjs/cli
).Expected Outcome:
A running RedwoodJS application where you can enter a phone number and message text into a form, click ""Send"", and have an SMS delivered to that number via your Vonage account.
1. Setting up the Project
Let's create the RedwoodJS project and install necessary dependencies.
Step 1: Create RedwoodJS Application
Open your terminal and run the RedwoodJS create command. We'll name our project
redwood-vonage-sms
.Follow the prompts. Choose TypeScript if you prefer, but this guide will use JavaScript for broader accessibility.
Step 2: Navigate to Project Directory
Step 3: Install Vonage Server SDK
The Vonage SDK needs to be installed in the API workspace of your Redwood project.
This command specifically adds the
@vonage/server-sdk
package to theapi/package.json
file and installs it within theapi/node_modules
directory.Step 4: Configure Environment Variables
RedwoodJS uses
.env
files for environment variables. The.env
file is gitignored by default for security.Create a
.env
file in the root of your project:Add your Vonage API credentials and your Vonage sending number to this file.
VONAGE_API_KEY
: Found on your Vonage Dashboard. Purpose: Authenticates your application with Vonage.VONAGE_API_SECRET
: Found on your Vonage Dashboard. Purpose: Authenticates your application with Vonage.VONAGE_SENDER_ID
: One of your purchased Vonage virtual numbers in E.164 format (e.g.,14155550100
). Purpose: The 'From' number displayed to the recipient. In some countries, you might use an Alphanumeric Sender ID if registered and approved by Vonage.Explanation: Using environment variables keeps sensitive credentials out of your source code, which is crucial for security. RedwoodJS automatically loads variables from
.env
during development. For deployment, you'll need to configure these variables in your hosting provider's environment settings.2. Defining the API Layer (GraphQL)
Now, let's define the backend API endpoint using GraphQL.
Step 1: Generate SDL and Service Files
Use the Redwood generator to create the Schema Definition Language (SDL) and service files for SMS functionality:
This command creates:
api/src/graphql/sms.sdl.ts
(or.js
)api/src/services/sms/sms.ts
(or.js
)api/src/services/sms/sms.test.ts
(or.js
)Step 2: Define the GraphQL Schema
Edit
api/src/graphql/sms.sdl.ts
(or.js
) to define thesendSms
mutation:Explanation:
Mutation
type with one field:sendSms
.sendSms
takes a requiredinput
argument of typeSendSmsInput
.SendSmsInput
defines the required fields:to
(recipient) andtext
(message body). Using an input type keeps the mutation arguments organized.sendSms
returns aSendSmsResponse
type.SendSmsResponse
indicatessuccess
(boolean) and provides optionalmessageId
orerror
details.@skipAuth
: For simplicity in this guide, we disable authentication for this mutation. In a real application, you would implement authentication (@requireAuth
) to ensure only authorized users can send SMS.3. Implementing the Service Logic
Now, implement the logic within the service file generated earlier. This function will initialize the Vonage client and call its API.
Edit
api/src/services/sms/sms.ts
(or.js
):Explanation:
Vonage
class from the SDK and Redwood'slogger
.sendSms
function receives theinput
object matching ourSendSmsInput
GraphQL type.to
ortext
. Production apps should have more robust validation (e.g., usingzod
or checking phone number format). Added a comment about considering more specific error types.process.env
. Crucially, it checks if they exist and throws an error if not, preventing the app from trying to operate without proper configuration.Vonage
instance using the API key and secret.logger.info
andlogger.error
to record actions and potential issues. This is invaluable for debugging.vonage.sms.send()
: Call the core SDK function:to
: Recipient number from the input.from
: Your configured Vonage Sender ID from.env
.text
: Message content from the input.send
method returns a response object. We now checkresponseData?.messages?.length > 0
before accessingresponseData.messages[0]
to prevent runtime errors if themessages
array is missing or empty.status
is'0'
, log success and return{ success: true, messageId }
.{ success: false, error }
.try...catch
): Wrap the Vonage call in atry...catch
block. This catches errors thrown by the SDK itself (e.g., invalid credentials recognized by the SDK, network problems connecting to Vonage). Log the error and return{ success: false, error }
.SendSmsResponse
GraphQL type.4. Building the Frontend
Now, let's create a simple page on the web side to interact with our API.
Step 1: Generate the Page
Use the Redwood generator to create a page:
This creates
web/src/pages/SmsSenderPage/SmsSenderPage.js
(or.tsx
) and adds a route inweb/src/Routes.js
(or.tsx
).Step 2: Implement the Page Component
Edit
web/src/pages/SmsSenderPage/SmsSenderPage.js
(or.tsx
):Explanation:
MetaTags
,useMutation
,@redwoodjs/forms
,@redwoodjs/web/toast
). Optionally importlogger
.SEND_SMS_MUTATION
: Define the GraphQL mutation string that matches the one defined in the SDL.useForm
: Initialize Redwood Forms for handling form state and validation.useState
: Track aloading
state for user feedback during submission.useMutation
Hook:SEND_SMS_MUTATION
) as the first argument.onCompleted
: Called when the mutation successfully executes on the server (even if the service logic returnssuccess: false
). It receives the data returned by the mutation (data.sendSms
). We checkdata.sendSms.success
here to show appropriate success/error toasts and reset the form on success.onError
: Called if there's a GraphQL or network-level error preventing the mutation from even reaching the service resolver.[sendSmsFunction, { data, loading, error }]
. We primarily use thesendSmsFunction
to trigger the mutation and theerror
object for displaying API-level errors.onSubmit
Handler:<Form>
component'sonSubmit
prop.data
.loading
to true.sendSms
function returned byuseMutation
, passing the formdata
wrapped in the expected{ variables: { input: data } }
structure.try...catch
as a fallback, thoughonError
usually handles mutation execution errors.<Toaster>
: Component required bytoast
to display notifications.<Form>
Component: Redwood's form wrapper. Takes theonSubmit
handler andformMethods
.Label
,TextField
,TextAreaField
, andFieldError
components for easy form creation and validation display.required
checks and a basicpattern
check for the E.164 format on theto
field.maxLength
is added to thetext
field. Redwood Forms handles displaying errors defined here usingFieldError
.<Submit>
Button: Redwood's submit button component.disabled={loading}
prevents multiple submissions.mutationError
if there's a GraphQL/network error. Service-level errors are handled via toasts inonCompleted
.5. Implementing Proper Error Handling, Logging, and Retry Mechanisms
Error Handling (Covered Above):
useMutation
'sonError
catches GraphQL/network errors.onCompleted
checks thesuccess
flag from the service response for Vonage-specific errors. Toasts provide user feedback.try...catch
blocks handle SDK exceptions (auth, network).responseData.messages[0].status
) handles errors reported by Vonage itself (e.g., invalid number format recognized by Vonage, insufficient funds). The logic was improved for safety (Section 3).{ success, messageId, error }
).ValidationError
,ConfigurationError
,VonageApiError
) instead of genericError
objects for clearer error handling upstream.Logging (Covered Above):
logger
fromsrc/lib/logger
) is used in the service (api/src/services/sms/sms.ts
).logger.info
logs successful attempts and outcomes.logger.error
logs configuration issues, SDK errors, and Vonage API errors, often including the error object itself for detailed stack traces.yarn rw dev
). In production deployments, configure your hosting provider or logging service (e.g., Logflare, Datadog) to capture these logs.Retry Mechanisms:
Implementing retries adds complexity. For SMS, retries should be handled carefully to avoid duplicate messages.
Client-Side Retries: Generally not recommended for actions like sending SMS, as network hiccups could lead to multiple successful submissions if the user retries manually after the first request actually succeeded but the response was lost. Disabling the submit button while
loading
helps prevent this.Server-Side Retries: If the
vonage.sms.send()
call fails due to potentially transient issues (e.g., temporary network error, Vonage rate limit), you could implement a retry strategy within the service function.429 Too Many Requests
from Vonage, which might manifest as status code '1' or '8' depending on context). Do not retry on errors like invalid credentials ('4') or invalid phone numbers ('15'). Consult the Vonage SMS API documentation for the specific meaning of status codes to determine which are truly transient and safe to retry.async-retry
orp-retry
can simplify implementing exponential backoff (waiting progressively longer between retries).async-retry
):6. Creating a Database Schema and Data Layer (Optional Extension)
While not strictly required for sending a single SMS, storing campaign details or message logs is often necessary. RedwoodJS uses Prisma for database interactions.
Step 1: Define Schema
Edit
api/db/schema.prisma
:Step 2: Create Migration
Generate the SQL migration file and apply it to your database:
This creates a migration file in
api/db/migrations
and updates your database schema.Step 3: Update Service to Log
Modify
api/src/services/sms/sms.ts
to use the Prisma client (db
is auto-imported/available in Redwood services) to save a log entry: