Skip to content

WorkuMekuriya/Blog-API

Repository files navigation

Blog API (Soryal technical test)

REST API for a blog: Express, PostgreSQL, Prisma 7, Zod, JWT, layered routes/controllers/services, Jest (HTTP checks via Node fetch + ephemeral server), and Docker Compose.

Requirements

  • Node.js 22+ (includes npm; Prisma 7’s dependency tree expects Node ≥ 22)
  • npm or Yarn 1.x (Classic) for installing dependencies and running scripts
  • PostgreSQL 14+ (local or container)

Clone the repository

git clone https://github.com/WorkuMekuriya/Blog-API.git
cd Blog-API

Then continue with Environment variables and Local development below.

Environment variables

Variable Required Description
DATABASE_URL Yes PostgreSQL URL (also read by prisma.config.ts for migrations).
JWT_SECRET Yes Secret used to sign JWT access tokens.
PORT No HTTP port (default 3000).
NODE_ENV No Set to **production** in live deployments (e.g. trust proxy for rate limits behind a load balancer).

Copy the example file and edit values:

cp .env.example .env

Local development

Use Yarn or npm — script names are the same (package.jsonscripts). With npm, run npm install once, then npm run <name> (e.g. npm run dev). The test script is also available as **npm test**.

yarn install          # or: npm install
yarn prisma:generate   # or: npm run prisma:generate
yarn prisma:migrate    # or: npm run prisma:migrate  — or prisma:deploy against an existing DB
yarn db:seed           # or: npm run db:seed  — optional: default user admin@example.com / Password123!
yarn dev               # or: npm run dev
  • Health: GET http://localhost:3000/health

Production build (without Docker)

yarn install          # or: npm install
yarn prisma:generate  # or: npm run prisma:generate
yarn build            # or: npm run build
yarn prisma:deploy    # or: NODE_ENV=production npm run prisma:deploy
NODE_ENV=production node dist/server.js

Docker Compose

Build and run the API plus PostgreSQL:

# Optional: enforce a strong JWT secret (recommended)
export JWT_SECRET="$(openssl rand -hex 32)"

docker compose build --no-cache blog_api
docker compose up
  • API: http://localhost:3000
  • Postgres is exposed on localhost:5432 for tooling (user/password/db: blog / blog / blog).
  • Default login after seed: admin@example.com / Password123!.

Rate limiting (public endpoints)

Area Window Max (per IP)
GET /health 1 minute 60
POST /auth/login 15 minutes 30
GET /articles, GET /articles/:id 1 minute 120

Authenticated POST / PUT / DELETE on /articles are not covered by these public limiters.

In **NODE_ENV=test**, limits are skipped so Jest stays deterministic.

Behind a reverse proxy, the app sets **trust proxy** when NODE_ENV=production so the client IP used for limits is correct.

Tests

yarn test    # or: npm test

API overview

Method Path Auth Body
GET /health No
POST /auth/login No { "email": "string", "password": "string" }
GET /articles No (pagination: page, limit)
GET /articles/:id No
POST /articles Bearer JWT { "title": "string", "content": "string" }
PUT /articles/:id Bearer JWT { "title": "string", "content": "string" }
DELETE /articles/:id Bearer JWT

Login response: { "token": "<jwt>" }. Send Authorization: Bearer <jwt> on protected routes.

Project layout

  • src/routes, src/controllers, src/services — HTTP layering
  • src/schemas — Zod validation
  • src/middleware — auth, errors, rate limits
  • prisma/ — schema and migrations

About

Soryal technical test - blog REST API (Express, Prisma, PostgreSQL, Zod, JWT)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors