Status: Production-Ready — Fully operational API with JWT auth, IP moderation, and automated OpenAPI documentation.
A high-performance, serverless REST API designed to manage ephemeral video stories (mirroring the functionality of Instagram/WhatsApp Stories). Built from the ground up using Clean Architecture principles, ensuring absolute separation of concerns across Domain, Application, API, and Infrastructure layers.
TECH STACK:
- TypeScript
- Hono
- Cloudflare Workers
- Cloudflare D1 (SQLite)
- Cloudflare R2
- AWS SDK
- Zod
- OpenAPI.
ARCHITECTURE & INFRASTRUCTURE • Dependency Flow: API (Controllers) -> Application (Use Cases) -> Domain (Entities) <- Infrastructure (D1/R2) • Fully Serverless Edge Computing: Deployed entirely on Cloudflare Workers, providing sub-millisecond cold starts and global low-latency responses. • Relational Edge Database: Powered by Cloudflare D1 with fully normalized schemas. Uses ON DELETE CASCADE and composite primary keys to maintain strict relational data integrity.
KEY FEATURES
- Ephemeral Data Lifecycle: Automated Cloudflare Cron Triggers execute scheduled background jobs to permanently purge stories and associated interactions older than 24 hours.
- Optimized Media Uploads: Implements the Presigned URL pattern via the AWS SDK. The API generates temporary upload URLs, allowing clients to push videos directly to R2 object storage without bottlenecking the worker’s memory.
Cascading Multi-Layer Security
- Global X-API-Key validation.
- Stateless JWT authentication for admin routes.
- Custom IP Moderation middleware checking cf-connecting-ip to protect public endpoints. • Type-Safe & Self-Documenting: End-to-end type safety using TypeScript and Zod schemas, automatically mapping to an interactive OpenAPI (Swagger) UI.
CODE HIGHLIGHTS
- Clean Architecture: Use Case (Application Layer) Isolating business logic from infrastructure and HTTP delivery.
// src/application/use-cases/CreateStoryUseCase.ts
export class CreateStoryUseCase {
constructor(
private storyRepo: IStoryRepository,
private storageService: IStorageService
) {}
async execute(): Promise<{ story: Story; uploadUrl: string }> {
const storyId = crypto.randomUUID();
const fileName = `stories/${storyId}.mp4`;
// Generate temporary upload URL directly to Cloudflare R2
const uploadUrl = await this.storageService.generateUploadUrl(fileName);
const story = {
id: storyId,
videoUrl: `${process.env.PUBLIC_R2_URL}/${fileName}`,
createdAt: new Date().toISOString(),
};
// Persist to Cloudflare D1
await this.storyRepo.create(story);
return { story, uploadUrl };
}
}TypeScript- Edge Security: IP Ban Middleware (API Layer) Intercepting requests at the edge to block banned users using Cloudflare’s injected headers.
// src/api/middlewares/ipBan.middleware.ts
import { createMiddleware } from 'hono/factory';
import { UnauthorizedError } from '../../helpers/error';
export const ipBanMiddleware = (moderationRepo: IModerationRepository) =>
createMiddleware(async (c, next) => {
// Retrieve connecting IP from Cloudflare Edge
const clientIp = c.req.header('cf-connecting-ip') || 'unknown';
if (clientIp !== 'unknown') {
const isBanned = await moderationRepo.isIpBanned(clientIp);
if (isBanned) {
throw new UnauthorizedError('This IP is banned from interacting with stories');
}
}
await next();
});TypeScript- Storage Integration (Infrastructure Layer) Implementing the storage interface to generate Presigned URLs using the AWS SDK adapted for R2.
// src/infrastructure/storage/R2StorageService.ts
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
export class R2StorageService implements IStorageService {
private client: S3Client;
constructor(accountId: string, accessKeyId: string, secretAccessKey: string) {
this.client = new S3Client({
region: 'auto',
endpoint: `https://${accountId}.r2.cloudflarestorage.com`,
credentials: { accessKeyId, secretAccessKey },
});
}
async generateUploadUrl(fileName: string): Promise<string> {
const command = new PutObjectCommand({
Bucket: 'stories-bucket',
Key: fileName,
ContentType: 'video/mp4',
});
// URL valid for 3600 seconds (1 hour)
return await getSignedUrl(this.client, command, { expiresIn: 3600 });
}
}TypeScript