This repository contains the complete backend source code for a modern, serverless blogging platform built on the Cloudflare Workers ecosystem. It features a robust API for user authentication, blog post management, and utilizes a shared validation library for type safety.
- Serverless Architecture: Built entirely on Cloudflare Workers for global scale and performance.
- Fast & Lightweight: Uses Hono, a blazing-fast, lightweight web framework for edge environments.
- Database ORM: Integrates with Prisma and Prisma Accelerate for type-safe database access to a PostgreSQL database.
- Authentication: Secure user signup and signin using JWT (JSON Web Tokens) and hashed passwords with bcryptjs.
- Type-Safe Validation: Shared request validation schemas using Zod, published as a private npm package for consistency between frontend and backend.
- Monorepo Structure: A clean pnpm workspace setup separating the
backendworker from thecommonshared library. - Ready to Deploy: Streamlined deployment process using the Wrangler CLI.
The project is organized as a monorepo with two main packages:
medium-blog/
βββ backend/ # Cloudflare Worker API
β βββ prisma/
β β βββ schema.prisma # Database models (User, Post)
β βββ src/
β β βββ index.ts # Hono application routes and logic
β βββ package.json
β βββ wrangler.toml # Cloudflare Worker configuration
β
βββ common/ # Shared validation library
β βββ src/
β β βββ index.ts # Zod schemas and TypeScript types
β βββ package.json
β
βββ .gitignore
βββ package.json
βββ README.md
- Runtime: Cloudflare Workers
- Framework: Hono
- Database: PostgreSQL
- ORM: Prisma (with Prisma Accelerate)
- Authentication: JWT (
hono/jwt) & bcryptjs - Validation: Zod
- Deployment: Wrangler CLI
Follow these instructions to set up, run, and deploy the project on your own Cloudflare account.
- Node.js (v18 or later)
- pnpm (or npm/yarn)
- A Cloudflare account
- A PostgreSQL database (e.g., from Supabase, Neon, or Aiven)
git clone https://github.com/your-username/medium-blog.git
cd medium-blogThis project uses pnpm workspaces. Install all dependencies from the root directory.
pnpm installThe backend worker requires two crucial environment variables. Create a .dev.vars file inside the backend directory. This file is used by wrangler dev for local development.
File: backend/.dev.vars
# Direct connection string for your PostgreSQL database (used for Prisma migrations)
DATABASE_URL="postgres://USER:PASSWORD@HOST:PORT/DATABASE"
# A strong, secret key for signing JWTs
JWT_SECRET="your-super-secret-key"a. Configure Prisma Schema:
The schema is already defined in backend/prisma/schema.prisma. It uses the DATABASE_URL environment variable.
b. Run Database Migrations:
cd backend
pnpm prisma migrate devc. Generate Prisma Client:
pnpm prisma generateTo run the server locally, use the wrangler dev command from the backend directory. This will start a local server that emulates the Cloudflare Workers environment and automatically loads your .dev.vars file.
cd backend
pnpm devYour API will be available at http://localhost:8787.
pnpm wrangler loginFor a serverless environment like Cloudflare Workers, a direct database connection is not ideal. Prisma Accelerate provides a connection pool and global cache over a serverless-friendly HTTP connection.
a. Enable Accelerate: Go to your project on the Prisma Data Platform and enable Accelerate.
b. Get the Accelerate URL: Generate an API key and copy the connection string. It will look like this:
prisma://accelerate.prisma-data.net/?api_key=...
Never store production database URLs or secrets in your wrangler.toml file. Use Wrangler secrets, which are securely encrypted.
# From the /backend directory
# Use the Prisma Accelerate connection string here
pnpm wrangler secret put DATABASE_URL
# Use your production JWT secret
pnpm wrangler secret put JWT_SECRETcd backend
pnpm deployWrangler will build your project, upload it to Cloudflare, and provide you with your public worker URL.
Base URL: https://your-worker-name.your-subdomain.workers.dev/api/v1
Creates a new user account.
- Method: POST
- Endpoint:
/user/signup
Request Body:
{
"email": "test@example.com",
"password": "strongpassword123",
"name": "Test User"
}Success Response (201):
{
"id": "c5f8e9b0-5b2a-4b1e-8c3b-2f3a1d9c8e7f",
"email": "test@example.com"
}Error Response (409):
{
"message": "Email already exists"
}Authenticates a user and returns a JWT.
- Method: POST
- Endpoint:
/user/signin
Request Body:
{
"email": "test@example.com",
"password": "strongpassword123"
}Success Response (200):
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}Note: All blog endpoints (except GET) require an Authorization: Bearer <TOKEN> header.
- Method: POST
- Endpoint:
/blog
Request Body:
{
"title": "My First Blog Post",
"content": "This is the content of the post."
}Success Response (201):
{
"id": "a1b2c3d4-e5f6-7890-1234-567890abcdef"
}- Method: PUT
- Endpoint:
/blog
Request Body:
{
"id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
"title": "Updated Title",
"content": "Updated content."
}Success Response (200):
{
"message": "Blog post updated successfully"
}- Method: GET
- Endpoint:
/blog/:id
Example: /blog/a1b2c3d4-e5f6-7890-1234-567890abcdef
Success Response (200):
{
"id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
"title": "Updated Title",
"content": "Updated content.",
"author": {
"name": "Test User"
}
}- Method: GET
- Endpoint:
/blog/bulk
Success Response (200):
[
{
"id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
"title": "Updated Title",
"content": "Updated content.",
"author": {
"name": "Test User"
}
}
]A reusable validation and type-safety library for the Medium Blog API, built and maintained by Abhisek Sahoo. This package provides Zod schemas and TypeScript types that are shared across the backend and frontend, ensuring consistent validation and reducing duplication.
- Zod Schemas: Centralized validation rules for user authentication and blog post operations.
- TypeScript Types: Automatically inferred types for safer frontendβbackend integration.
- Shared Module: Designed for monorepos or external consumers via npm.
- Lightweight: Pure TypeScript + Zod, no extra dependencies beyond dev tooling.
common/
βββ src/
β βββ index.ts # Main exports (schemas + types)
βββ package.json
βββ tsconfig.json
βββ .npmignore
Install from npm:
npm install abhi-medium-blogImport schemas and types directly into your project:
import {
signupInput,
signinInput,
createBlogInput,
editBlogInput,
type SignupInput,
type SigninInput,
type CreateBlogInput,
type EditBlogInput
} from "abhi-medium-blog";
// Example: validating signup
const parsed = signupInput.parse({
email: "alice@example.com",
password: "Password123",
name: "Alice"
});
console.log(parsed); // β
safe, validated objectsignupInputβ{ email: string; password: string; name?: string }signinInputβ{ email: string; password: string }createBlogInputβ{ title: string; content: string }editBlogInputβ{ id: string; title: string; content: string }
SignupInputSigninInputCreateBlogInputEditBlogInput
In the backend, you can use the schemas to validate incoming requests:
import { signupInput } from "abhi-medium-blog";
app.post("/api/v1/user/signup", async (c) => {
const body = await c.req.json();
const parsed = signupInput.safeParse(body);
if (!parsed.success) {
return c.json({ message: "Invalid input", errors: parsed.error.errors }, 400);
}
// parsed.data is type-safe and validated
const { email, password, name } = parsed.data;
// ... continue with Prisma + JWT logic
});Developed and maintained by Abhisek Sahoo
- π GitHub
- π§ abhiseksahoo7154@example.com (replace with your actual email if you want)