Frequently Asked Questions
Create a NestJS application with the Infobip SDK (@infobip-api/sdk) and configure an API endpoint to accept recipient phone numbers and a message. The Infobip service will handle sending the messages via the Infobip API using the provided credentials. You can manage these credentials and application settings through .env files for security and maintainability. The API Gateway returns a response back to the client with a BulkId for tracking purposes.
The Infobip Node.js SDK (`@infobip-api/sdk`) simplifies interaction with the Infobip API. It provides methods to send SMS messages and manage other communication channels, abstracting away the complexities of direct API calls. Use the official SDK for ease of integration and better maintenance.
NestJS provides a robust, structured framework with features like dependency injection, validation, and modularity, resulting in a more maintainable and scalable application. It accelerates development and handles automatic validation, and has structured logging for monitoring.
Consider a message queue like BullMQ for high-volume SMS broadcasting. Queues handle asynchronous processing, ensuring your API remains responsive while messages are sent in the background. This decoupling enhances reliability, especially for very large recipient lists.
Yes, the provided code allows for a custom sender ID. Pass the desired sender ID in the request payload alongside the recipients and message. If no custom ID is provided, a default sender ID is used from the configuration. This is particularly helpful for branding and recognition.
Store your Infobip API key, base URL, and sender ID in a .env file in your project's root directory. Use the @nestjs/config package to load these variables into your NestJS application securely. Avoid hardcoding these sensitive credentials directly in your code. Add this file to your .gitignore.
Rate limiting, implemented with @nestjs/throttler, prevents abuse and protects your application from excessive requests. The provided code limits requests to 10 per minute per IP by default, preventing overload and ensuring service availability.
The system implements error handling for various scenarios: validation errors (400), rate limiting (429), configuration errors (500), and Infobip API errors (502). `p-retry` automatically retries failed calls to the Infobip API with exponential backoff, and logs error details for debugging purposes.
The project utilizes NestJS, Infobip API with its Node.js SDK, TypeScript, dotenv, class-validator, class-transformer, @nestjs/throttler, Winston/NestJS Logger, helmet, and p-retry. This comprehensive stack ensures robustness, security, and maintainability.
The example code uses the 'p-retry' library for retry logic. This handles transient errors gracefully. Failed Infobip API calls are automatically retried a certain number of times with increasing delays between attempts, enhancing the reliability of message delivery. You should inspect error responses, especially the response code or error type, to determine whether to initiate a retry.
The BroadcastController receives requests at the /broadcast endpoint, validates them, and passes the data to the InfobipService. It also handles rate limiting and returns the appropriate response to the client, including error handling.
While not implemented in the basic guide, a database is crucial for production. PostgreSQL or MySQL are recommended, along with an ORM like Prisma or TypeORM to manage and track broadcast history, recipient statuses, delivery reports, and other data persistently.
The provided code uses `@IsPhoneNumber` from `class-validator`, which offers a basic level of validation. For comprehensive validation across all regions and formats, consider a dedicated library like `libphonenumber-js` combined with a custom validator to enforce E.164 compliance. This ensures accurate and reliable delivery.
You need Node.js (LTS), npm or yarn, an active Infobip account, and basic understanding of TypeScript, Node.js, and NestJS. After installing required dependencies and setting up your environment variables, configure the core modules, specifically app.module.ts, then update your main application file (main.ts). Ensure CORS is enabled if needed, and apply automatic request validation based on data transfer objects (DTOs).
A successful response returns a 202 Accepted status code with a JSON body containing a success message and the bulkId provided by Infobip. This bulkId allows tracking the status and delivery reports of the sent messages. The client can utilize this ID for further inquiries and management.
This guide provides a complete walkthrough for building a robust bulk SMS broadcasting service using NestJS and the Infobip API. We will create a backend application capable of accepting lists of phone numbers and a message, then efficiently dispatching these messages via Infobip's communication platform.
This solution addresses the need for applications to send notifications, alerts, or marketing messages to multiple recipients simultaneously, leveraging Infobip's scalable infrastructure. We'll focus on creating a reliable, maintainable, and secure service suitable for production environments.
Prerequisites:
curl
, Postman)Technology Stack:
@infobip-api/sdk
): Provides the interface to Infobip's SMS sending capabilities. We use the official SDK for ease of integration.@nestjs/config
: For managing environment variables securely.class-validator
/class-transformer
: For robust request data validation.@nestjs/throttler
: For rate limiting API requests.nestjs-pino
: For structured logging.helmet
: For basic security headers.p-retry
: For implementing retry logic on API calls.System Architecture:
(Note: A graphical diagram illustrating this flow is recommended.)
The system involves a client (like Postman or another application) sending a POST request to the
/broadcast
endpoint of the NestJS API Gateway (specifically, theBroadcastController
). This controller validates the request and calls theInfobipService
. TheInfobipService
handles the core logic, using the Infobip Node.js SDK (@infobip-api/sdk
) to interact with the external Infobip API, which ultimately sends the SMS messages. Configuration is managed via.env
files loaded by@nestjs/config
, and various dependencies like validation, rate limiting, security headers, and retry mechanisms support the core functionality. The API Gateway returns a response (e.g., 202 Accepted with abulkId
) back to the client.Final Outcome:
By the end of this guide, you will have a NestJS application with a single API endpoint (
POST /broadcast
) that:bulkId
provided by Infobip for tracking purposes.1. Setting up the Project
Let's initialize our NestJS project and install the necessary dependencies.
Install NestJS CLI (if you haven't already):
Create a new NestJS project:
Choose your preferred package manager (npm or yarn) when prompted.
Navigate into the project directory:
Install required dependencies:
@infobip-api/sdk
: The official Infobip SDK for Node.js.@nestjs/config
: For managing environment variables (integrates well withdotenv
).@nestjs/throttler
: For implementing rate limiting.class-validator
&class-transformer
: Peer dependencies for@nestjs/common
's built-inValidationPipe
.helmet
: Middleware for setting security-related HTTP headers.p-retry
: Utility for retrying asynchronous operations.dotenv
: Loads environment variables from a.env
file.Set up Environment Variables: Create a
.env
file in the project root for your Infobip credentials and application settings. Never commit this file to version control.Also, create a
.env.example
file to track required variables:Add
.env
to your.gitignore
file if it's not already there.Configure Core Modules (
app.module.ts
): Updatesrc/app.module.ts
to import and configure theConfigModule
andThrottlerModule
.ConfigModule.forRoot({ isGlobal: true, envFilePath: '.env' })
: Loads variables from.env
and makesConfigService
available everywhere without needing to importConfigModule
in other modules.ThrottlerModule.forRoot(...)
: Sets up default rate limiting rules. We allow 10 requests per minute per IP address. This protects our API from abuse.{ provide: APP_GUARD, useClass: ThrottlerGuard }
: Applies the rate limiting guard globally.Update Main Application File (
main.ts
): Modifysrc/main.ts
to enable theValidationPipe
globally, usehelmet
, enable CORS, and use the configured port.app.get(ConfigService)
: Retrieves theConfigService
instance.configService.get<number>('PORT', 3000)
: Gets thePORT
environment variable, defaulting to 3000.app.use(helmet())
: Adds various HTTP headers to improve security (e.g., X-Frame-Options, HSTS). We installedhelmet
in Step 4.app.enableCors()
: Enables Cross-Origin Resource Sharing. Configure appropriately for your frontend's origin in production.app.useGlobalPipes(new ValidationPipe(...))
: Enables automatic request validation based on DTOs decorated withclass-validator
. This is crucial for API robustness.2. Implementing Core Functionality (Infobip Service)
We'll encapsulate the Infobip SDK interaction within a dedicated NestJS service.
Generate the Infobip Module and Service:
This creates
src/infobip/infobip.module.ts
andsrc/infobip/infobip.service.ts
. The--no-spec
flag skips generating test files for now.Implement the
InfobipService
: Editsrc/infobip/infobip.service.ts
.Infobip
client using credentials fromConfigService
.sendBulkSms
Method:destinations
format[{ to: string }_ ...]
.this.infobipClient.channels.sms.send
call withinpRetry
for resilience against transient errors.BadGatewayException
if the call fails after all retries.Update the
InfobipModule
: Make sure theInfobipService
is provided and exported.3. Building the API Layer (Broadcast Controller)
Now_ let's create the API endpoint.
Generate the Broadcast Module and Controller:
Create a Data Transfer Object (DTO) for Validation: Create
src/broadcast/dto/create-broadcast.dto.ts
. (Optional: For Swagger documentation_ install@nestjs/swagger swagger-ui-express
and configure it inmain.ts
)class-validator
decorators (@IsArray
_@IsString
_@IsNotEmpty
_@ArrayMinSize
_@IsPhoneNumber
_@IsOptional
).@IsPhoneNumber
: Provides basic validation. See Section 6 for more on robust validation.@IsOptional
: MakessenderId
optional.@ApiProperty
: Added for potential Swagger integration.Implement the
BroadcastController
: Editsrc/broadcast/broadcast.controller.ts
.@Controller('broadcast')
: Defines the base route.@Post()
: Handles POST requests.@HttpCode(HttpStatus.ACCEPTED)
: Sets default success status to 202.@Throttle(...)
: Overrides global rate limit for this endpoint.@Body() createBroadcastDto: CreateBroadcastDto
: Validates the request body using the DTO and globalValidationPipe
.InfobipService
.infobipService.sendBulkSms
.bulkId
on success.Update the
BroadcastModule
: ImportInfobipModule
.Testing the API Endpoint: Start the application:
Use
curl
or Postman:Using
curl
: (Replace placeholders)Expected Success Response (202 Accepted):
Example Validation Error Response (400 Bad Request): (If sending invalid data_ e.g._ missing
message
)4. Integrating with Infobip (Details & Configuration)
Recap of the integration specifics handled in
InfobipService
.Obtaining Credentials:
xxxxx.api.infobip.com
).INFOBIP_SENDER_ID
. Ensure it's registered/approved if needed. Free trials often have restrictions.Environment Variables: Ensure these are correctly set in
.env
:INFOBIP_BASE_URL
INFOBIP_API_KEY
INFOBIP_SENDER_ID
Secure Handling:
.env
locally (add to.gitignore
).Fallback Mechanisms (Retry):
InfobipService
now usesp-retry
to automatically retry failed API calls (due to network issues or temporary Infobip 5xx errors) with exponential backoff.opossum
) could be added for prolonged outages, preventing repeated calls to a known-failing service.5. Error Handling, Logging, and Retry Mechanisms
Robustness is key.
Error Handling Strategy:
ValidationPipe
.@nestjs/throttler
.InfobipService
constructor.InfobipService
after retries, logged, and rethrown asBadGatewayException
.Logging:
Logger
(@nestjs/common
). Logs info, errors, warnings, debug, verbose messages.nestjs-pino
for JSON logs compatible with aggregation systems (Datadog, Splunk, ELK).new Logger(...)
calls with dependency injection or ensure the global logger is used correctly.Retry Mechanisms:
InfobipService
usingp-retry
(installed in Section 1, used in Section 2).6. Database Schema and Data Layer (Recommendation)
While not implemented here, persistence is crucial for production.
Why a Database? Track broadcast history, statuses, manage recipients, schedule messages, store delivery reports (via webhooks).
Recommendation: Use PostgreSQL/MySQL with Prisma or TypeORM.
Conceptual Prisma Schema:
Implementation: Integrate Prisma/TypeORM into NestJS, create a service to handle database operations (create broadcast record, update statuses), and call this service from the
BroadcastController
and potentially a webhook handler for delivery reports. This is beyond the scope of this initial guide but essential for a complete solution. Consider using a message queue (like BullMQ) for large broadcasts to decouple API requests from database writes and Infobip calls.