Appearance
Nodejs Example
This example demonstrates how to integrate with the Engagifii API using JavaScript.
Code Example
javascript
// Node.js Integration Example for Bill Tracking API
// Complete Express.js application with middleware, error handling, and caching
const express = require('express');
const axios = require('axios');
const NodeCache = require('node-cache');
const rateLimit = require('express-rate-limit');
const helmet = require('helmet');
const morgan = require('morgan');
require('dotenv').config();
// Configuration
const config = {
apiUrl: process.env.BILLTRACKING_API_URL || 'https://engagifii-billtracking.azurewebsites.net',
apiVersion: process.env.BILLTRACKING_API_VERSION || '1.0',
tenantCode: process.env.BILLTRACKING_TENANT_CODE || 'YOUR_TENANT_CODE',
port: process.env.PORT || 3000,
cacheTimeout: parseInt(process.env.CACHE_TIMEOUT) || 300 // 5 minutes
};
// Initialize Express app
const app = express();
// Middleware
app.use(helmet());
app.use(morgan('combined'));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Initialize cache
const cache = new NodeCache({ stdTTL: config.cacheTimeout });
// Rate limiting for our API
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
});
app.use('/api/', limiter);
// Create axios instance for Bill Tracking API
const billTrackingAPI = axios.create({
baseURL: config.apiUrl,
timeout: 30000,
headers: {
'api-version': config.apiVersion,
'tenant-code': config.tenantCode,
'Content-Type': 'application/json'
}
});
// Request interceptor for logging
billTrackingAPI.interceptors.request.use(
request => {
console.log(`API Request: ${request.method?.toUpperCase()} ${request.url}`);
return request;
},
error => {
console.error('Request error:', error);
return Promise.reject(error);
}
);
// Response interceptor for error handling and retry logic
billTrackingAPI.interceptors.response.use(
response => {
console.log(`API Response: ${response.status} ${response.config.url}`);
return response;
},
async error => {
const originalRequest = error.config;
// Retry logic for rate limiting
if (error.response?.status === 429 && !originalRequest._retry) {
originalRequest._retry = true;
const retryAfter = error.response.headers['retry-after'] || 60;
console.warn(`Rate limited. Retrying after ${retryAfter}s`);
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
return billTrackingAPI(originalRequest);
}
// Retry logic for server errors
if (error.response?.status >= 500 && !originalRequest._retry) {
originalRequest._retry = true;
console.warn('Server error. Retrying request...');
await new Promise(resolve => setTimeout(resolve, 2000));
return billTrackingAPI(originalRequest);
}
return Promise.reject(error);
}
);
// API Service Class
class BillTrackingService {
// Get states with caching
async getStates() {
const cacheKey = 'states';
let states = cache.get(cacheKey);
if (!states) {
const response = await billTrackingAPI.get(`/api/${config.apiVersion}/dropdown/states`);
states = response.data;
cache.set(cacheKey, states, 3600); // Cache for 1 hour
}
return states;
}
// Get sessions with optional state filter
async getSessions(stateId = null) {
const cacheKey = `sessions_${stateId || 'all'}`;
let sessions = cache.get(cacheKey);
if (!sessions) {
const params = stateId ? { stateId } : {};
const response = await billTrackingAPI.get(`/api/${config.apiVersion}/dropdown/sessions`, { params });
sessions = response.data;
cache.set(cacheKey, sessions, 1800); // Cache for 30 minutes
}
return sessions;
}
// Get bill calendar events
async getCalendarEvents(filters = {}) {
const defaultFilters = {
startDate: new Date().toISOString().split('T')[0],
endDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString().split('T')[0],
pageNumber: 1,
pageSize: 50,
...filters
};
const response = await billTrackingAPI.post(
`/api/${config.apiVersion}/bill/event/calendar`,
defaultFilters
);
return response.data;
}
// Save activity log
async logActivity(userId, action, entityType, entityId, metadata = {}) {
const logEntry = {
userId,
action,
entityType,
entityId,
metadata,
timestamp: new Date().toISOString()
};
const response = await billTrackingAPI.post(
`/api/${config.apiVersion}/activity/log/save`,
logEntry
);
return response.data;
}
// Get activity logs
async getActivityLogs(filters = {}) {
const defaultFilters = {
pageNumber: 1,
pageSize: 50,
sortBy: 'timestamp',
isAscending: false,
...filters
};
const response = await billTrackingAPI.post(
`/api/${config.apiVersion}/activity/log/list`,
defaultFilters
);
return response.data;
}
// Save campaign template
async saveCampaignTemplate(campaignData) {
const response = await billTrackingAPI.post(
`/api/${config.apiVersion}/Advocacy/saveChampaignTemplate`,
campaignData
);
return response.data;
}
// Get campaign template
async getCampaignTemplate(id) {
const response = await billTrackingAPI.get(
`/api/${config.apiVersion}/Advocacy/getChampaignTemplate/${id}`
);
return response.data;
}
// List campaigns
async listCampaigns(filters = {}) {
const defaultFilters = {
pageNumber: 1,
pageSize: 20,
isActive: true,
...filters
};
const response = await billTrackingAPI.post(
`/api/${config.apiVersion}/Advocacy/list`,
defaultFilters
);
return response.data;
}
// Subscribe to bill events
async subscribeToBillEvents(subscriptions) {
const response = await billTrackingAPI.post(
`/api/${config.apiVersion}/bill/event/subscribe`,
subscriptions
);
return response.data;
}
// Get subscriptions
async getSubscriptions() {
const response = await billTrackingAPI.post(
`/api/${config.apiVersion}/bill/event/Getsubscriptions`
);
return response.data;
}
}
// Initialize service
const billTrackingService = new BillTrackingService();
// Express Routes
// Health check
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
config: {
apiUrl: config.apiUrl,
apiVersion: config.apiVersion,
cacheStats: cache.getStats()
}
});
});
// Get states
app.get('/api/states', async (req, res, next) => {
try {
const states = await billTrackingService.getStates();
res.json({ success: true, data: states });
} catch (error) {
next(error);
}
});
// Get sessions
app.get('/api/sessions', async (req, res, next) => {
try {
const { stateId } = req.query;
const sessions = await billTrackingService.getSessions(stateId);
res.json({ success: true, data: sessions });
} catch (error) {
next(error);
}
});
// Get calendar events
app.post('/api/calendar/events', async (req, res, next) => {
try {
const events = await billTrackingService.getCalendarEvents(req.body);
res.json({ success: true, data: events });
} catch (error) {
next(error);
}
});
// Log activity
app.post('/api/activity/log', async (req, res, next) => {
try {
const { userId, action, entityType, entityId, metadata } = req.body;
const result = await billTrackingService.logActivity(
userId,
action,
entityType,
entityId,
metadata
);
res.json({ success: true, data: result });
} catch (error) {
next(error);
}
});
// Get activity logs
app.post('/api/activity/list', async (req, res, next) => {
try {
const logs = await billTrackingService.getActivityLogs(req.body);
res.json({ success: true, data: logs });
} catch (error) {
next(error);
}
});
// Campaign routes
app.post('/api/campaigns', async (req, res, next) => {
try {
const campaignId = await billTrackingService.saveCampaignTemplate(req.body);
res.json({ success: true, data: { id: campaignId } });
} catch (error) {
next(error);
}
});
app.get('/api/campaigns/:id', async (req, res, next) => {
try {
const campaign = await billTrackingService.getCampaignTemplate(req.params.id);
res.json({ success: true, data: campaign });
} catch (error) {
next(error);
}
});
app.post('/api/campaigns/list', async (req, res, next) => {
try {
const campaigns = await billTrackingService.listCampaigns(req.body);
res.json({ success: true, data: campaigns });
} catch (error) {
next(error);
}
});
// Event subscriptions
app.post('/api/subscriptions', async (req, res, next) => {
try {
const result = await billTrackingService.subscribeToBillEvents(req.body);
res.json({ success: true, data: result });
} catch (error) {
next(error);
}
});
app.get('/api/subscriptions', async (req, res, next) => {
try {
const subscriptions = await billTrackingService.getSubscriptions();
res.json({ success: true, data: subscriptions });
} catch (error) {
next(error);
}
});
// Clear cache endpoint (for admin use)
app.post('/api/cache/clear', (req, res) => {
cache.flushAll();
res.json({ success: true, message: 'Cache cleared successfully' });
});
// Error handling middleware
app.use((err, req, res, next) => {
console.error('Error:', err);
// Handle Axios errors
if (err.response) {
return res.status(err.response.status).json({
success: false,
error: err.response.data?.error || 'API Error',
message: err.response.data?.message || err.message,
details: err.response.data?.details
});
}
// Handle other errors
res.status(500).json({
success: false,
error: 'Internal Server Error',
message: err.message || 'An unexpected error occurred'
});
});
// 404 handler
app.use((req, res) => {
res.status(404).json({
success: false,
error: 'Not Found',
message: `Cannot ${req.method} ${req.url}`
});
});
// Graceful shutdown
process.on('SIGTERM', () => {
console.log('SIGTERM signal received: closing HTTP server');
server.close(() => {
console.log('HTTP server closed');
process.exit(0);
});
});
// Start server
const server = app.listen(config.port, () => {
console.log(`Bill Tracking API Integration Server running on port ${config.port}`);
console.log(`API URL: ${config.apiUrl}`);
console.log(`API Version: ${config.apiVersion}`);
});
module.exports = { app, billTrackingService };Usage Notes
- Make sure to replace placeholder values with your actual API credentials
- Install required dependencies before running this code
- Refer to the main API documentation for detailed endpoint information
Download
Download this example: nodejs-example.js
