Skip to content

JayShende/express-layered-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

express-layered-api

A Cursor Agent Skill for Express 5 + TypeScript layered APIs
Routes → Controllers → Services → Prisma — with Zod validation and auth stubs

skills.sh License: MIT Express 5 TypeScript ESM Prisma 7


Table of Contents


Overview

express-layered-api is an Agent Skill that teaches AI coding agents how to scaffold and extend production-style Express backends. Instead of dumping logic into route files, it enforces a strict layered pattern so every endpoint follows the same predictable flow.

Works with Cursor, Claude Code, Codex, and 68+ other agents via the skills.sh ecosystem.

# One command to install globally for Cursor
npx skills add JayShende/express-layered-api -g -a cursor -y

Architecture

Request Flow

Every HTTP request travels through a fixed pipeline. Each layer has one job and delegates to the next.

flowchart LR
    A[Client] --> B[index.ts]
    B --> C["/api/v1"]
    C --> D[domain.route.ts]
    D --> E[isAuthenticated]
    E --> F[requireRole]
    F --> G[validate]
    G --> H[controller]
    H --> I[service]
    I --> J[(Prisma / PostgreSQL)]
    H --> K["response()"]
    K --> A
Loading

Layered Design

graph TB
    subgraph HTTP["HTTP Layer"]
        R[Route]
        M[Middleware]
    end

    subgraph App["Application Layer"]
        C[Controller]
        V[Validator]
    end

    subgraph Domain["Domain Layer"]
        S[Service]
    end

    subgraph Data["Data Layer"]
        P[Prisma Client]
        DB[(PostgreSQL)]
    end

    R --> M
    M --> V
    V --> C
    C --> S
    S --> P
    P --> DB
Loading

Add API Workflow (Mode 2)

When you ask the agent to add a new endpoint, it always works bottom-up — never skipping layers.

flowchart TD
    Start([User: Add an API]) --> Parse[Parse domain, method, auth, validation]
    Parse --> Exists{Domain exists?}
    Exists -->|No| Create[Create 4 domain files + register route]
    Exists -->|Yes| Extend[Extend existing files]
    Create --> Prisma
    Extend --> Prisma
    Prisma[1. schema.prisma + migrate] --> Validator[2. validator.ts - Zod schemas]
    Validator --> Service[3. service.ts - business logic]
    Service --> Controller[4. controller.ts - try/catch + response]
    Controller --> Route[5. route.ts - middleware chain]
    Route --> Verify[6. Verify checklist]
    Verify --> Done([Endpoint live at /api/v1/...])
Loading

Three Modes

The skill picks the right workflow based on what you ask.

Mode You say Agent does
Existing project "I have an app ready", "adopt this pattern", "create API files in my project" Scans your app, adds missing infra, then creates APIs in your structure
Scaffold "Set up backend", "scaffold API", "new project" Creates a full Express 5 + Prisma + TypeScript project from templates
Add API "Add an API that...", "create endpoint for...", "add CRUD for..." Adds a new endpoint across all layers (validator → service → controller → route)

Mode 0 — Existing Node.js app

Use this when you already have a Node/Express app and want API files created inside it.

@express-layered-api I have an existing Node app in ./backend.
Read the project structure first, match existing conventions.
Then add GET /api/v1/orders with pagination. Admin only.

The agent will:

  1. Read index.ts, existing routes, controllers, services
  2. Add missing infrastructure only if absent (api-error, reponses, validate, auth stubs)
  3. Create or extend the 4 domain files for your API
  4. Match your conventions (/v1 vs /api/v1, existing auth, etc.)

Mode 1 — Scaffold

Produces a minimal, API-only starter:

  • Express 5 app with CORS, JSON parsing, trust proxy
  • Prisma 7 + PostgreSQL with a sample SystemPing model
  • Auth middleware stubs (isAuthenticated, requireRole) ready to wire later
  • A working test route: GET /api/v1/test/loggerAPI

Mode 2 — Add API

The day-to-day mode. Example prompt:

"Add an API to create and list products. Name and price required. Admin only."

The agent produces:

Layer File What gets added
Database schema.prisma Product model + migration
Validation product.validator.ts createProduct, listProducts Zod schemas
Business logic product.service.ts createProduct, listProducts
HTTP handler product.controller.ts create, list with try/catch
Routing product.route.ts POST / and GET / with auth + role + validate
Registry routes/index.ts { path: "/products", route: productRoute }

Result: POST /api/v1/products and GET /api/v1/products


Project Structure

Scaffolded projects follow this layout:

backend/
├── prisma/
│   └── schema.prisma              # Database models
├── prisma.config.ts
├── generated/prisma/              # Prisma client output (gitignored)
├── src/
│   ├── index.ts                   # App bootstrap
│   ├── routes/
│   │   ├── index.ts               # Route registry
│   │   └── {domain}.route.ts
│   ├── controllers/
│   │   └── {domain}.controller.ts
│   ├── services/
│   │   └── {domain}.service.ts
│   ├── validators/
│   │   └── {domain}.validator.ts
│   ├── middlewares/
│   │   ├── auth-middleware.ts     # Auth stubs
│   │   └── validate.ts
│   ├── lib/
│   │   └── prisma.ts
│   ├── utils/
│   │   ├── api-error.ts
│   │   └── reponses.ts
│   └── types/express/
│       └── index.d.ts
├── .env.example
├── package.json
└── tsconfig.json

Layer Responsibilities

Layer Does Does NOT
Route Mount path, chain middleware, call controller Business logic, Prisma, try/catch
Middleware Auth, validation, request augmentation Database access
Controller Extract req data, call service, map errors to HTTP, response() Prisma, role checks
Service Business rules, Prisma calls, throw ApiError Send HTTP responses
Validator Zod schemas { body?, query?, params? } Runtime logic

Middleware Chain

router.post(
  "/",
  isAuthenticated,                        // omit if public
  requireRole("ADMIN"),                   // omit if any authenticated user
  validate(domainValidator.createDomain),   // always validate input
  domainController.create,
);

Response Formats

Source Shape
Controllers (success/error) { message, data }
Validation middleware { success: false, message: "Validation Error", errors: string[] }
Auth middleware stubs { error: "Unauthorized" } or { error: "Forbidden: ..." }

Install

Global (recommended)

Available in every project:

npx skills add JayShende/express-layered-api -g -a cursor -y

Project-level

Committed with your team repo:

npx skills add JayShende/express-layered-api -a cursor -y

Update

npx skills update express-layered-api -g -y

Other agents

Replace -a cursor with your agent: claude-code, codex, opencode, etc.

npx skills add JayShende/express-layered-api -g -a claude-code -a cursor -y

Usage

Invoke directly

/express-layered-api

Or attach with @express-layered-api in chat.

Quick prompts

Existing app — add an API:

@express-layered-api I have an existing Node app in ./backend.
Read the project first, match conventions.
Add full CRUD for products. Name and price required. Admin only.

Scaffold a new backend:

@express-layered-api scaffold a new backend in ./backend

Add a single endpoint:

@express-layered-api add GET /api/v1/users/:id with authentication

Extend an existing domain:

@express-layered-api add PATCH /api/v1/products/:id/archive. Admin only.
Read existing product files and extend them.

Sample Use Cases

Full copy-paste examples for every scenario are in examples.md.

Scenario Example prompt
New project @express-layered-api scaffold a new backend in ./backend
Existing app setup @express-layered-api My app in ./api has no controllers folder yet. Add infra + health endpoint.
Full CRUD @express-layered-api add full CRUD for categories. Admin write, user read.
Public endpoint @express-layered-api add GET /api/v1/health. Public.
Action endpoint @express-layered-api add POST /api/v1/orders/:id/cancel. Admin only.
Match existing codebase @express-layered-api @Backend add GET /api/v1/sessions. Match vip.route.ts style.

Prompt formula:

@express-layered-api [app path] [action] [method/path] [fields] [auth/roles] [match existing style]

Tech Stack

Layer Choice
Runtime Node.js, pnpm
Framework Express 5
Language TypeScript — ESM, module: NodeNext, .js extensions on imports
ORM Prisma 7 + PostgreSQL (@prisma/adapter-pg)
Validation Zod 4
HTTP codes http-status package

Conventions

Naming

Artifact Pattern Example
Route file {domain}.route.ts product.route.ts
Controller {domain}.controller.ts product.controller.ts
Service {domain}.service.ts product.service.ts
Validator {domain}.validator.ts product.validator.ts
Handler fn camelCase verb create, list, getById
URL segments kebab-case plural /api/v1/deleted-items
Exports export default { fn1, fn2 } Controllers, services, validators

HTTP Method Map

HTTP Path Handler Validator Service
POST / create create{Domain} create{Domain}
GET / list list{Domain}s list{Domain}s
GET /:id getById get{Domain}ById get{Domain}ById
PATCH /:id update update{Domain} update{Domain}
DELETE /:id remove remove{Domain} remove{Domain}

Route Ordering

Static paths before dynamic params:

GET /suggest     <-- first
GET /:id         <-- after static routes

What Is Included

Included Not included (unless you ask)
Layered route/controller/service pattern Better Auth / JWT implementation
Zod request validation Geolocation / geo gate middleware
Prisma 7 + PostgreSQL setup Cron jobs, email, S3, Excel export
Auth middleware stubs Global error handler middleware
Per-controller try/catch error handling constants/ folder
Sample test route + Prisma model

Repository Files

This skill repo contains only the agent instructions — not a runnable backend.

express-layered-api/
├── SKILL.md        # Main agent workflow and conventions
├── reference.md    # Copy-paste templates for every scaffold file
├── examples.md     # Sample prompts for all three modes
├── README.md       # This file
└── LICENSE         # MIT
  • SKILL.md — Full workflow: existing-project, scaffold, and add-API modes
  • reference.md — Complete file templates (package.json, schema.prisma, controllers, services, validators, middleware, etc.)
  • examples.md — Copy-paste prompt examples for new projects, existing apps, CRUD, auth patterns, and more

License

MIT — see LICENSE.

About

No description, website, or topics provided.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors