← 返回 Skills 市场
bayudsatriyo

backend developer

作者 Bayu Dwi Satriyo · GitHub ↗ · v1.0.0 · MIT-0
cross-platform ⚠ suspicious
125
总下载
0
收藏
0
当前安装
1
版本数
在 OpenClaw 中安装
/install backend-developer
功能描述
Standardized backend REST API development following layered architecture patterns (Route → Controller → Service → Repository). Use when building new REST API...
使用说明 (SKILL.md)

Backend API Architecture Skill

This skill provides a standardized, production-ready architecture for Node.js/TypeScript REST APIs following the 4-layer pattern proven across multiple production systems.

Core Architecture

Client Request
  ↓
[routes/] HTTP handlers + middleware
  ↓
[controller/] Request parsing + response formatting
  ↓
[service/] Business logic + orchestration
  ↓
[repository/] Database access (Prisma)

Each layer has a single responsibility and clear boundaries.

Quick Start: The Standard Stack

Runtime: Node.js + TypeScript
Framework: Express
ORM: Prisma
Validation: Joi + Zod (request validation)
Error Handling: Custom AppError class + centralized middleware
Response Format: Standardized JSON with {status, data, meta, error}

File Organization

Each feature gets a feature module with 6 files:

src/
├── app/
│   └── [feature]/
│       ├── [feature].route.ts      ← HTTP routes + middleware
│       ├── [feature].controller.ts ← Request → response
│       ├── [feature].service.ts    ← Business logic
│       ├── [feature].repository.ts ← Database queries
│       ├── [feature].dto.ts        ← TypeScript types
│       ├── [feature].mapper.ts     ← Entity → DTO transformation
│       └── [feature].request.ts    ← Joi/Zod validation schemas
├── config/
│   └── config.ts                   ← Environment loading
├── interface/
│   └── index.ts                    ← Global types, ERROR_CODE, ApiResponse
├── middleware/
│   ├── auth-middleware.ts
│   ├── error-handler.ts            ← Centralized error handling
│   ├── validate-request.ts
│   ├── security.middleware.ts
│   └── index.ts
├── lib/
│   └── prisma.ts                   ← Prisma client singleton
├── utils/
│   ├── response-handler.ts         ← ResponseHandler utilities
│   ├── handle-prisma-error.ts
│   └── clean-joi-error-message.ts
├── routes/
│   └── index.ts                    ← Central route aggregator
└── index.ts                        ← Express app setup

The 4 Layers Explained

1. Route Layer ([feature].route.ts)

Responsibility: HTTP method binding, middleware ordering, parameter extraction
Does: Apply auth middleware → validate input → call controller → error handling
Does NOT: Business logic, database access

export const [feature]Routes = express.Router();

[feature]Routes.post(
  '/',
  auth('ACCESS', [Roles.Admin]),          // ← Auth middleware
  validate(createSchema, 'body'),         // ← Validation middleware
  catchAsync([feature]Controller.create), // ← Error wrapping
);

[feature]Routes.get(
  '/:id',
  auth('ACCESS', [Roles.User, Roles.Admin]),
  catchAsync([feature]Controller.findById),
);

Key utilities:

  • auth(tokenType, allowedRoles) — JWT verification
  • validate(schema, 'body'|'query'|'params') — Input validation
  • catchAsync(fn) — Wrapper that catches promise rejections

2. Controller Layer ([feature].controller.ts)

Responsibility: Extract request data, call service, format response
Does: req.body, req.query, req.params → service call → ResponseHandler.ok()
Does NOT: Business logic, database queries

export const [feature]Controller = {
  create: async (req: Request, res: Response, next: NextFunction) => {
    const { body } = req;
    const result = await [feature]Service.create(body);
    
    // Service returns AppError or data
    if (result instanceof AppError) {
      next(result);
      return;
    }
    
    ResponseHandler.created(res, result, 'Created successfully');
  },
  
  findAll: async (req: Request, res: Response, next: NextFunction) => {
    const { query } = req;
    const { data, meta } = await [feature]Service.findAll(query);
    if (data instanceof AppError) {
      next(data);
      return;
    }
    ResponseHandler.ok(res, data, 'Fetched successfully', meta);
  },
};

Pattern:

  1. Extract req data
  2. Call service (which returns AppError | data)
  3. Check for AppErrornext(error)
  4. Otherwise → ResponseHandler.ok() or .created()

3. Service Layer ([feature].service.ts)

Responsibility: Business logic, data orchestration, mapper usage
Does: Calls repository → transforms data (via mappers) → returns AppError | data
Does NOT: Direct database queries, HTTP handling

export const [feature]Service = {
  create: async (input: CreateDto): Promise\x3CAppError | [Feature]Dto> => {
    // Validate business rules (not input format — that's the request layer)
    const existing = await [feature]Repository.findByEmail(input.email);
    if (existing) {
      return new AppError('CONFLICT', 'Email already exists');
    }
    
    // Call repository
    const entity = await [feature]Repository.create(input);
    
    // Transform entity to DTO via mapper
    return [feature]Mapper.toDtoArray([entity])[0];
  },
  
  findAll: async (query: QueryParams) => {
    const { page = 1, perPage = 10 } = query;
    const result = await [feature]Repository.findAll(page, perPage);
    
    return {
      data: [feature]Mapper.toDtoArray(result.data),
      meta: {
        currentPage: page,
        totalPages: Math.ceil(result.count / perPage),
        perPage,
        totalEntries: result.count,
      },
    };
  },
};

Pattern:

  • Accept DTOs (validated input from request layer)
  • Call repository for data access
  • Use mapper to transform entities → DTOs
  • Return AppError | data (union type)

4. Repository Layer ([feature].repository.ts)

Responsibility: Raw database access via Prisma
Does: prisma.model.query() — nothing else
Does NOT: Business logic, data transformation

export const [feature]Repository = {
  create: async (input: CreateDto) => {
    return prisma.[feature].create({
      data: input,
    });
  },
  
  findAll: async (page: number, perPage: number) => {
    const skip = (page - 1) * perPage;
    const [data, count] = await Promise.all([
      prisma.[feature].findMany({
        skip,
        take: perPage,
        where: { deletedAt: null }, // Soft delete filter
      }),
      prisma.[feature].count({
        where: { deletedAt: null },
      }),
    ]);
    return { data, count };
  },
};

Pattern:

  • Direct Prisma calls
  • No business logic
  • Return raw entity objects

DTO & Mapper Pattern

DTO (Data Transfer Object) — TypeScript interface defining what data leaves the system:

// [feature].dto.ts
export interface [Feature]Dto {
  id: string;
  name: string;
  email: string;
  createdAt: Date;
}

Mapper — Transform database entity to DTO:

// [feature].mapper.ts
export const [feature]Mapper = {
  toDto(entity: [FeatureEntity]): [Feature]Dto {
    return {
      id: entity.id,
      name: entity.name,
      email: entity.email,
      createdAt: entity.createdAt,
    };
  },
  
  toDtoArray(entities: [FeatureEntity][]): [Feature]Dto[] {
    return entities.map(e => this.toDto(e));
  },
};

Error Handling

Central error class:

export class AppError extends Error {
  constructor(
    public readonly code: ErrorCode, // 'BAD_REQUEST', 'UNAUTHORIZED', etc.
    message?: string,
  ) {
    super(message);
  }
}

Error codes (from interface/index.ts):

export const ERROR_CODE = {
  BAD_REQUEST: { code: 'BAD_REQUEST', message: 'Bad Request', httpStatus: 400 },
  UNAUTHORIZED: { code: 'UNAUTHORIZED', message: 'Unauthorized', httpStatus: 401 },
  FORBIDDEN: { code: 'FORBIDDEN', message: 'Forbidden', httpStatus: 403 },
  NOT_FOUND: { code: 'NOT_FOUND', message: 'Not Found', httpStatus: 404 },
  CONFLICT: { code: 'CONFLICT', message: 'Resource already exists', httpStatus: 409 },
  INTERNAL_SERVER_ERROR: { code: 'INTERNAL_SERVER_ERROR', httpStatus: 500 },
  // ... extend as needed
};

Centralized error handler middleware:

export const errorHandler: ErrorRequestHandler = (
  err: AppError | Error,
  req: Request,
  res: Response,
) => {
  if (err instanceof AppError) {
    return res.status(err.httpStatus).json({
      status: 'error',
      error: {
        code: err.code,
        message: err.message,
      },
    });
  }
  
  // Fallback for unhandled errors
  console.error(err.stack);
  res.status(500).json({
    status: 'error',
    error: { code: 'INTERNAL_SERVER_ERROR', message: 'Internal Server Error' },
  });
};

Response Format

Success response:

{
  "status": "success",
  "message": "User created successfully",
  "data": { "id": "123", "name": "John", "email": "[email protected]" },
  "meta": null
}

Paginated response:

{
  "status": "success",
  "data": [{ "id": "1" }, { "id": "2" }],
  "meta": {
    "currentPage": 1,
    "totalPages": 5,
    "perPage": 10,
    "totalEntries": 42
  }
}

Error response:

{
  "status": "error",
  "error": {
    "code": "NOT_FOUND",
    "message": "User not found"
  }
}

Validation Pattern

Request file defines Joi schema + TypeScript type:

// [feature].request.ts
import Joi from 'joi';

export const createSchema = Joi.object({
  name: Joi.string().required(),
  email: Joi.string().email().required(),
  phone: Joi.string().optional(),
});

export type CreateRequest = {
  name: string;
  email: string;
  phone?: string;
};

Route uses it:

[feature]Routes.post(
  '/',
  validate(createSchema, 'body'), // Validates against schema
  catchAsync([feature]Controller.create),
);

Controller receives typed input:

create: async (req: Request, res: Response) => {
  const body = req.body as CreateRequest; // Already validated + typed
  // ...
};

Middleware Stack

Standard middleware order in index.ts:

app.use(express.json());
app.use(cors());
app.use(securityHeaders());
app.use(requestLogger());

app.use('/api', routes);

app.use(errorHandler); // Must be last

Authentication Pattern

JWT middleware extracts and verifies token:

export const auth = (tokenType: 'ACCESS' | 'REFRESH', roles?: Role[]) => {
  return async (req: Request, res: Response, next: NextFunction) => {
    const token = req.headers.authorization?.split(' ')[1];
    if (!token) {
      return next(new AppError('UNAUTHORIZED'));
    }
    
    try {
      const payload = jwt.verify(token, process.env.JWT_SECRET!);
      if (roles && !roles.includes(payload.role)) {
        return next(new AppError('FORBIDDEN'));
      }
      (req as any).user = payload;
      next();
    } catch {
      next(new AppError('UNAUTHORIZED'));
    }
  };
};

Key Utilities

See references/utilities.md for helper functions:

  • catchAsync(fn) — Promise error wrapper
  • ResponseHandler — Response formatting
  • validate(schema, field) — Request validation middleware
  • handlePrismaError(err) — Convert Prisma errors to AppError

When Implementing Features

  1. Define request schema[feature].request.ts
  2. Define DTOs[feature].dto.ts
  3. Create repository[feature].repository.ts (Prisma queries only)
  4. Create service[feature].service.ts (business logic)
  5. Create controller[feature].controller.ts (request/response)
  6. Create mapper[feature].mapper.ts (entity → DTO)
  7. Create routes[feature].route.ts (HTTP endpoints)
  8. Register routes — Add to routes/index.ts

Checklist Before Merge

  • All layers follow the pattern (route → controller → service → repository)
  • Service returns AppError | data (union type)
  • Controller checks for AppError before responding
  • Validation happens in request layer, not service
  • DTOs defined, mappers used for entity transformation
  • Error codes added to ERROR_CODE if new errors introduced
  • Prisma queries in repository layer only
  • Business logic in service layer only
  • No database access in controller
  • Response uses ResponseHandler
  • Auth middleware applied where needed
  • Tests written for service layer (unit tests easy to write with pure functions)

References

  • See references/senior-engineer-mindset.mdREAD THIS FIRST — Thinking patterns, API design, security, performance, code quality standards
  • See references/error-handling.md — Error patterns and Prisma error conversion
  • See references/validation.md — Joi + Zod usage
  • See references/utilities.md — Helper functions explained
  • See assets/templates/ — Boilerplate code samples

Senior Engineer Standard

Before implementing anything, read references/senior-engineer-mindset.md. It defines the quality bar expected of every implementation:

  • REST API design: correct status codes, resource naming, nesting rules
  • Data modeling: audit fields, soft delete, naming conventions
  • Error philosophy: explicit errors, meaningful messages, no swallowing
  • Performance: no N+1, always paginate, parallel queries, select only needed fields
  • Security: validate everything, never expose sensitive data, service-level authorization
  • Code quality: early return, no magic values, explicit naming, short focused functions

An implementation that passes functionality but violates these principles is not complete.

安全使用建议
This package appears to be a standard Node/TypeScript backend template (Express + Prisma + Joi/Zod patterns). Before installing or running it: 1) Inspect config/config.ts and other files that reference process.env — the templates expect DATABASE_URL and JWT_SECRET and will throw if missing. 2) Only supply real database credentials or JWT secrets after you verify the code and trust the source; use throwaway/dev credentials when evaluating. 3) The registry metadata does not list the runtime dependencies or required env vars — treat that as an author oversight and confirm required packages (Node, npm/Yarn, Prisma, TypeScript, Express, Joi/Zod) are installed. 4) Because the source/homepage is unknown, review the templates and references yourself (they are included) to ensure there are no hidden endpoints or telemetry before using in production. If you want higher assurance, request the skill author to declare required env vars and provide a source/homepage or a signed release.
功能分析
Type: OpenClaw Skill Name: backend-developer Version: 1.0.0 The 'backend-developer' skill bundle provides a comprehensive and professional framework for building Node.js/TypeScript REST APIs using Express and Prisma. It includes well-structured templates for a 4-layer architecture (Route, Controller, Service, Repository) and detailed documentation in SKILL.md and the references directory regarding security best practices, input validation, and error handling. No indicators of malicious intent, data exfiltration, or harmful prompt injection were found; the bundle is clearly designed to assist an AI agent in generating high-quality, production-ready backend code.
能力评估
Purpose & Capability
The name/description match the included templates and references: Express + TypeScript + Prisma + validation + layered architecture. However, the skill's manifest declares no required env vars or binaries while the templates and config explicitly expect Node.js/TypeScript, Prisma client, and environment variables (DATABASE_URL, JWT_SECRET). This mismatch looks like an oversight in metadata rather than malicious intent, but it is important operationally.
Instruction Scope
SKILL.md and the provided files limit actions to generating/using API templates, validation, error handling, and Prisma DB access. The instructions and code do not instruct the agent to read unrelated local files or exfiltrate data. They do, however, include code that will read process.env for DB and JWT configuration when run.
Install Mechanism
There is no install spec (instruction-only with template files). That lowers risk because nothing in the registry will automatically download or execute remote code. To run the templates you will need to install normal Node/npm dependencies locally (express, prisma, joi/zod, etc.).
Credentials
The code and references expect sensitive environment variables (e.g., DATABASE_URL, JWT_SECRET) and will validate/require them at startup (config/config.ts throws if missing). Yet the registry metadata lists no required env vars or primary credential. Requesting DB credentials and JWT secret is proportionate for a backend template, but the omission from metadata is an inconsistency the user should be aware of before supplying secrets to any third-party templates.
Persistence & Privilege
The skill is not always-on and does not request elevated platform privileges. It doesn't modify other skill configs or system-wide settings. Autonomous invocation is allowed by platform default but there is no sign this combines with other red flags.
如何使用
  1. 确保已安装 OpenClaw(本地或 Docker 部署)
  2. 在对话框中输入安装命令:/install backend-developer
  3. 安装完成后,直接呼叫该 Skill 的名称或使用 /backend-developer 触发
  4. 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
版本历史
v1.0.0
Initial publish
元数据
Slug backend-developer
版本 1.0.0
许可证 MIT-0
累计安装 0
当前安装数 0
历史版本数 1
常见问题

backend developer 是什么?

Standardized backend REST API development following layered architecture patterns (Route → Controller → Service → Repository). Use when building new REST API... 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 125 次。

如何安装 backend developer?

在 OpenClaw 或 Claude Code 对话框中运行命令「/install backend-developer」即可一键安装,无需额外配置。

backend developer 是免费的吗?

是的,backend developer 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。

backend developer 支持哪些平台?

backend developer 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。

谁开发了 backend developer?

由 Bayu Dwi Satriyo(@bayudsatriyo)开发并维护,当前版本 v1.0.0。

💬 留言讨论