README
¶
DynamORM Example: Blog Platform
Overview
This example demonstrates how to build a modern blog platform using DynamORM with AWS Lambda. It showcases advanced DynamoDB patterns including:
- Slug-based URLs with unique constraints
- Nested comments with moderation
- Tag and category management
- Full-text search patterns
- View analytics and tracking
- Content versioning
- Multi-author support with roles
Key Features
- Posts: Full CRUD with drafts, publishing, and archiving
- Comments: Nested comments with spam detection and moderation
- Search: DynamoDB-based full-text search implementation
- Analytics: View tracking with session management
- Performance: Optimized for Lambda cold starts
- SEO: Slug-based URLs for better SEO
Architecture
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Client │────▶│ API Gateway │────▶│ Lambda │
└─────────────┘ └──────────────┘ └──────┬──────┘
│
┌──────▼──────┐
│ DynamoDB │
│ │
│ Tables: │
│ - Posts │
│ - Comments │
│ - Authors │
│ - Search │
└─────────────┘
DynamoDB Schema
Posts Table
- PK:
ID - GSIs:
gsi-slug: For unique slug lookupsgsi-author: For author's postsgsi-status-date: For listing by status and dategsi-category: For category filtering
Comments Table
- PK:
ID - GSI:
gsi-post: For post comments with nesting
Quick Start
Prerequisites
- Go 1.21+
- AWS CLI configured
- Docker (for local DynamoDB)
Local Development
- Clone and setup:
cd examples/blog
make setup
- Start local DynamoDB:
docker-compose up -d
- Run locally:
make run-local
- Run tests:
make test
API Reference
Posts API
List Posts
GET /posts?status=published&limit=20&cursor=xxx
Query Parameters:
status: Filter by status (draft, published, archived)author_id: Filter by authorcategory_id: Filter by categorytag: Filter by taglimit: Results per page (max 100)cursor: Pagination cursor
Response:
{
"success": true,
"data": {
"posts": [
{
"id": "123",
"slug": "my-first-post",
"title": "My First Post",
"excerpt": "This is my first post...",
"author": {
"id": "author-1",
"display_name": "John Doe"
},
"published_at": "2024-01-15T10:00:00Z",
"tags": ["blog", "first-post"]
}
],
"next_cursor": "xxx",
"has_more": true
}
}
Get Post by Slug
GET /posts/{slug}
Response includes full post content, author details, and category.
Create Post
POST /posts
Authorization: Bearer {token}
{
"title": "My New Post",
"content": "Post content in Markdown",
"excerpt": "Short description",
"category_id": "category-1",
"tags": ["tag1", "tag2"],
"status": "draft"
}
Update Post
PUT /posts/{id}
Authorization: Bearer {token}
{
"title": "Updated Title",
"content": "Updated content",
"status": "published"
}
Delete Post
DELETE /posts/{id}
Authorization: Bearer {token}
Comments API
List Comments
GET /posts/{postId}/comments?status=approved&limit=50
Returns nested comment structure.
Create Comment
POST /posts/{postId}/comments
{
"author_name": "Jane Doe",
"author_email": "jane@example.com",
"content": "Great post!",
"parent_id": "parent-comment-id" // Optional for nested comments
}
Moderate Comment (Admin)
PUT /comments/{commentId}/moderate
Authorization: Bearer {admin-token}
{
"status": "approved",
"reason": "Not spam"
}
Search API
Search Posts
GET /search?q=dynamodb&limit=20
Deployment
Using AWS SAM
- Build:
sam build
- Deploy:
sam deploy --guided
Using Serverless Framework
- Install dependencies:
npm install -g serverless
- Deploy:
serverless deploy
Environment Variables
DYNAMODB_REGION: AWS region (default: us-east-1)DYNAMODB_ENDPOINT: Custom endpoint (for local testing)JWT_SECRET: Secret for JWT validationENABLE_ANALYTICS: Enable view tracking (default: true)
Performance
Benchmarks
| Operation | Latency (p99) | Throughput |
|---|---|---|
| Get post by slug | 15ms | 5,000 req/s |
| List posts | 25ms | 2,000 req/s |
| Create post | 30ms | 1,000 req/s |
| Add comment | 20ms | 3,000 req/s |
Optimization Techniques
- Lambda Optimization: Connection pooling and initialization outside handler
- Index Design: Strategic GSIs for common queries
- Caching: CloudFront for static content
- Batch Operations: Bulk author lookups
Cost Estimation
For a blog with:
- 100,000 monthly page views
- 1,000 posts
- 10,000 comments
- 5 authors
Monthly costs:
- DynamoDB: ~$5-10 (on-demand)
- Lambda: ~$2-5
- API Gateway: ~$3-5
- Total: ~$10-20/month
What You'll Learn
- Slug-based URLs: Implementing unique constraints in DynamoDB
- Nested Data: Handling hierarchical comments efficiently
- Search Patterns: Building search without Elasticsearch
- Session Management: Tracking unique views with TTL
- Composite Keys: Using them for analytics
- Transactions: Maintaining consistency across tables
- Lambda Optimization: Reducing cold start impact
Advanced Features
Content Versioning
Posts use optimistic locking with version numbers to prevent conflicts.
Spam Detection
Basic spam detection for comments using:
- Keyword matching
- Link counting
- Caps lock detection
Analytics
- Real-time view counting
- Geographic distribution
- Referrer tracking
- Unique visitor tracking
SEO Optimization
- Clean URLs with slugs
- Structured data support
- Sitemap generation
- Meta tag management
Troubleshooting
Common Issues
- Slug Conflicts: The system automatically appends numbers to duplicate slugs
- Comment Nesting: Limited to 3 levels to maintain performance
- Search Limitations: Basic word matching, not full-text search
Performance Tips
- Use pagination for large result sets
- Enable caching for popular posts
- Consider read replicas for high traffic
- Use CloudFront for static assets
Extension Ideas
- RSS Feed: Add RSS feed generation
- Email Subscriptions: Notify subscribers of new posts
- Social Sharing: Add social media integration
- Image Optimization: Automatic image resizing
- Related Posts: ML-based recommendations
Contributing
Feel free to extend this example with additional features. Some ideas:
- GraphQL API
- Real-time comments with WebSockets
- A/B testing for titles
- Content scheduling
- Multi-language support
Click to show internal directories.
Click to hide internal directories.