A complete e-commerce backend (REST API) for a small online store: catalog, cart, checkout and
order management, built with zero runtime dependencies on Node.js 22+ (node:http,
node:sqlite, node:crypto).
It focuses on the parts that usually go wrong in real shops:
- No overselling. Checkout runs in one SQLite transaction and decrements stock with a guarded
UPDATE … WHERE stock >= ?. Two customers racing for the last item: one gets the order, the other a409. - Safe retries.
POST /ordersaccepts anIdempotency-Keyheader. A double-clicked "Pay" button creates one order. - Correct money. Prices are integer kuruş, VAT-inclusive, with per-product Turkish VAT (KDV) rates of 0, 1, 10 or 20 %.
- Order workflow.
pending → paid → shipped → delivered, orcancelled, which puts the stock back. - Secure auth. scrypt password hashes, HS256 JWTs verified in constant time, no user enumeration on login.
git clone https://github.com/bahriy-dev/ecommerce-rest-api.git
cd ecommerce-rest-api
npm start # http://localhost:3000/api/v1 (seeds an admin and 3 demo products)
npm test # 27 tests: unit + full HTTP flowsWith Docker:
docker build -t ecommerce-api .
docker run -p 3000:3000 -e JWT_SECRET=change-me -v shop-data:/data ecommerce-apiAll routes are under /api/v1. Send Authorization: Bearer <token> for protected routes.
| Method | Path | Auth | Description |
|---|---|---|---|
POST |
/auth/register |
— | Create a customer account, returns a JWT |
POST |
/auth/login |
— | Log in, returns a JWT |
GET |
/me |
user | Current user |
GET |
/categories |
— | Categories |
GET |
/products |
— | Search, filter and paginate (see below) |
GET |
/products/:id |
— | Product detail |
POST |
/products |
admin | Create a product |
PATCH |
/products/:id |
admin | Update any field |
DELETE |
/products/:id |
admin | Soft delete (keeps order history intact) |
GET |
/cart |
user | Cart lines, availability and totals |
PUT |
/cart/items/:productId |
user | Set quantity (0 removes) |
DELETE |
/cart |
user | Empty the cart |
POST |
/orders |
user | Checkout. Supports Idempotency-Key |
GET |
/orders |
user | My orders (?all=true for admins) |
GET |
/orders/:id |
user | Order detail (owner or admin) |
POST |
/orders/:id/cancel |
user | Cancel a pending order |
PATCH |
/orders/:id/status |
admin | Move an order through the workflow |
Product query parameters: q, category (slug), minPrice, maxPrice (kuruş),
inStock=true, sort (newest, price_asc, price_desc, name), page, limit (max 100).
TOKEN=$(curl -s localhost:3000/api/v1/auth/register -H 'Content-Type: application/json' \
-d '{"email":"ayse@example.com","name":"Ayşe","password":"password123"}' | jq -r .token)
curl -X PUT localhost:3000/api/v1/cart/items/1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"quantity":2}'
curl -X POST localhost:3000/api/v1/orders -H "Authorization: Bearer $TOKEN" \
-H 'Idempotency-Key: 6f1c…' -H 'Content-Type: application/json' \
-d '{"shippingAddress":"Caferağa Mah. Moda Cad. No:1, Kadıköy, İstanbul 34710"}'{
"id": 1,
"status": "pending",
"subtotal": 499800,
"vatTotal": 83300,
"shipping": 0,
"total": 499800,
"items": [{ "productId": 1, "name": "Mekanik Klavye", "unitPrice": 249900, "vatRate": 20, "quantity": 2 }]
}Errors always look like { "error": "…", "details": { … } }. Validation errors return 422
with one message per field.
| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
HTTP port |
DATABASE_PATH |
data.db |
SQLite file (:memory: for throwaway runs) |
JWT_SECRET |
dev value | Required in production |
ADMIN_EMAIL / ADMIN_PASSWORD |
admin@example.com / admin12345 |
First admin, created once |
SHIPPING_FEE |
4990 |
Flat shipping fee in kuruş |
FREE_SHIPPING_OVER |
50000 |
Free shipping threshold in kuruş |
CORS_ORIGIN |
* |
Allowed origin |
LOG_REQUESTS |
— | 1 logs method, path, status and duration |
src/
http.ts router, JSON body parsing, errors
auth.ts scrypt passwords, JWT, role guards
validate.ts tiny schema validator (422 with per-field errors)
db.ts schema migrations (PRAGMA user_version), transactions, seed data
pricing.ts VAT, shipping and totals in integer kuruş
routes/ auth, catalog, cart, orders
app.ts wiring, CORS, error handling
test/ node:test unit tests and end-to-end HTTP tests
MIT © Bahri YILMAZ