Subscription API
Relevant source files - config/upstash.js - controllers/subscription.controller.js - routes/subscription.routes.js
The Subscription API provides a comprehensive set of endpoints for managing recurring service commitments. It handles the full lifecycle of a subscription, from creation and automated workflow triggering to specialized queries for upcoming renewals.
API Architecture and Data Flow
The Subscription API is implemented using the Express.js Router pattern, delegating logic to a specialized controller. A critical feature of this API is its integration with an external workflow engine (Upstash) to manage asynchronous reminder logic.
Subscription Lifecycle Diagram
This diagram maps the natural language "Subscription Lifecycle" to the specific code entities responsible for each phase.
[Flowchart Diagram]
Sources:routes/subscription.routes.js82controllers/subscription.controller.js5-31config/upstash.js4-7
Endpoint Definitions
The API is served under the /api/v1/subscriptions prefix.
| Method | Path | Controller Function | Auth Required | Description |
|---|---|---|---|---|
| POST | / |
createSubscription |
Yes | Creates a record and triggers a reminder workflow. |
| GET | / |
getAllSubscriptions |
No | Retrieves all subscriptions in the system. |
| GET | /:id |
getSubscription |
No | Retrieves a single subscription by its MongoDB ID. |
| PUT | /:id |
updateSubscription |
No | Updates subscription details with validation. |
| DELETE | /:id |
deleteSubscription |
No | Removes a subscription record. |
| GET | /user/:id |
getUserSubscriptions |
Yes | Lists all subscriptions belonging to a specific user. |
| GET | /:id/cancel |
cancelSubscription |
No | Sets the subscription status to 'canceled'. |
| GET | /upcoming-renewals |
getUpcomingRenewals |
No | Queries for active subscriptions nearing renewal. |
Sources:routes/subscription.routes.js14-195
Key Implementation Details
Subscription Creation and Workflow Triggering
When createSubscription is invoked, the system performs two primary actions:
- Persistence: It saves the subscription to MongoDB, automatically associating it with the authenticated user's ID (
req.user._id) controllers/subscription.controller.js7-10 - Workflow Trigger: It calls
workflowClient.trigger()to initiate an asynchronous reminder sequence controllers/subscription.controller.js22-31
The trigger sends the subscriptionId to the workflow endpoint defined by the SERVER_URL. Notably, retries is set to 0 to prevent duplicate workflow runs for the same subscription controllers/subscription.controller.js30
Ownership and Authorization
The getUserSubscriptions endpoint implements an ownership check. It compares the id provided in the URL parameters with the id of the authenticated user stored in req.usercontrollers/subscription.controller.js47-51 If they do not match, it throws a 401 Unauthorized error.
Advanced Query Patterns
The getUpcomingRenewals function utilizes Mongoose/MongoDB operators to filter records controllers/subscription.controller.js152-162:
- $gt (Greater Than): Used on the
renewalDatefield to find subscriptions that expire in the future relative to the current timestamp (now) controllers/subscription.controller.js156 - $in (In Array): Used on the
statusfield to ensure only "active" or "pending" subscriptions are returned, excluding "canceled" or "expired" ones controllers/subscription.controller.js157
Sources:controllers/subscription.controller.js45-62controllers/subscription.controller.js152-166
Data Interaction Model
The following diagram illustrates how the subscription.controller.js interacts with the Subscription model and the workflowClient.
sequenceDiagram
participant Client
participant Controller as subscription.controller.js
participant Model as subscription.model.js
participant Upstash as workflowClient (config/upstash.js)
Client->>Controller: POST /api/v1/subscriptions
Controller->>Model: .create(req.body + user._id)
Model-->>Controller: subscription object
Controller->>Upstash: .trigger(workflowUrl, subscriptionId)
Upstash-->>Controller: workflowRunId
Controller-->>Client: 201 Created (subscription + workflowRunId)
Sources:controllers/subscription.controller.js5-38config/upstash.js4-7
Update and Deletion Logic
- Update: The
updateSubscriptionfunction uses{ new: true, runValidators: true }to ensure the returned document is the updated version and that all Mongoose schema validations are applied during the update controllers/subscription.controller.js95-99 - Cancellation: Unlike deletion,
cancelSubscriptionis a soft-update that only modifies thestatusfield to"canceled"controllers/subscription.controller.js133-136
Sources:controllers/subscription.controller.js93-112controllers/subscription.controller.js131-150