skills/aaaaqwq/claude-code-skills/backend-development-nodejs

backend-development-nodejs

SKILL.md

๐ŸŸข Node.js ๅŽ็ซฏๅผ€ๅ‘ไธ“ๅฎถ

่€็Ž‹ๆˆ‘ไนŸ็ŽฉNode.jsๅพˆๅคšๅนดไบ†๏ผŒ่ฟ™็Žฉๆ„ๅ„ฟๅ†™ๅŽ็ซฏ็œŸtm้กบๆ‰‹๏ผ

ๆŠ€ๆœฏๆ ˆๅ…จๆ™ฏ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    Node.js ๅŽ็ซฏๆŠ€ๆœฏๆ ˆ                        โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  Webๆก†ๆžถ                                                     โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”        โ”‚
โ”‚  โ”‚ NestJS  โ”‚  โ”‚ Express โ”‚  โ”‚  Koa    โ”‚  โ”‚ Fastify โ”‚        โ”‚
โ”‚  โ”‚ ไผไธš็บง  โ”‚  โ”‚ ็ปๅ…ธ    โ”‚  โ”‚ ่ฝป้‡    โ”‚  โ”‚ ้ซ˜ๆ€ง่ƒฝ  โ”‚        โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜        โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  ๆ•ฐๆฎๅฑ‚                                                      โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                     โ”‚
โ”‚  โ”‚ Prisma  โ”‚  โ”‚ TypeORM โ”‚  โ”‚ Mongooseโ”‚                     โ”‚
โ”‚  โ”‚ ๆ–ฐไธ€ไปฃ  โ”‚  โ”‚ ็ปๅ…ธORM โ”‚  โ”‚ MongoDB โ”‚                     โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                     โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  ๅฎžๆ—ถ้€šไฟก                                                    โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                   โ”‚
โ”‚  โ”‚Socket.ioโ”‚  โ”‚  WS     โ”‚                                   โ”‚
โ”‚  โ”‚ ๅ…จๅŠŸ่ƒฝ  โ”‚  โ”‚ ๅŽŸ็”Ÿ    โ”‚                                   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                   โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  API้ฃŽๆ ผ                                                     โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                   โ”‚
โ”‚  โ”‚  REST   โ”‚  โ”‚ GraphQL โ”‚                                   โ”‚
โ”‚  โ”‚ ็ปๅ…ธ    โ”‚  โ”‚ ็ตๆดปๆŸฅ่ฏขโ”‚                                   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

NestJS - ไผไธš็บง้ฆ–้€‰

้กน็›ฎ็ป“ๆž„๏ผˆๆœ€ไฝณๅฎž่ทต๏ผ‰

my-project/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ main.ts                  # ๅบ”็”จๅ…ฅๅฃ
โ”‚   โ”œโ”€โ”€ app.module.ts            # ๆ นๆจกๅ—
โ”‚   โ”œโ”€โ”€ config/                  # ้…็ฝฎ
โ”‚   โ”‚   โ”œโ”€โ”€ configuration.ts
โ”‚   โ”‚   โ””โ”€โ”€ validation.schema.ts
โ”‚   โ”œโ”€โ”€ common/                  # ้€š็”จๆจกๅ—
โ”‚   โ”‚   โ”œโ”€โ”€ decorators/
โ”‚   โ”‚   โ”œโ”€โ”€ filters/
โ”‚   โ”‚   โ”œโ”€โ”€ guards/
โ”‚   โ”‚   โ”œโ”€โ”€ interceptors/
โ”‚   โ”‚   โ”œโ”€โ”€ pipes/
โ”‚   โ”‚   โ””โ”€โ”€ interfaces/
โ”‚   โ”œโ”€โ”€ modules/                 # ๅŠŸ่ƒฝๆจกๅ—
โ”‚   โ”‚   โ”œโ”€โ”€ auth/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ auth.module.ts
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ auth.controller.ts
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ auth.service.ts
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ strategies/
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ guards/
โ”‚   โ”‚   โ”œโ”€โ”€ users/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ users.module.ts
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ users.controller.ts
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ users.service.ts
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ entities/
โ”‚   โ”‚   โ””โ”€โ”€ posts/
โ”‚   โ”œโ”€โ”€ database/                # ๆ•ฐๆฎๅบ“
โ”‚   โ”‚   โ”œโ”€โ”€ migrations/
โ”‚   โ”‚   โ””โ”€โ”€ seeds/
โ”‚   โ””โ”€โ”€ mail/                    # ้‚ฎไปถ็ญ‰ๅค–้ƒจๆœๅŠก
โ”œโ”€โ”€ test/
โ”‚   โ”œโ”€โ”€ unit/
โ”‚   โ””โ”€โ”€ e2e/
โ”œโ”€โ”€ .env.example
โ”œโ”€โ”€ nest-cli.json
โ”œโ”€โ”€ tsconfig.json
โ””โ”€โ”€ package.json

Prisma + NestJS ๅฎŒๆ•ด้›†ๆˆ

// prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  password  String
  name      String
  isActive  Boolean  @default(true)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  posts     Post[]
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
// modules/users/users.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { User } from '@prisma/client';
import * as bcrypt from 'bcrypt';

@Injectable()
export class UsersService {
  constructor(private prisma: PrismaService) {}

  async findAll(): Promise<User[]> {
    return this.prisma.user.findMany({
      select: {
        id: true,
        email: true,
        name: true,
        isActive: true,
        createdAt: true,
        password: false, // ๆŽ’้™คๅฏ†็ ๅญ—ๆฎต
      },
    });
  }

  async findOne(id: number): Promise<User> {
    const user = await this.prisma.user.findUnique({
      where: { id },
      select: {
        id: true,
        email: true,
        name: true,
        isActive: true,
        createdAt: true,
        password: false,
      },
    });

    if (!user) {
      throw new NotFoundException(`User #${id} not found`);
    }

    return user;
  }

  async findByEmail(email: string): Promise<User | null> {
    return this.prisma.user.findUnique({
      where: { email },
    });
  }

  async create(data: {
    email: string;
    password: string;
    name: string;
  }): Promise<User> {
    const hashedPassword = await bcrypt.hash(data.password, 10);

    return this.prisma.user.create({
      data: {
        ...data,
        password: hashedPassword,
      },
      select: {
        id: true,
        email: true,
        name: true,
        isActive: true,
        createdAt: true,
        password: false,
      },
    });
  }

  async update(id: number, data: Partial<User>): Promise<User> {
    const user = await this.findOne(id);

    if (data.password) {
      data.password = await bcrypt.hash(data.password, 10);
    }

    return this.prisma.user.update({
      where: { id },
      data,
      select: {
        id: true,
        email: true,
        name: true,
        isActive: true,
        createdAt: true,
        password: false,
      },
    });
  }

  async remove(id: number): Promise<User> {
    return this.prisma.user.delete({
      where: { id },
      select: {
        id: true,
        email: true,
        name: true,
        isActive: true,
        createdAt: true,
        password: false,
      },
    });
  }
}

JWT + Passport ่ฎค่ฏ

// modules/auth/strategies/jwt.strategy.ts
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(private configService: ConfigService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      secretOrKey: configService.get<string>('JWT_SECRET'),
    });
  }

  async validate(payload: any) {
    return { userId: payload.sub, email: payload.email };
  }
}

// modules/auth/guards/jwt-auth.guard.ts
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}

// modules/auth/decorators/current-user.decorator.ts
import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const CurrentUser = createParamDecorator(
  (data: unknown, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    return request.user;
  },
);

// ไฝฟ็”จ็คบไพ‹
@UseGuards(JwtAuthGuard)
@Get('profile')
getProfile(@CurrentUser() user: any) {
  return user;
}

Validation Pipe + DTO

// dto/create-user.dto.ts
import { IsEmail, IsString, MinLength, IsOptional, IsBoolean } from 'class-validator';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';

export class CreateUserDto {
  @ApiProperty({ example: 'user@example.com' })
  @IsEmail()
  email: string;

  @ApiProperty({ example: 'John Doe', minLength: 2 })
  @IsString()
  @MinLength(2)
  name: string;

  @ApiProperty({ example: 'password123', minLength: 8 })
  @IsString()
  @MinLength(8)
  password: string;

  @ApiPropertyOptional({ default: true })
  @IsOptional()
  @IsBoolean()
  isActive?: boolean;
}

// main.ts - ๅ…จๅฑ€ๅฏ็”จ้ชŒ่ฏ
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true,      // ่‡ชๅŠจ็งป้™คๆœชๅฎšไน‰็š„ๅฑžๆ€ง
      forbidNonWhitelisted: true,  // ๆ‹’็ปๆœชๅฎšไน‰็š„ๅฑžๆ€ง
      transform: true,      // ่‡ชๅŠจ่ฝฌๆข็ฑปๅž‹
      transformOptions: {
        enableImplicitConversion: true,
      },
    }),
  );

  await app.listen(3000);
}

Express - ๅฟซ้€ŸๅŽŸๅž‹ๅผ€ๅ‘

Express + TypeScript ็ป“ๆž„ๅŒ–ๅ†™ๆณ•

// src/app.ts
import express, { Application, Request, Response, NextFunction } from 'express';
import cors from 'cors';
import helmet from 'helmet';
import compression from 'compression';
import { AppError, errorConverter, errorHandler } from './utils/errors';

class App {
  public app: Application;

  constructor() {
    this.app = express();
    this.initializeMiddlewares();
    this.initializeRoutes();
    this.initializeErrorHandling();
  }

  private initializeMiddlewares() {
    this.app.use(helmet());
    this.app.use(cors());
    this.app.use(compression());
    this.app.use(express.json());
    this.app.use(express.urlencoded({ extended: true }));
  }

  private initializeRoutes() {
    this.app.get('/health', (req: Request, res: Response) => {
      res.json({ status: 'ok', timestamp: new Date().toISOString() });
    });

    // API ่ทฏ็”ฑ
    this.app.use('/api/v1/users', userRoutes);
  }

  private initializeErrorHandling() {
    this.app.use(errorConverter);
    this.app.use(errorHandler);
  }
}

export default new App().app;

// src/routes/user.routes.ts
import { Router, Request, Response, NextFunction } from 'express';
import { UserService } from '../services/user.service';
import { authMiddleware } from '../middlewares/auth.middleware';
import { validate CreateUserDto } from '../validators/user.validator';

const router = Router();
const userService = new UserService();

router.get(
  '/',
  authMiddleware,
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const users = await userService.findAll();
      res.json({ success: true, data: users });
    } catch (error) {
      next(error);
    }
  }
);

router.post(
  '/',
  validate CreateUserDto,
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const user = await userService.create(req.body);
      res.status(201).json({ success: true, data: user });
    } catch (error) {
      next(error);
    }
  }
);

export default router;

Socket.io ๅฎžๆ—ถ้€šไฟก

// gateway/chat.gateway.ts
import {
  WebSocketGateway,
  SubscribeMessage,
  MessageBody,
  WebSocketServer,
  ConnectedSocket,
  OnGatewayInit,
  OnGatewayConnection,
  OnGatewayDisconnect,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';

@WebSocketGateway({
  cors: { origin: '*' },
  namespace: '/chat',
})
export class ChatGateway
  implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect
{
  @WebSocketServer()
  server: Server;

  private connectedClients: Map<string, Socket> = new Map();

  afterInit(server: Server) {
    console.log('WebSocket server initialized');
  }

  handleConnection(client: Socket) {
    const userId = client.handshake.query.userId as string;
    this.connectedClients.set(userId, client);
    console.log(`Client connected: ${userId}`);
  }

  handleDisconnect(client: Socket) {
    const userId = client.handshake.query.userId as string;
    this.connectedClients.delete(userId);
    console.log(`Client disconnected: ${userId}`);
  }

  @SubscribeMessage('sendMessage')
  handleMessage(
    @MessageBody() data: { roomId: string; message: string; userId: string },
    @ConnectedSocket() client: Socket,
  ) {
    // ๅนฟๆ’ญๆถˆๆฏๅˆฐๆˆฟ้—ด
    this.server.to(data.roomId).emit('newMessage', {
      userId: data.userId,
      message: data.message,
      timestamp: new Date().toISOString(),
    });
  }

  @SubscribeMessage('joinRoom')
  handleJoinRoom(
    @MessageBody() data: { roomId: string },
    @ConnectedSocket() client: Socket,
  ) {
    client.join(data.roomId);
    client.emit('joinedRoom', data.roomId);
  }
}

Redis ็ผ“ๅญ˜่ฃ…้ฅฐๅ™จ

// common/decorators/cache.decorator.ts
import { SetMetadata } from '@nestjs/common';

export const CACHE_KEY_METADATA = 'CACHE_KEY_METADATA';
export const CACHE_TTL_METADATA = 'CACHE_TTL_METADATA';

export const Cache = (key: string, ttl: number = 60) =>
  SetMetadata(CACHE_KEY_METADATA, { key, ttl });

// common/interceptors/cache.interceptor.ts
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable, of } from 'rxjs';
import { tap } from 'rxjs/operators';
import { RedisService } from '../services/redis.service';

@Injectable()
export class CacheInterceptor implements NestInterceptor {
  constructor(private redisService: RedisService) {}

  async intercept(context: ExecutionContext, next: CallHandler): Promise<Observable<any>> {
    const request = context.switchToHttp().getRequest();
    const cacheKey = `cache:${request.url}:${JSON.stringify(request.query)}`;

    // ๅฐ่ฏ•ไปŽ็ผ“ๅญ˜่Žทๅ–
    const cached = await this.redisService.get(cacheKey);
    if (cached) {
      return of(JSON.parse(cached));
    }

    return next.handle().pipe(
      tap(async (data) => {
        await this.redisService.set(cacheKey, JSON.stringify(data), 60);
      })
    );
  }
}

// ไฝฟ็”จ
@Injectable()
export class UsersService {
  @Cache('users:list', 300)
  async findAll() {
    return this.usersRepository.findAll();
  }
}

ไพ่ต–ๆŽจ่๏ผˆpackage.json๏ผ‰

{
  "dependencies": {
    "@nestjs/common": "^10.3.0",
    "@nestjs/core": "^10.3.0",
    "@nestjs/platform-express": "^10.3.0",
    "@nestjs/config": "^3.1.1",
    "@nestjs/jwt": "^10.2.0",
    "@nestjs/passport": "^10.0.3",
    "@nestjs/swagger": "^7.1.17",
    "@prisma/client": "^5.7.0",
    "passport": "^0.7.0",
    "passport-jwt": "^4.0.1",
    "passport-local": "^1.0.0",
    "bcrypt": "^5.1.1",
    "class-validator": "^0.14.0",
    "class-transformer": "^0.5.1",
    "helmet": "^7.1.0",
    "cors": "^2.8.5",
    "compression": "^1.7.4",
    "redis": "^4.6.11",
    "socket.io": "^4.6.0",
    "winston": "^3.11.0"
  },
  "devDependencies": {
    "@nestjs/cli": "^10.2.1",
    "@nestjs/schematics": "^10.1.0",
    "@types/express": "^4.17.21",
    "@types/node": "^20.10.6",
    "@types/passport-jwt": "^4.0.0",
    "typescript": "^5.3.3",
    "prisma": "^5.7.0",
    "jest": "^29.7.0",
    "supertest": "^6.3.3"
  }
}

่€็Ž‹ๅปบ่ฎฎ๏ผš

  • ไผไธš็บง้กน็›ฎ็›ดๆŽฅ็”จ NestJS + Prisma + TypeScript
  • ๅฟซ้€ŸๅŽŸๅž‹็”จ Express๏ผŒไฝ†่ฎฐๅพ—ๅŠ ไธŠ็ฑปๅž‹ๆฃ€ๆŸฅ
  • ๅฎžๆ—ถ้€šไฟก็”จ Socket.io๏ผŒๅˆซtm่‡ชๅทฑ้€ ่ฝฎๅญ
  • GraphQL ่€ƒ่™‘ TypeGraphQL๏ผŒ็ฑปๅž‹ๅฎ‰ๅ…จๅพˆ้‡่ฆ
  • ๅˆซๅฟ˜ไบ†ๅŠ ไธŠ Swagger ๆ–‡ๆกฃ๏ผŒๆŽฅๅฃๆ–‡ๆกฃ่‡ชๅŠจๅŒ–ๅพˆ้ฆ™๏ผ
Weekly Installs
1
GitHub Stars
13
First Seen
Feb 13, 2026
Installed on
codex1