652 lines
16 KiB
Markdown
652 lines
16 KiB
Markdown
|
|
# API Usage Flow Guide
|
||
|
|
|
||
|
|
## Overview
|
||
|
|
|
||
|
|
This document provides detailed workflows for different user types and common scenarios in the Attune Heart Therapy API system.
|
||
|
|
|
||
|
|
## User Types and Flows
|
||
|
|
|
||
|
|
### 1. Client User Flow (Regular Users)
|
||
|
|
|
||
|
|
#### A. New User Registration & First Booking
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
sequenceDiagram
|
||
|
|
participant C as Client
|
||
|
|
participant API as API Server
|
||
|
|
participant DB as Database
|
||
|
|
participant Stripe as Stripe
|
||
|
|
participant Jitsi as Jitsi
|
||
|
|
|
||
|
|
C->>API: POST /api/auth/register
|
||
|
|
API->>DB: Create user record
|
||
|
|
API->>C: User created successfully
|
||
|
|
|
||
|
|
C->>API: POST /api/auth/login
|
||
|
|
API->>DB: Validate credentials
|
||
|
|
API->>C: JWT token + user info
|
||
|
|
|
||
|
|
C->>API: GET /api/schedules?date=2024-12-15
|
||
|
|
API->>DB: Query available slots
|
||
|
|
API->>C: Available time slots
|
||
|
|
|
||
|
|
C->>API: POST /api/bookings (with JWT)
|
||
|
|
API->>DB: Create booking record
|
||
|
|
API->>Jitsi: Generate room details
|
||
|
|
API->>C: Booking created + room info
|
||
|
|
|
||
|
|
C->>API: POST /api/payments/intent (with JWT)
|
||
|
|
API->>Stripe: Create payment intent
|
||
|
|
API->>C: Payment intent + client secret
|
||
|
|
|
||
|
|
C->>Stripe: Process payment (frontend)
|
||
|
|
Stripe->>API: POST /api/payments/webhook
|
||
|
|
API->>DB: Update booking payment status
|
||
|
|
|
||
|
|
C->>API: POST /api/payments/confirm (with JWT)
|
||
|
|
API->>Stripe: Confirm payment
|
||
|
|
API->>DB: Update booking status
|
||
|
|
API->>C: Payment confirmed
|
||
|
|
```
|
||
|
|
|
||
|
|
**Step-by-step breakdown:**
|
||
|
|
|
||
|
|
1. **Registration** (`POST /api/auth/register`)
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"first_name": "Sarah",
|
||
|
|
"last_name": "Johnson",
|
||
|
|
"email": "sarah.johnson@email.com",
|
||
|
|
"phone": "+1234567890",
|
||
|
|
"location": "New York, NY",
|
||
|
|
"password": "securePassword123"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
2. **Login** (`POST /api/auth/login`)
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"email": "sarah.johnson@email.com",
|
||
|
|
"password": "securePassword123"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
*Store the returned JWT token for subsequent requests*
|
||
|
|
|
||
|
|
3. **Browse Available Slots** (`GET /api/schedules?date=2024-12-15`)
|
||
|
|
*No authentication required - public endpoint*
|
||
|
|
|
||
|
|
4. **Create Booking** (`POST /api/bookings`)
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"schedule_id": 5,
|
||
|
|
"duration": 60,
|
||
|
|
"notes": "First therapy session - anxiety management"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
*Requires JWT token in Authorization header*
|
||
|
|
|
||
|
|
5. **Process Payment** (`POST /api/payments/intent`)
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"amount": 15000,
|
||
|
|
"currency": "usd"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
*Amount in cents ($150.00)*
|
||
|
|
|
||
|
|
6. **Confirm Payment** (`POST /api/payments/confirm`)
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"payment_intent_id": "pi_1234567890abcdef"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### B. Returning User Flow
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
sequenceDiagram
|
||
|
|
participant C as Client
|
||
|
|
participant API as API Server
|
||
|
|
participant DB as Database
|
||
|
|
|
||
|
|
C->>API: POST /api/auth/login
|
||
|
|
API->>C: JWT token
|
||
|
|
|
||
|
|
C->>API: GET /api/bookings (with JWT)
|
||
|
|
API->>DB: Get user's bookings
|
||
|
|
API->>C: List of bookings
|
||
|
|
|
||
|
|
C->>API: GET /api/auth/profile (with JWT)
|
||
|
|
API->>C: User profile data
|
||
|
|
|
||
|
|
alt Update Profile
|
||
|
|
C->>API: PUT /api/auth/profile (with JWT)
|
||
|
|
API->>DB: Update user data
|
||
|
|
API->>C: Updated profile
|
||
|
|
end
|
||
|
|
|
||
|
|
alt Cancel Booking
|
||
|
|
C->>API: PUT /api/bookings/123/cancel (with JWT)
|
||
|
|
API->>DB: Update booking status
|
||
|
|
API->>C: Booking cancelled
|
||
|
|
end
|
||
|
|
|
||
|
|
alt Reschedule Booking
|
||
|
|
C->>API: PUT /api/bookings/123/reschedule (with JWT)
|
||
|
|
API->>DB: Update booking schedule
|
||
|
|
API->>C: Booking rescheduled
|
||
|
|
end
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Admin User Flow
|
||
|
|
|
||
|
|
#### A. Admin Dashboard & Management
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
sequenceDiagram
|
||
|
|
participant A as Admin
|
||
|
|
participant API as API Server
|
||
|
|
participant DB as Database
|
||
|
|
|
||
|
|
A->>API: POST /api/auth/login (admin credentials)
|
||
|
|
API->>A: JWT token (with admin privileges)
|
||
|
|
|
||
|
|
A->>API: GET /api/admin/dashboard (with admin JWT)
|
||
|
|
API->>DB: Aggregate statistics
|
||
|
|
API->>A: Dashboard stats
|
||
|
|
|
||
|
|
A->>API: POST /api/admin/schedules (with admin JWT)
|
||
|
|
API->>DB: Create schedule slots
|
||
|
|
API->>A: Schedule created
|
||
|
|
|
||
|
|
A->>API: GET /api/admin/users?limit=50&offset=0
|
||
|
|
API->>DB: Query users with pagination
|
||
|
|
API->>A: User list
|
||
|
|
|
||
|
|
A->>API: GET /api/admin/bookings?limit=50&offset=0
|
||
|
|
API->>DB: Query all bookings
|
||
|
|
API->>A: Booking list
|
||
|
|
|
||
|
|
A->>API: GET /api/admin/reports/financial?start_date=2024-01-01&end_date=2024-12-31
|
||
|
|
API->>DB: Generate financial report
|
||
|
|
API->>A: Financial data
|
||
|
|
```
|
||
|
|
|
||
|
|
#### B. Schedule Management Flow
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
sequenceDiagram
|
||
|
|
participant A as Admin
|
||
|
|
participant API as API Server
|
||
|
|
participant DB as Database
|
||
|
|
|
||
|
|
Note over A,DB: Creating Weekly Schedule
|
||
|
|
|
||
|
|
loop For each day of the week
|
||
|
|
A->>API: POST /api/admin/schedules
|
||
|
|
Note right of A: Create morning slot (9:00-10:00)
|
||
|
|
API->>DB: Insert schedule record
|
||
|
|
|
||
|
|
A->>API: POST /api/admin/schedules
|
||
|
|
Note right of A: Create afternoon slot (14:00-15:00)
|
||
|
|
API->>DB: Insert schedule record
|
||
|
|
|
||
|
|
A->>API: POST /api/admin/schedules
|
||
|
|
Note right of A: Create evening slot (18:00-19:00)
|
||
|
|
API->>DB: Insert schedule record
|
||
|
|
end
|
||
|
|
|
||
|
|
A->>API: GET /api/schedules?date=2024-12-15
|
||
|
|
API->>A: Verify created slots are available
|
||
|
|
```
|
||
|
|
|
||
|
|
## Common Integration Patterns
|
||
|
|
|
||
|
|
### 1. Frontend Application Integration
|
||
|
|
|
||
|
|
#### React/Vue.js Example Flow
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
// 1. Authentication Service
|
||
|
|
class AuthService {
|
||
|
|
async login(email, password) {
|
||
|
|
const response = await fetch('/api/auth/login', {
|
||
|
|
method: 'POST',
|
||
|
|
headers: { 'Content-Type': 'application/json' },
|
||
|
|
body: JSON.stringify({ email, password })
|
||
|
|
});
|
||
|
|
|
||
|
|
const data = await response.json();
|
||
|
|
if (data.token) {
|
||
|
|
localStorage.setItem('authToken', data.token);
|
||
|
|
localStorage.setItem('user', JSON.stringify(data.user));
|
||
|
|
}
|
||
|
|
return data;
|
||
|
|
}
|
||
|
|
|
||
|
|
getAuthHeader() {
|
||
|
|
const token = localStorage.getItem('authToken');
|
||
|
|
return token ? { 'Authorization': `Bearer ${token}` } : {};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 2. Booking Service
|
||
|
|
class BookingService {
|
||
|
|
constructor(authService) {
|
||
|
|
this.authService = authService;
|
||
|
|
}
|
||
|
|
|
||
|
|
async getAvailableSlots(date) {
|
||
|
|
const response = await fetch(`/api/schedules?date=${date}`);
|
||
|
|
return response.json();
|
||
|
|
}
|
||
|
|
|
||
|
|
async createBooking(scheduleId, duration, notes) {
|
||
|
|
const response = await fetch('/api/bookings', {
|
||
|
|
method: 'POST',
|
||
|
|
headers: {
|
||
|
|
'Content-Type': 'application/json',
|
||
|
|
...this.authService.getAuthHeader()
|
||
|
|
},
|
||
|
|
body: JSON.stringify({
|
||
|
|
schedule_id: scheduleId,
|
||
|
|
duration,
|
||
|
|
notes
|
||
|
|
})
|
||
|
|
});
|
||
|
|
return response.json();
|
||
|
|
}
|
||
|
|
|
||
|
|
async getUserBookings() {
|
||
|
|
const response = await fetch('/api/bookings', {
|
||
|
|
headers: this.authService.getAuthHeader()
|
||
|
|
});
|
||
|
|
return response.json();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 3. Payment Service
|
||
|
|
class PaymentService {
|
||
|
|
constructor(authService) {
|
||
|
|
this.authService = authService;
|
||
|
|
}
|
||
|
|
|
||
|
|
async createPaymentIntent(amount, currency = 'usd') {
|
||
|
|
const response = await fetch('/api/payments/intent', {
|
||
|
|
method: 'POST',
|
||
|
|
headers: {
|
||
|
|
'Content-Type': 'application/json',
|
||
|
|
...this.authService.getAuthHeader()
|
||
|
|
},
|
||
|
|
body: JSON.stringify({ amount, currency })
|
||
|
|
});
|
||
|
|
return response.json();
|
||
|
|
}
|
||
|
|
|
||
|
|
async confirmPayment(paymentIntentId) {
|
||
|
|
const response = await fetch('/api/payments/confirm', {
|
||
|
|
method: 'POST',
|
||
|
|
headers: {
|
||
|
|
'Content-Type': 'application/json',
|
||
|
|
...this.authService.getAuthHeader()
|
||
|
|
},
|
||
|
|
body: JSON.stringify({ payment_intent_id: paymentIntentId })
|
||
|
|
});
|
||
|
|
return response.json();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Mobile Application Integration
|
||
|
|
|
||
|
|
#### React Native Example
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
// API Client with automatic token management
|
||
|
|
class APIClient {
|
||
|
|
constructor() {
|
||
|
|
this.baseURL = 'http://localhost:8080';
|
||
|
|
this.token = null;
|
||
|
|
}
|
||
|
|
|
||
|
|
async setToken(token) {
|
||
|
|
this.token = token;
|
||
|
|
await AsyncStorage.setItem('authToken', token);
|
||
|
|
}
|
||
|
|
|
||
|
|
async getToken() {
|
||
|
|
if (!this.token) {
|
||
|
|
this.token = await AsyncStorage.getItem('authToken');
|
||
|
|
}
|
||
|
|
return this.token;
|
||
|
|
}
|
||
|
|
|
||
|
|
async request(endpoint, options = {}) {
|
||
|
|
const token = await this.getToken();
|
||
|
|
const headers = {
|
||
|
|
'Content-Type': 'application/json',
|
||
|
|
...(token && { 'Authorization': `Bearer ${token}` }),
|
||
|
|
...options.headers
|
||
|
|
};
|
||
|
|
|
||
|
|
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
||
|
|
...options,
|
||
|
|
headers
|
||
|
|
});
|
||
|
|
|
||
|
|
if (response.status === 401) {
|
||
|
|
// Token expired, redirect to login
|
||
|
|
await AsyncStorage.removeItem('authToken');
|
||
|
|
this.token = null;
|
||
|
|
// Navigate to login screen
|
||
|
|
}
|
||
|
|
|
||
|
|
return response.json();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Error Handling Patterns
|
||
|
|
|
||
|
|
### 1. Client-Side Error Handling
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
class APIErrorHandler {
|
||
|
|
static handle(error, response) {
|
||
|
|
switch (response.status) {
|
||
|
|
case 400:
|
||
|
|
return { type: 'VALIDATION_ERROR', message: error.details || error.error };
|
||
|
|
case 401:
|
||
|
|
return { type: 'AUTH_ERROR', message: 'Please login again' };
|
||
|
|
case 403:
|
||
|
|
return { type: 'PERMISSION_ERROR', message: 'Access denied' };
|
||
|
|
case 409:
|
||
|
|
return { type: 'CONFLICT_ERROR', message: error.error };
|
||
|
|
case 422:
|
||
|
|
return { type: 'PAYMENT_ERROR', message: error.error };
|
||
|
|
case 500:
|
||
|
|
return { type: 'SERVER_ERROR', message: 'Server error, please try again' };
|
||
|
|
default:
|
||
|
|
return { type: 'UNKNOWN_ERROR', message: 'An unexpected error occurred' };
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Usage in service methods
|
||
|
|
async createBooking(data) {
|
||
|
|
try {
|
||
|
|
const response = await fetch('/api/bookings', {
|
||
|
|
method: 'POST',
|
||
|
|
headers: this.getHeaders(),
|
||
|
|
body: JSON.stringify(data)
|
||
|
|
});
|
||
|
|
|
||
|
|
const result = await response.json();
|
||
|
|
|
||
|
|
if (!response.ok) {
|
||
|
|
const error = APIErrorHandler.handle(result, response);
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
} catch (error) {
|
||
|
|
if (error.type) {
|
||
|
|
// Handled API error
|
||
|
|
throw error;
|
||
|
|
} else {
|
||
|
|
// Network or other error
|
||
|
|
throw { type: 'NETWORK_ERROR', message: 'Network error, please check your connection' };
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Retry Logic for Failed Requests
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
class RetryableAPIClient {
|
||
|
|
async requestWithRetry(endpoint, options = {}, maxRetries = 3) {
|
||
|
|
let lastError;
|
||
|
|
|
||
|
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||
|
|
try {
|
||
|
|
const response = await fetch(`${this.baseURL}${endpoint}`, options);
|
||
|
|
|
||
|
|
if (response.ok) {
|
||
|
|
return response.json();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Don't retry client errors (4xx)
|
||
|
|
if (response.status >= 400 && response.status < 500) {
|
||
|
|
throw await response.json();
|
||
|
|
}
|
||
|
|
|
||
|
|
lastError = await response.json();
|
||
|
|
|
||
|
|
if (attempt < maxRetries) {
|
||
|
|
// Exponential backoff
|
||
|
|
await new Promise(resolve =>
|
||
|
|
setTimeout(resolve, Math.pow(2, attempt) * 1000)
|
||
|
|
);
|
||
|
|
}
|
||
|
|
} catch (error) {
|
||
|
|
lastError = error;
|
||
|
|
|
||
|
|
if (attempt < maxRetries && this.isRetryableError(error)) {
|
||
|
|
await new Promise(resolve =>
|
||
|
|
setTimeout(resolve, Math.pow(2, attempt) * 1000)
|
||
|
|
);
|
||
|
|
} else {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
throw lastError;
|
||
|
|
}
|
||
|
|
|
||
|
|
isRetryableError(error) {
|
||
|
|
return error.code === 'NETWORK_ERROR' ||
|
||
|
|
error.code === 'TIMEOUT' ||
|
||
|
|
(error.status >= 500);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Testing Workflows
|
||
|
|
|
||
|
|
### 1. Postman Collection Testing Flow
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
// Collection-level pre-request script
|
||
|
|
pm.collectionVariables.set("baseUrl", "http://localhost:8080");
|
||
|
|
|
||
|
|
// Test script for login request
|
||
|
|
if (pm.response.code === 200) {
|
||
|
|
const response = pm.response.json();
|
||
|
|
pm.collectionVariables.set("authToken", response.token);
|
||
|
|
pm.collectionVariables.set("userId", response.user.id);
|
||
|
|
|
||
|
|
pm.test("Login successful", function () {
|
||
|
|
pm.expect(response.token).to.not.be.empty;
|
||
|
|
pm.expect(response.user.email).to.not.be.empty;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test script for booking creation
|
||
|
|
if (pm.response.code === 201) {
|
||
|
|
const response = pm.response.json();
|
||
|
|
pm.collectionVariables.set("bookingId", response.booking.id);
|
||
|
|
|
||
|
|
pm.test("Booking created successfully", function () {
|
||
|
|
pm.expect(response.booking.id).to.be.a('number');
|
||
|
|
pm.expect(response.booking.jitsi_room_url).to.not.be.empty;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Automated Testing Sequence
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Run the complete user journey
|
||
|
|
newman run "Attune Heart Therapy API.postman_collection.json" \
|
||
|
|
-e "Local Environment.postman_environment.json" \
|
||
|
|
--folder "Authentication" \
|
||
|
|
--folder "Schedules & Bookings" \
|
||
|
|
--folder "Payments" \
|
||
|
|
--reporters cli,json \
|
||
|
|
--reporter-json-export results.json
|
||
|
|
```
|
||
|
|
|
||
|
|
## Performance Considerations
|
||
|
|
|
||
|
|
### 1. Caching Strategy
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
// Client-side caching for available slots
|
||
|
|
class CachedBookingService {
|
||
|
|
constructor() {
|
||
|
|
this.cache = new Map();
|
||
|
|
this.cacheTimeout = 5 * 60 * 1000; // 5 minutes
|
||
|
|
}
|
||
|
|
|
||
|
|
async getAvailableSlots(date) {
|
||
|
|
const cacheKey = `slots_${date}`;
|
||
|
|
const cached = this.cache.get(cacheKey);
|
||
|
|
|
||
|
|
if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
|
||
|
|
return cached.data;
|
||
|
|
}
|
||
|
|
|
||
|
|
const data = await this.fetchAvailableSlots(date);
|
||
|
|
this.cache.set(cacheKey, {
|
||
|
|
data,
|
||
|
|
timestamp: Date.now()
|
||
|
|
});
|
||
|
|
|
||
|
|
return data;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Pagination Handling
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
// Efficient pagination for admin endpoints
|
||
|
|
class PaginatedDataService {
|
||
|
|
async getAllUsers(pageSize = 50) {
|
||
|
|
let allUsers = [];
|
||
|
|
let offset = 0;
|
||
|
|
let hasMore = true;
|
||
|
|
|
||
|
|
while (hasMore) {
|
||
|
|
const response = await fetch(
|
||
|
|
`/api/admin/users?limit=${pageSize}&offset=${offset}`,
|
||
|
|
{ headers: this.getAuthHeaders() }
|
||
|
|
);
|
||
|
|
|
||
|
|
const data = await response.json();
|
||
|
|
allUsers = [...allUsers, ...data.users];
|
||
|
|
|
||
|
|
hasMore = data.users.length === pageSize;
|
||
|
|
offset += pageSize;
|
||
|
|
}
|
||
|
|
|
||
|
|
return allUsers;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Security Best Practices
|
||
|
|
|
||
|
|
### 1. Token Management
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
// Secure token storage and refresh
|
||
|
|
class SecureAuthService {
|
||
|
|
constructor() {
|
||
|
|
this.tokenRefreshThreshold = 5 * 60 * 1000; // 5 minutes before expiry
|
||
|
|
}
|
||
|
|
|
||
|
|
async getValidToken() {
|
||
|
|
const token = localStorage.getItem('authToken');
|
||
|
|
const tokenExpiry = localStorage.getItem('tokenExpiry');
|
||
|
|
|
||
|
|
if (!token || !tokenExpiry) {
|
||
|
|
throw new Error('No valid token found');
|
||
|
|
}
|
||
|
|
|
||
|
|
const expiryTime = new Date(tokenExpiry).getTime();
|
||
|
|
const now = Date.now();
|
||
|
|
|
||
|
|
if (now >= expiryTime - this.tokenRefreshThreshold) {
|
||
|
|
// Token is about to expire, refresh it
|
||
|
|
await this.refreshToken();
|
||
|
|
return localStorage.getItem('authToken');
|
||
|
|
}
|
||
|
|
|
||
|
|
return token;
|
||
|
|
}
|
||
|
|
|
||
|
|
async refreshToken() {
|
||
|
|
// Implement token refresh logic
|
||
|
|
// This would require a refresh token endpoint
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Input Validation
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
// Client-side validation before API calls
|
||
|
|
class ValidationService {
|
||
|
|
static validateBookingData(data) {
|
||
|
|
const errors = [];
|
||
|
|
|
||
|
|
if (!data.schedule_id || !Number.isInteger(data.schedule_id)) {
|
||
|
|
errors.push('Valid schedule ID is required');
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!data.duration || data.duration < 15 || data.duration > 480) {
|
||
|
|
errors.push('Duration must be between 15 and 480 minutes');
|
||
|
|
}
|
||
|
|
|
||
|
|
if (data.notes && data.notes.length > 1000) {
|
||
|
|
errors.push('Notes cannot exceed 1000 characters');
|
||
|
|
}
|
||
|
|
|
||
|
|
return {
|
||
|
|
isValid: errors.length === 0,
|
||
|
|
errors
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
static validateUserRegistration(data) {
|
||
|
|
const errors = [];
|
||
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||
|
|
|
||
|
|
if (!data.first_name || data.first_name.length < 2) {
|
||
|
|
errors.push('First name must be at least 2 characters');
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!data.last_name || data.last_name.length < 2) {
|
||
|
|
errors.push('Last name must be at least 2 characters');
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!data.email || !emailRegex.test(data.email)) {
|
||
|
|
errors.push('Valid email address is required');
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!data.password || data.password.length < 8) {
|
||
|
|
errors.push('Password must be at least 8 characters');
|
||
|
|
}
|
||
|
|
|
||
|
|
return {
|
||
|
|
isValid: errors.length === 0,
|
||
|
|
errors
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
This comprehensive flow guide should help developers understand how to integrate with your API effectively and handle various scenarios that may arise during implementation.
|