A professional REST API that provides access to U.S. Department of State Travel Advisories with comprehensive documentation, rate limiting, and caching capabilities.
- Real-time Data: Fetches live travel advisory data from the official U.S. Department of State RSS feed
- Rate Limiting: Configurable rate limiting to prevent abuse
- Caching: Intelligent caching system to reduce external API calls and improve performance
- Professional Documentation: Complete OpenAPI/Swagger documentation
- Type Safety: Full TypeScript support with comprehensive type definitions
- Error Handling: Robust error handling with detailed logging
- Security: Helmet.js security headers, CORS configuration, and input validation
- Health Monitoring: Built-in health check endpoints
- Pagination: Efficient pagination for large datasets
- Quick Start
- API Documentation
- API Endpoints
- PowerShell Usage Examples
- Configuration
- Rate Limiting
- Caching
- Error Handling
- Development
- Testing
- Deployment
- Quick Reference
- Contributing
- License
- Node.js 18+ and npm
- TypeScript 5.0+
- Clone the repository:
git clone <repository-url>
cd travel-advisory-api- Install dependencies:
npm install- Set up environment variables:
cp env.example .env
# Edit .env with your configuration- Start the development server:
npm run dev- Build for production:
npm run build
npm startThe API will be available at http://localhost:3000
Visit http://localhost:3000/api-docs for the complete interactive API documentation powered by Swagger UI.
GET /healthReturns the health status of the API.
Response:
{
"success": true,
"message": "Travel Advisory API is healthy",
"timestamp": "2025-09-09T00:15:28.100Z",
"version": "1.0.0",
"uptime": 123.45,
"requestId": "req_1634567890123_abc123"
}GET /healthReturns the health status of the API including uptime and version information.
Example:
curl -X GET "http://localhost:3000/health"GET /api/countriesReturns a comprehensive list of all countries with their codes and current advisory levels.
Response:
{
"success": true,
"data": {
"countries": [
{
"name": "Armenia",
"code": "AM",
"level": "Level 2: Exercise Increased Caution"
},
{
"name": "Belarus",
"code": "BY",
"level": "Level 4: Do Not Travel"
}
]
},
"message": "Found 211 countries with travel advisories",
"timestamp": "2025-09-09T00:15:28.100Z",
"requestId": "req_1634567890123_abc123"
}Example:
curl -X GET "http://localhost:3000/api/countries"GET /api/rawReturns simplified travel advisory data for all countries with essential information only.
Query Parameters:
limit(integer): Number of results (default: 100)
Response:
{
"success": true,
"data": [
{
"country": "Armenia",
"countryCode": "AM",
"level": "Level 2: Exercise Increased Caution",
"levelNumber": 2,
"title": "Armenia - Level 2: Exercise Increased Caution",
"summary": "Exercise increased caution in Armenia due to areas of potential armed conflict.",
"restrictions": [],
"recommendations": [
"Enroll in the Smart Traveler Enrollment Program (STEP)",
"Review the Country Security Report"
],
"link": "https://travel.state.gov/content/travel/en/traveladvisories/traveladvisories/armenia-travel-advisory.html",
"lastUpdated": "2025-09-08T23:30:08.000Z"
}
],
"message": "Raw data for 211 countries",
"timestamp": "2025-09-09T00:15:28.100Z",
"requestId": "req_1634567890123_abc123"
}Example:
curl -X GET "http://localhost:3000/api/raw?limit=50"GET /api/advisoriesReturns all travel advisories with optional filtering, sorting, and pagination.
Query Parameters:
level(string): Filter by threat level (e.g., "4", "Level 2", "Do Not Travel")country(string): Filter by country namecountryCode(string): Filter by country code (e.g., "US", "CA")limit(integer): Number of results (default: 50, max: 100)offset(integer): Pagination offset (default: 0)sortBy(string): Sort field (pubDate,country,level) - default:pubDatesortOrder(string): Sort order (asc,desc) - default:desc
Response:
{
"success": true,
"data": [
{
"id": "abc123def456",
"country": "Armenia",
"countryCode": "AM",
"title": "Armenia - Level 2: Exercise Increased Caution",
"level": "Level 2: Exercise Increased Caution",
"levelNumber": 2,
"link": "https://travel.state.gov/content/travel/en/traveladvisories/traveladvisories/armenia-travel-advisory.html",
"pubDate": "2025-09-08T23:30:08.000Z",
"description": "Full HTML description...",
"summary": "Brief summary...",
"restrictions": ["Border region restrictions"],
"recommendations": ["STEP enrollment", "Security report review"],
"lastUpdated": "2025-09-08T23:30:08.000Z"
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 211,
"totalPages": 5,
"hasNext": true,
"hasPrev": false
},
"timestamp": "2025-09-09T00:15:28.100Z",
"requestId": "req_1634567890123_abc123"
}Examples:
# Get all advisories
curl -X GET "http://localhost:3000/api/advisories"
# Filter by threat level 4
curl -X GET "http://localhost:3000/api/advisories?level=4"
# Filter by country and limit results
curl -X GET "http://localhost:3000/api/advisories?country=Armenia&limit=1"
# Sort by country name
curl -X GET "http://localhost:3000/api/advisories?sortBy=country&sortOrder=asc"GET /api/advisories/{country}Returns travel advisory information for a specific country.
Path Parameters:
country(string): Country name or country code (case-insensitive)
Response:
{
"success": true,
"data": {
"id": "abc123def456",
"country": "Armenia",
"countryCode": "AM",
"title": "Armenia - Level 2: Exercise Increased Caution",
"level": "Level 2: Exercise Increased Caution",
"levelNumber": 2,
"link": "https://travel.state.gov/content/travel/en/traveladvisories/traveladvisories/armenia-travel-advisory.html",
"pubDate": "2025-09-08T23:30:08.000Z",
"description": "Full HTML description...",
"summary": "Brief summary...",
"restrictions": ["Border region restrictions"],
"recommendations": ["STEP enrollment", "Security report review"],
"lastUpdated": "2025-09-08T23:30:08.000Z"
},
"message": "Advisory found for Armenia",
"timestamp": "2025-09-09T00:15:28.100Z",
"requestId": "req_1634567890123_abc123"
}Examples:
# By country name
curl -X GET "http://localhost:3000/api/advisories/Armenia"
# By country code
curl -X GET "http://localhost:3000/api/advisories/US"
# Case insensitive
curl -X GET "http://localhost:3000/api/advisories/armenia"GET /api/advisories/level/{level}Returns all travel advisories for a specific threat level.
Path Parameters:
level(string): Threat level number (1-4) or description
Response:
{
"success": true,
"data": [
{
"id": "abc123def456",
"country": "Armenia",
"countryCode": "AM",
"title": "Armenia - Level 2: Exercise Increased Caution",
"level": "Level 2: Exercise Increased Caution",
"levelNumber": 2,
"link": "https://travel.state.gov/content/travel/en/traveladvisories/traveladvisories/armenia-travel-advisory.html",
"pubDate": "2025-09-08T23:30:08.000Z",
"description": "Full HTML description...",
"summary": "Brief summary...",
"restrictions": ["Border region restrictions"],
"recommendations": ["STEP enrollment", "Security report review"],
"lastUpdated": "2025-09-08T23:30:08.000Z"
}
],
"message": "Found 45 advisories with level containing '2'",
"timestamp": "2025-09-09T00:15:28.100Z",
"requestId": "req_1634567890123_abc123"
}Examples:
# By level number
curl -X GET "http://localhost:3000/api/advisories/level/4"
# By level description
curl -X GET "http://localhost:3000/api/advisories/level/Do%20Not%20Travel"GET /api/cache/statsReturns information about the current cache state and performance statistics.
Response:
{
"success": true,
"data": {
"keys": ["travel_advisories", "last_updated"],
"hits": 150,
"misses": 5,
"ksize": 2,
"vsize": 45632,
"lastUpdated": "2025-09-08T23:30:08.000Z",
"remainingTTL": 1800,
"isDataStale": false
},
"message": "Cache statistics retrieved successfully",
"timestamp": "2025-09-09T00:15:28.100Z",
"requestId": "req_1634567890123_abc123"
}Example:
curl -X GET "http://localhost:3000/api/cache/stats"POST /api/cache/refreshForces a refresh of the travel advisory cache by fetching fresh data from the RSS feed.
Response:
{
"success": true,
"data": true,
"message": "Cache refreshed successfully with 211 advisories",
"timestamp": "2025-09-09T00:15:28.100Z",
"requestId": "req_1634567890123_abc123"
}Example:
curl -X POST "http://localhost:3000/api/cache/refresh"GET /api-docsInteractive API documentation powered by Swagger UI.
GET /api-docs.jsonReturns the OpenAPI specification in JSON format.
Since this API is often used in Windows environments, here are PowerShell examples for common operations:
Invoke-WebRequest -Uri "http://localhost:3000/api/countries" -UseBasicParsing | Select-Object -ExpandProperty Content | ConvertFrom-Json | Select-Object -ExpandProperty data | Select-Object -ExpandProperty countriesInvoke-WebRequest -Uri "http://localhost:3000/api/advisories/Armenia" -UseBasicParsing | Select-Object -ExpandProperty Content | ConvertFrom-Json | Select-Object -ExpandProperty dataInvoke-WebRequest -Uri "http://localhost:3000/api/advisories?level=4&limit=5" -UseBasicParsing | Select-Object -ExpandProperty Content | ConvertFrom-Json | Select-Object -ExpandProperty dataInvoke-WebRequest -Uri "http://localhost:3000/api/raw?limit=10" -UseBasicParsing | Select-Object -ExpandProperty Content | ConvertFrom-Json | Select-Object -ExpandProperty data | Select-Object country, level, levelNumberInvoke-WebRequest -Uri "http://localhost:3000/api/cache/stats" -UseBasicParsing | Select-Object -ExpandProperty Content | ConvertFrom-Json | Select-Object -ExpandProperty dataInvoke-WebRequest -Uri "http://localhost:3000/api/cache/refresh" -Method POST -UseBasicParsing | Select-Object -ExpandProperty Content | ConvertFrom-Json$advisories = Invoke-WebRequest -Uri "http://localhost:3000/api/advisories" -UseBasicParsing | Select-Object -ExpandProperty Content | ConvertFrom-Json
$advisories.data | Where-Object { $_.levelNumber -eq 4 } | Select-Object country, level | Format-Table -AutoSize| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
Server port |
NODE_ENV |
development |
Environment mode |
RATE_LIMIT_WINDOW_MS |
900000 |
Rate limit window in milliseconds (15 minutes) |
RATE_LIMIT_MAX_REQUESTS |
100 |
Max requests per window |
CACHE_RATE_LIMIT_MAX |
10 |
Max cache refresh requests per hour |
CORS_ORIGIN |
http://localhost:3000,http://localhost:8080 |
Allowed CORS origins |
LOG_LEVEL |
info |
Logging level |
REQUEST_TIMEOUT |
30000 |
Request timeout in milliseconds |
PORT=3000
NODE_ENV=development
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=100
CACHE_RATE_LIMIT_MAX=10
CORS_ORIGIN=http://localhost:3000,http://localhost:8080
LOG_LEVEL=info
REQUEST_TIMEOUT=30000The API implements multiple layers of rate limiting:
- Window: 15 minutes
- Max Requests: 100 per IP
- Headers: Includes
X-RateLimit-*headers
- Window: 1 hour
- Max Requests: 10 per IP
- Endpoints:
/api/cache/*
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 99
X-RateLimit-Reset: 1634567890The API uses an intelligent caching system:
- Cache Duration: 30 minutes
- Auto-refresh: Automatically fetches fresh data when cache expires
- Memory-based: Uses Node.js memory for fast access
- Statistics: Available via
/api/cache/stats
{
"success": true,
"data": {
"keys": ["travel_advisories", "last_updated"],
"hits": 150,
"misses": 5,
"ksize": 2,
"vsize": 45632,
"lastUpdated": "2025-09-08T23:30:08.000Z",
"remainingTTL": 1800,
"isDataStale": false
}
}The API provides comprehensive error handling:
{
"success": false,
"error": "Error message",
"code": "ERROR_CODE",
"timestamp": "2025-09-08T23:30:08.000Z",
"requestId": "req_1634567890123_abc123"
}VALIDATION_ERROR: Input validation failedNOT_FOUND: Resource not foundRATE_LIMIT_EXCEEDED: Rate limit exceededEXTERNAL_SERVICE_ERROR: RSS feed unavailableINTERNAL_ERROR: Internal server error
# Development
npm run dev # Start development server with hot reload
npm run build # Build for production
npm run start # Start production server
# Testing
npm test # Run tests
npm run test:watch # Run tests in watch mode
npm run test:coverage # Run tests with coverage
# Utilities
npm run lint # Type check with TypeScript
npm run clean # Clean build directorysrc/
βββ config/ # Application configuration
βββ controllers/ # Route controllers
βββ middleware/ # Express middleware
βββ routes/ # API route definitions
βββ services/ # Business logic services
βββ types/ # TypeScript type definitions
βββ utils/ # Utility functions
- TypeScript: Full type safety
- ESLint: Code linting (configured via tsconfig)
- Prettier: Code formatting
- Husky: Git hooks for quality checks
# Unit tests
npm test
# Integration tests
npm run test:integration
# With coverage
npm run test:coveragetests/
βββ unit/ # Unit tests
βββ integration/ # Integration tests
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY dist/ ./dist/
EXPOSE 3000
CMD ["npm", "start"]# Build for production
npm run build
# Start production server
npm start- Set
NODE_ENV=production - Configure production database/redis if used
- Set appropriate CORS origins
- Configure logging for production
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
- Follow TypeScript best practices
- Write comprehensive tests
- Update documentation
- Use conventional commits
- Ensure all tests pass
This project is licensed under the MIT License - see the LICENSE file for details.
- U.S. Department of State for providing the travel advisory data
- Express.js team for the excellent web framework
- Swagger/OpenAPI for API documentation standards
| Endpoint | Method | Purpose | Example |
|---|---|---|---|
/health |
GET | API health check | GET /health |
/api/countries |
GET | List all countries | GET /api/countries |
/api/raw |
GET | Simplified data for all countries | GET /api/raw?limit=50 |
/api/advisories |
GET | All advisories with filtering | GET /api/advisories?level=4 |
/api/advisories/{country} |
GET | Specific country advisory | GET /api/advisories/Armenia |
/api/advisories/level/{level} |
GET | Advisories by threat level | GET /api/advisories/level/4 |
/api/cache/stats |
GET | Cache statistics | GET /api/cache/stats |
/api/cache/refresh |
POST | Force cache refresh | POST /api/cache/refresh |
/api-docs |
GET | Interactive documentation | Visit in browser |
All API responses follow this consistent structure:
{
"success": true|false,
"data": { ... } | [ ... ] | null,
"message": "Human-readable message",
"timestamp": "ISO 8601 timestamp",
"requestId": "Unique request identifier"
}- Level 1: Exercise Normal Precautions
- Level 2: Exercise Increased Caution
- Level 3: Reconsider Travel
- Level 4: Do Not Travel
| Field | Type | Description |
|---|---|---|
country |
string | Country name |
countryCode |
string | ISO country code (2-3 characters) |
level |
string | Full threat level description |
levelNumber |
number | Numeric threat level (1-4) |
title |
string | Advisory title |
summary |
string | Brief summary (may be "No summary available") |
restrictions |
array | List of travel restrictions |
recommendations |
array | List of travel recommendations |
link |
string | Link to official advisory |
lastUpdated |
string | Last update timestamp |
Made with β€οΈ for safe travels worldwide