Overview
The Template Service manages notification templates for the distributed notification system. Built with FastAPI and Python, it provides a simple, lightweight API for retrieving email and push notification templates stored in a JSON file.
Purpose and Responsibilities
- Template storage - Store notification templates with subject, body, and variables
- Template retrieval - Provide templates by code via REST API
- Version management - Track template versions for auditing
- Variable definition - Define required variables for each template
Tech Stack
- Framework: FastAPI (latest)
- Language: Python 3.9+
- Server: Uvicorn (ASGI server)
- Storage: JSON file (
templates.json)
Configuration
Port: 8002 (configurable)
Environment Variables:
PORT=8002 # Default if not specified
Server Configuration (main.py:42-43):
if __name__ == "__main__":
uvicorn.run("main:app", host="0.0.0.0", port=8002, reload=True)
Template Structure
Templates are stored in templates.json with the following structure.
Template Schema
File: templates.json
{
"welcome_email": {
"subject": "Welcome to Our Platform!",
"body": "Hi {{name}},\n\nThanks for signing up. We're glad to have you onboard!",
"version": "2.0.0",
"variables": ["name"]
},
"password_reset": {
"subject": "Reset Your Password",
"body": "Hi {{name}},\n\nClick here to reset your password: {{link}}",
"version": "1.5.4",
"variables": ["name", "link"]
},
"account_deactivated": {
"subject": "Your Account Has Been Deactivated",
"body": "Hi {{name}},\n\nWe noticed you deactivated your account. We hope to see you back soon.",
"version": "1.0.0",
"variables": ["name"]
}
}
Template Fields:
| Field | Type | Description |
|---|
subject | string | Email subject line or push notification title |
body | string | Template body with {{variable}} placeholders |
version | string | Semantic version for template versioning |
variables | array | List of required variable names |
Variables use Mustache-style {{variable}} syntax and are replaced by downstream services (Email/Push).
API Endpoints
GET /api/v1/templates/:code
Retrieve a template by its code.
Example Request:
GET /api/v1/templates/welcome_email
Implementation (main.py:7-23):
@app.get("/api/v1/templates/{code}")
def get_template(code: str):
"""
Fetch a notification template by its code.
Example: GET /api/v1/templates/welcome_email
"""
with open("templates.json", "r") as f:
templates = json.load(f)
template = templates.get(code)
if not template:
raise HTTPException(status_code=404, detail="Template not found")
return {
"success": True,
"data": template,
"message": "Template fetched successfully"
}
Response (200 OK):
{
"success": true,
"data": {
"subject": "Welcome to Our Platform!",
"body": "Hi {{name}},\n\nThanks for signing up. We're glad to have you onboard!",
"version": "2.0.0",
"variables": ["name"]
},
"message": "Template fetched successfully"
}
Error Response (404 Not Found):
{
"detail": "Template not found"
}
GET /
Root endpoint with welcome message.
Response (200 OK):
{
"message": "Welcome to the Template Service"
}
GET /health
Health check endpoint for monitoring and orchestration.
Implementation (main.py:33-38):
@app.get("/health")
def health_check():
"""
Health check endpoint — for CI/CD, monitoring, or orchestration tools.
"""
return {"status": "ok", "service": "template-service"}
Response (200 OK):
{
"status": "ok",
"service": "template-service"
}
Template Variables
Templates support dynamic variables that are replaced by downstream services.
Variable Syntax:
- Use double curly braces:
{{variable_name}}
- Variables are case-sensitive
- Undefined variables are left as-is (not replaced)
Example Template:
Subject: Reset Your Password
Body: Hi {{name}},
Click here to reset your password: {{link}}
This link will expire in 24 hours.
Variable Replacement (performed by Email/Push services):
{
"name": "John Doe",
"link": "https://example.com/reset?token=abc123"
}
Rendered Output:
Subject: Reset Your Password
Body: Hi John Doe,
Click here to reset your password: https://example.com/reset?token=abc123
This link will expire in 24 hours.
Template Versioning
Each template includes a semantic version number for tracking changes.
Version Format: MAJOR.MINOR.PATCH
- MAJOR: Breaking changes (e.g., removed variables)
- MINOR: New features (e.g., added variables)
- PATCH: Bug fixes or minor text changes
Example:
{
"welcome_email": {
"version": "2.0.0",
"variables": ["name", "link"]
}
}
Version changes help track template evolution and coordinate updates across teams.
Adding New Templates
To add a new template, edit templates.json and add a new entry.
Example:
{
"order_confirmation": {
"subject": "Order Confirmed - #{{order_id}}",
"body": "Hi {{name}},\n\nYour order #{{order_id}} has been confirmed!\n\nTotal: ${{total}}",
"version": "1.0.0",
"variables": ["name", "order_id", "total"]
}
}
Restart the service after editing templates.json for changes to take effect (unless using auto-reload).
Running the Service
Development (with auto-reload)
The service will start on http://0.0.0.0:8002 with auto-reload enabled.
Production
uvicorn main:app --host 0.0.0.0 --port 8002 --workers 4
Docker
docker build -t template-service .
docker run -p 8002:8002 template-service
Dockerfile Example:
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY main.py templates.json ./
EXPOSE 8002
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8002"]
API Documentation
FastAPI automatically generates interactive API documentation.
Swagger UI: http://localhost:8002/docs
ReDoc: http://localhost:8002/redoc
OpenAPI Spec: http://localhost:8002/openapi.json
Configuration (main.py:4):
app = FastAPI(title="Template Service")
- File I/O: Templates are loaded from disk on each request
- Caching: Consider adding in-memory caching for production
- Concurrency: Uvicorn supports multiple workers for high traffic
Optimization Example (with caching):
import json
from functools import lru_cache
@lru_cache(maxsize=1)
def load_templates():
with open("templates.json", "r") as f:
return json.load(f)
@app.get("/api/v1/templates/{code}")
def get_template(code: str):
templates = load_templates()
template = templates.get(code)
if not template:
raise HTTPException(status_code=404, detail="Template not found")
return {
"success": True,
"data": template,
"message": "Template fetched successfully"
}
The @lru_cache decorator caches template data in memory, reducing file I/O overhead.
Future Enhancements
Database Backend:
Replace JSON file storage with a database (PostgreSQL, MongoDB) for:
- Multi-user template management
- Template history and rollbacks
- Real-time updates without restarts
Template Validation:
Add validation to ensure:
- All declared variables are present in the body
- No undeclared variables are used
- Subject/body fields are not empty
Internationalization (i18n):
Support multiple languages:
{
"welcome_email": {
"en": {
"subject": "Welcome!",
"body": "Hi {{name}}..."
},
"es": {
"subject": "¡Bienvenido!",
"body": "Hola {{name}}..."
}
}
}
Error Handling
FastAPI provides automatic error handling with detailed error responses.
404 Example (main.py:18):
if not template:
raise HTTPException(status_code=404, detail="Template not found")
Response:
{
"detail": "Template not found"
}