Next API Schwab Application
The Next API Schwab application serves as the central API hub for Charles Schwab's web ecosystem, providing internal API services for data synchronization, content management, cache revalidation, and utility functions across multiple applications in the monorepo.
Overview
- Application:
apps/nextapi.schwab.com - Port: 3002
- Version: 1.0.60
- Framework: Next.js 15.3.2 with App Router
- Purpose: Internal API services for non-public facing endpoints
- Architecture: API-only Next.js application with serverless functions
Key Features
- Content Management API: CMAP (Content Management API Portal) integration
- Cache Revalidation: On-demand cache invalidation for content updates
- Health Monitoring: Application health check endpoints
- Environment Synchronization: Deployment webhook handling for environment sync
- Utility Functions: URL building, path resolution, and data transformation
- Drupal Integration: Content fetching from Drupal CMS systems
- Edge Computing: Vercel Edge Config integration for dynamic configuration
Technical Architecture
Framework Stack
| Technology | Version | Purpose |
|---|---|---|
| Next.js | 15.3.2 | React framework with App Router |
| React | 19.1.0 | Component library (minimal usage) |
| TypeScript | 5.8.2 | Type safety and development experience |
| Vercel Edge Config | 1.4.0 | Dynamic configuration management |
| JSON5 | 2.2.3 | Enhanced JSON parsing |
Core Dependencies
{
"@schwab/fetch": "workspace:*",
"@schwab/ui": "workspace:*",
"@schwab/utilities": "workspace:*",
"@schwab/schema": "workspace:*",
"@vercel/edge-config": "^1.4.0",
"cross-env": "^7.0.3",
"json5": "^2.2.3"
}
Monorepo Integration
The application leverages several internal packages:
@schwab/fetch: HTTP client utilities and data fetching functions@schwab/utilities: Common utility functions and logging@schwab/schema: Data validation schemas and enums@schwab/ui: Shared React components (limited usage)
Directory Structure
apps/nextapi.schwab.com/
├── src/
│ ├── app/ # App Router directory (Next.js 13+)
│ │ └── api/ # API route handlers
│ │ ├── cmap/ # Content Management API Portal
│ │ │ └── [...alias]/ # Dynamic CMAP content routes
│ │ ├── health-check/ # Application health monitoring
│ │ ├── sync-lower-environments/ # Deployment webhooks
│ │ └── utils/ # Utility API functions
│ │ ├── build-url-path.ts # URL construction utilities
│ │ └── revalidate-path-tag.ts # Cache revalidation logic
│ └── global/ # Global styles and utilities
│ ├── icons.scss # Icon definitions
│ ├── styles.scss # Global SCSS styles
│ └── windowDataLayer.tsx # Analytics data layer
├── public/ # Static assets
│ ├── fonts/ # Font files
│ ├── ira-poc/ # IRA proof-of-concept assets
│ └── test-img.png # Test images
├── .allowlists/ # Security allowlist configurations
├── next.config.js # Next.js configuration
├── postcss.config.js # PostCSS configuration
└── tsconfig.json # TypeScript configuration
API Endpoint Architecture
Health Check Endpoint
Route: /api/health-check
Method: GET
Purpose: Application health monitoring and version information
export function GET() {
return new Response(JSON.stringify(getAppVersion(packageJSON.name)), {
status: 200,
});
}
Features:
- Dynamic Response: Always fresh, never cached
- Version Info: Returns application version and metadata
- Monitoring Integration: Used by deployment and monitoring systems
Content Management API (CMAP)
Route: /api/cmap/[...alias]
Method: GET
Purpose: Drupal content fetching and transformation
export async function GET(request: NextRequest, props: { params: Promise<{ alias: string[] }> }) {
const params = await props.params;
const pageNodeId = Number(params.alias[3]);
const status = params.alias[1];
const lang = params.alias[2];
const story = await getStory(EDrupalSource.Education, '', pageNodeId, status, lang);
return Response.json(story?.data);
}
Parameters:
alias[1]: Content status (published, draft, etc.)alias[2]: Language code (en, es, zh-CN, etc.)alias[3]: Drupal node ID for content retrieval
Environment Synchronization
Route: /api/sync-lower-environments
Method: POST
Purpose: Webhook handler for deployment synchronization
async function verifySignature(req, payload) {
const signature = crypto
.createHmac('sha1', process.env.WEBHOOK_SECRET)
.update(payload)
.digest('hex');
return signature === req.headers['x-vercel-signature'];
}
Features:
- Webhook Security: HMAC signature verification
- Deployment Tracking: Monitors deployment status across environments
- Team Integration: Vercel team and user identification
Cache Revalidation Utilities
Module: /api/utils/revalidate-path-tag.ts
Purpose: On-demand cache invalidation for content updates
export function revalidateCache(request: NextRequest) {
const path = request.nextUrl.searchParams.get('path');
const revalByPath = isBooleanTrue(request.nextUrl.searchParams.get('revalidatebypath'));
const revalByTag = request.nextUrl.searchParams.get('revalidatebytag');
// Revalidation logic implementation
}
Cache Tags:
- MegaNav Menu Cache: Navigation component cache invalidation
- Utility Nav Cache: Utility navigation updates
- Card Cache: Content card component updates
Development Workflow
Local Development
# Install dependencies
pnpm install
# Start development server on port 3002
pnpm dev
# Build for production
pnpm build
# Start production server
pnpm start
# Type checking
pnpm type-check
# Conformance checking
pnpm conformance
The development server automatically runs on port 3002 with process management to prevent port conflicts.
API Testing
# Health check
curl http://localhost:3002/api/health-check
# CMAP content retrieval
curl http://localhost:3002/api/cmap/education/published/en/12345
# Cache revalidation
curl "http://localhost:3002/api/utils/revalidate?path=/example&revalidatebypath=true"
Configuration Management
Next.js Configuration
The application uses several key configurations:
const nextConfig = {
experimental: {
useCache: true,
},
reactStrictMode: true,
trailingSlash: true,
transpilePackages: [
'@adobe/react-spectrum',
// Additional React Spectrum packages...
],
};
Features:
- Experimental Caching: Enhanced performance with Next.js caching
- React Strict Mode: Development safety and debugging
- Trailing Slash: Consistent URL formatting
- Package Transpilation: Adobe React Spectrum compatibility
Environment Variables
# Webhook security
WEBHOOK_SECRET=your_webhook_secret
# Vercel integration
VERCEL_TOKEN=your_vercel_token
# Additional API configurations
DRUPAL_API_BASE_URL=your_drupal_url
Content Management Integration
Drupal Source Integration
The application integrates with multiple Drupal sources:
Content Flow Architecture
- Content Request: Frontend applications request content via CMAP API
- Drupal Fetching: API fetches content from appropriate Drupal source
- Data Transformation: Content processed and formatted for consumption
- Cache Management: Responses cached with appropriate tags
- Revalidation: Cache invalidated when content updates occur
Security and Performance
Security Measures
- Webhook Verification: HMAC signature validation for webhooks
- Environment Isolation: Secure handling of environment-specific data
- Allowlist Configuration: Defined security boundaries
- Non-Public API: Internal-only endpoints not exposed to public internet
Performance Optimizations
- Next.js 15 Features: Latest performance improvements and caching
- Dynamic Routes: Efficient routing for parameterized endpoints
- Edge Computing: Vercel Edge Config for low-latency configuration
- Cache Strategy: Intelligent caching with tag-based invalidation
API Reference
Health Check API
GET /api/health-check
Content-Type: application/json
Response:
{
"name": "app_nextapi.schwab.com",
"version": "1.0.60",
"timestamp": "2025-01-01T00:00:00Z"
}
CMAP Content API
GET /api/cmap/{source}/{status}/{lang}/{nodeId}
Content-Type: application/json
Parameters:
- source: Content source (education, prospect, etc.)
- status: published | draft | archived
- lang: en | es | zh-CN | zh-TW
- nodeId: Drupal node identifier
Response:
{
"data": {
"title": "Content Title",
"body": "Content body...",
"metadata": { ... }
}
}
Cache Revalidation API
POST /api/utils/revalidate
Content-Type: application/json
Query Parameters:
- path: Content path to revalidate
- revalidatebypath: boolean flag for path-based revalidation
- revalidatebytag: cache tag for tag-based revalidation
Response:
{
"success": true,
"revalidated": ["path1", "path2"],
"timestamp": "2025-01-01T00:00:00Z"
}
Error Handling and Logging
Structured Logging
try {
const story = await getStory(source, '', nodeId, status, lang);
return Response.json(story?.data);
} catch (e: unknown) {
SchLogger.error(e);
return new Response(`Failed to generate response: ${(e as Error).message}`, {
status: 400,
});
}
Features:
- Centralized Logging:
SchLoggerfor consistent log formatting - Error Context: Detailed error messages with request context
- HTTP Status Codes: Appropriate status codes for different error types
- Request Tracking: Request correlation for debugging
Integration Patterns
Monorepo API Consumption
// Frontend application consuming Next API
import { fetchContent } from '@schwab/fetch';
const contentData = await fetchContent('/api/cmap/education/published/en/12345');
Cache Invalidation Workflow
Deployment and Operations
Build Process
- Dependency Resolution: pnpm workspace dependency installation
- TypeScript Compilation: Type checking and JavaScript generation
- Next.js Build: API route compilation and optimization
- Asset Processing: Static asset optimization
- Serverless Functions: Individual API route deployment
Monitoring and Health Checks
- Health Endpoint:
/api/health-checkfor application status - Error Tracking: Centralized error logging and monitoring
- Performance Metrics: API response time and throughput monitoring
- Cache Hit Rates: Cache efficiency tracking
Common Use Cases
Content Synchronization
// Sync content from Drupal to applications
const syncContent = async (nodeId: number, lang: string) => {
const response = await fetch(`/api/cmap/education/published/${lang}/${nodeId}`);
const content = await response.json();
return content;
};
Cache Management
// Revalidate specific content path
const revalidateContent = async (path: string) => {
const response = await fetch(`/api/utils/revalidate?path=${path}&revalidatebypath=true`, {
method: 'POST'
});
return response.json();
};
Troubleshooting
Common Issues
| Issue | Cause | Solution |
|---|---|---|
| Port 3002 in use | Previous API process running | Use kill script in dev command |
| CMAP 404 errors | Invalid node ID or source | Verify Drupal node exists and is published |
| Webhook verification fails | Incorrect WEBHOOK_SECRET | Check environment variable configuration |
| Cache not invalidating | Missing cache tags | Verify revalidation tag configuration |
| TypeScript errors | Schema mismatches | Run pnpm type-check and update schemas |
Development Tips
Use the health check endpoint to verify API availability before running integration tests.
Never expose internal API endpoints to public internet. Use proper authentication and rate limiting for any external access.
Future Enhancements
- GraphQL Integration: Enhanced query capabilities for complex data requirements
- Rate Limiting: API rate limiting and throttling implementation
- Authentication Layer: JWT-based authentication for secure API access
- Metrics Dashboard: Real-time API performance and usage metrics
- Content Preview: Draft content preview capabilities
- Multi-Environment: Enhanced environment-specific configuration management
This Next API application serves as the backbone for Charles Schwab's content management and data synchronization needs, providing reliable, performant, and secure API services across the entire monorepo ecosystem.