Token导航 LogoToken导航TokenDH.com
研究检索敏感数据github未标认证来源可访问许可证需确认审计通过

vaporvapor 搜索

Agent Skill

vapor 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

360

周安装

15

GitHub Stars

8

下载量

120
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:vapor(vapor 搜索)
来源仓库:https://github.com/ar4mirez/samuel
仓库路径:skills/vapor
安装命令:
npx skills add https://github.com/ar4mirez/samuel --skill vapor
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/ar4mirez/samuel --skill vapor

简介

vapor 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中快速定位候选结果。

  • 它支持根据关键词、任务场景或来源线索进行信息匹配,适用于研究类工作流。
  • 通过 npx skills add 命令从指定 GitHub 仓库安装并使用。
  • 安装前建议确认权限范围、维护状态及是否触发联网或文件操作。
  • vapor 属于研究检索类 Skill,可作为该场景下的辅助能力补充。

SKILL.md

Vapor Framework Guide

Applies to: Vapor 4.x, Swift 5.9+, Fluent ORM, Leaf Templates, Server-Side Swift Language Guide: @.claude/skills/swift-guide/SKILL.md

Overview

Vapor is a server-side Swift framework for building web applications, REST APIs, and backend services. It provides type-safe routing, Fluent ORM, async/await concurrency, JWT authentication, and Leaf templating.

Use Vapor when:

  • Building Swift-native backend services
  • Sharing code between iOS/macOS clients and the server
  • You need type-safe, compile-time-checked API development
  • You want async/await patterns throughout the stack

Consider alternatives when:

  • Team lacks Swift experience
  • You need a massive middleware ecosystem (consider Express, Rails)
  • Maximum raw performance is critical (consider Rust/Actix-web)

Guardrails

Vapor-Specific Rules

  • Use the @main entry point pattern with Application.make
  • Group routes by resource with RouteCollection controllers
  • Use Fluent property wrappers (@ID, @Field, @Parent, @Children) for models
  • Use Content protocol for all request/response DTOs
  • Use Validatable protocol for input validation on every endpoint
  • Use AsyncMiddleware for cross-cutting concerns (auth, logging, CORS)
  • Use AsyncMigration with both prepare and revert methods
  • Configure databases from environment variables (never hardcode credentials)
  • Use DTOs to separate API contracts from database models
  • Implement pagination for all list endpoints
  • Use @Sendable on all route handler closures
  • Mark model classes as @unchecked Sendable (Fluent requirement)

Anti-Patterns

  • Do not expose Fluent models directly as API responses (use DTOs)
  • Do not put business logic in controllers (use a service layer)
  • Do not use autoMigrate in production (run migrations explicitly)
  • Do not skip revert in migrations (always provide rollback)
  • Do not use try! or fatalError in request handlers
  • Do not store request-scoped state in global variables

Project Structure

MyVaporApp/
├── Package.swift
├── Sources/
│   └── App/
│       ├── Controllers/        # RouteCollection implementations
│       │   ├── UserController.swift
│       │   └── AuthController.swift
│       ├── Models/             # Fluent models
│       │   ├── User.swift
│       │   └── Post.swift
│       ├── DTOs/               # Request/response types (Content + Validatable)
│       │   ├── UserDTO.swift
│       │   └── CreateUserRequest.swift
│       ├── Migrations/         # AsyncMigration implementations
│       │   ├── CreateUser.swift
│       │   └── CreatePost.swift
│       ├── Middleware/         # AsyncMiddleware implementations
│       │   ├── JWTAuthMiddleware.swift
│       │   └── AppErrorMiddleware.swift
│       ├── Services/          # Business logic (protocol + implementation)
│       │   ├── UserService.swift
│       │   └── EmailService.swift
│       ├── Extensions/
│       │   └── Request+Extensions.swift
│       ├── configure.swift    # Database, middleware, JWT, Leaf setup
│       ├── routes.swift       # Top-level route registration
│       └── entrypoint.swift   # @main entry point
├── Tests/
│   └── AppTests/
│       ├── UserControllerTests.swift
│       └── AuthControllerTests.swift
├── Resources/
│   └── Views/                 # Leaf templates
│       └── index.leaf
├── Public/                    # Static files
│   ├── css/
│   └── js/
└── docker-compose.yml

Layer responsibilities:

  • Controllers/ -- HTTP routing only: parse request, call service, write response
  • Services/ -- Business logic, orchestration, domain rules
  • Models/ -- Fluent database models with property wrappers
  • DTOs/ -- Request/response types with validation (Content + Validatable)
  • Migrations/ -- Schema changes with prepare and revert
  • Middleware/ -- Cross-cutting: auth, error handling, CORS, logging

Application Setup

Entry Point and Configuration

// entrypoint.swift
import Vapor
import Logging

@main
enum Entrypoint {
    static func main() async throws {
        var env = try Environment.detect()
        try LoggingSystem.bootstrap(from: &env)
        let app = try await Application.make(env)
        do {
            try await configure(app)
            try await app.execute()
        } catch {
            app.logger.report(error: error)
            try? await app.asyncShutdown()
            throw error
        }
    }
}

// configure.swift -- database, middleware, migrations, routes
func configure(_ app: Application) async throws {
    app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
    app.middleware.use(AppErrorMiddleware())
    app.middleware.use(CORSMiddleware())

    // Database (always from environment variables)
    if let databaseURL = Environment.get("DATABASE_URL") {
        try app.databases.use(.postgres(url: databaseURL), as: .psql)
    } else {
        app.databases.use(.postgres(
            hostname: Environment.get("DB_HOST") ?? "localhost",
            port: Environment.get("DB_PORT").flatMap(Int.init) ?? 5432,
            username: Environment.get("DB_USER") ?? "vapor",
            password: Environment.get("DB_PASSWORD") ?? "vapor",
            database: Environment.get("DB_NAME") ?? "vapor_dev"
        ), as: .psql)
    }

    app.migrations.add(CreateUser())
    if app.environment == .development { try await app.autoMigrate() }
    try routes(app)
}

// routes.swift -- group public vs protected
func routes(_ app: Application) throws {
    app.get("health") { _ -> HTTPStatus in .ok }
    let api = app.grouped("api", "v1")
    try api.register(collection: AuthController())

    let protected = api.grouped(JWTAuthMiddleware())
    try protected.register(collection: UserController())
}

Routing with Controllers

struct UserController: RouteCollection {
    func boot(routes: RoutesBuilder) throws {
        let users = routes.grouped("users")
        users.get(use: index)
        users.get(":userID", use: show)
        users.put(":userID", use: update)
        users.delete(":userID", use: delete)
    }

    @Sendable
    func index(req: Request) async throws -> PaginatedResponse<UserResponse> {
        let page = try req.query.decode(PageRequest.self)
        let result = try await User.query(on: req.db)
            .filter(\.$isActive == true)
            .sort(\.$createdAt, .descending)
            .paginate(PageRequest(page: page.page, per: page.per))
        let items = try result.items.map { try UserResponse(user: $0) }
        return PaginatedResponse(items: items, metadata: PageMetadata(
            page: page.page, perPage: page.per,
            total: result.metadata.total, totalPages: result.metadata.pageCount
        ))
    }

    @Sendable
    func show(req: Request) async throws -> UserResponse {
        guard let user = try await User.find(req.parameters.get("userID"), on: req.db) else {
            throw Abort(.notFound, reason: "User not found")
        }
        return try UserResponse(user: user)
    }
}

Conventions: Implement RouteCollection per resource. Use @Sendable on all handlers. Validate before processing. Return DTOs, not Fluent models.

Fluent Models

Model with Property Wrappers

import Fluent
import Vapor

final class User: Model, Content, @unchecked Sendable {
    static let schema = "users"

    @ID(key: .id)
    var id: UUID?

    @Field(key: "email")
    var email: String

    @Field(key: "password_hash")
    var passwordHash: String

    @Enum(key: "role")
    var role: Role

    @Timestamp(key: "created_at", on: .create)
    var createdAt: Date?

    @Timestamp(key: "updated_at", on: .update)
    var updatedAt: Date?

    @Children(for: \.$user)
    var posts: [Post]

    init() {}

    init(id: UUID? = nil, email: String, passwordHash: String, role: Role = .user) {
        self.id = id
        self.email = email
        self.passwordHash = passwordHash
        self.role = role
    }

    enum Role: String, Codable, CaseIterable {
        case admin, user, guest
    }
}

Model conventions:

  • Always mark as final class conforming to Model, Content, @unchecked Sendable
  • Use @ID(key:.id) for UUID primary keys
  • Use @Timestamp for created_at and updated_at
  • Use @Parent/@Children/@Siblings for relationships
  • Provide an empty init() (Fluent requirement)

Migrations

import Fluent

struct CreateUser: AsyncMigration {
    func prepare(on database: Database) async throws {
        let role = try await database.enum("user_role")
            .case("admin").case("user").case("guest")
            .create()

        try await database.schema("users")
            .id()
            .field("email", .string, .required)
            .field("password_hash", .string, .required)
            .field("role", role, .required)
            .field("created_at", .datetime)
            .field("updated_at", .datetime)
            .unique(on: "email")
            .create()
    }

    func revert(on database: Database) async throws {
        try await database.schema("users").delete()
        try await database.enum("user_role").delete()
    }
}

Migration rules:

  • Always implement both prepare and revert
  • Create enums before referencing them in schema
  • Delete enums in revert after deleting the table
  • Use .references() for foreign keys with onDelete behavior
  • Add indexes for frequently queried columns

DTOs and Validation

Request/Response DTOs

import Vapor

struct CreateUserRequest: Content, Validatable {
    let email: String
    let password: String
    let name: String

    static func validations(_ validations: inout Validations) {
        validations.add("email", as: String.self, is: .email)
        validations.add("password", as: String.self, is: .count(8...))
        validations.add("name", as: String.self, is: !.empty)
    }
}

struct UserResponse: Content {
    let id: UUID
    let email: String
    let name: String
    let role: User.Role
    let createdAt: Date?

    init(user: User) throws {
        self.id = try user.requireID()
        self.email = user.email
        self.name = user.name
        self.role = user.role
        self.createdAt = user.createdAt
    }
}

DTO conventions:

  • Request types conform to Content + Validatable
  • Response types conform to Content only
  • Always validate in the controller before processing: try CreateUserRequest.validate(content: req)
  • Use Validatable rules: .email, .count(range), !.empty, .url, .alphanumeric

Middleware

Custom AsyncMiddleware

import Vapor
import JWT

struct JWTAuthMiddleware: AsyncMiddleware {
    func respond(
        to request: Request,
        chainingTo next: any AsyncResponder
    ) async throws -> Response {
        guard let token = request.headers.bearerAuthorization?.token else {
            throw Abort(.unauthorized, reason: "Missing authorization token")
        }

        let payload = try await request.jwt.verify(token, as: UserPayload.self)

        guard let userID = UUID(payload.subject.value),
              let user = try await User.find(userID, on: request.db),
              user.isActive else {
            throw Abort(.unauthorized, reason: "User not found or inactive")
        }

        request.auth.login(user)
        return try await next.respond(to: request)
    }
}

Error Middleware

import Vapor

struct AppErrorMiddleware: AsyncMiddleware {
    func respond(
        to request: Request,
        chainingTo next: any AsyncResponder
    ) async throws -> Response {
        do {
            return try await next.respond(to: request)
        } catch let abort as AbortError {
            let body = ErrorResponse(error: true, reason: abort.reason, code: abort.status.code)
            return try await body.encodeResponse(status: abort.status, for: request)
        } catch {
            request.logger.error("Unexpected error: \(error)")
            let reason = request.application.environment.isRelease
                ? "An internal error occurred" : error.localizedDescription
            let body = ErrorResponse(error: true, reason: reason, code: 500)
            return try await body.encodeResponse(status: .internalServerError, for: request)
        }
    }
}

struct ErrorResponse: Content {
    let error: Bool
    let reason: String
    let code: UInt
}

Content Negotiation

Vapor's Content protocol handles JSON automatically. Configure custom encoding in configure.swift:

let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
encoder.dateEncodingStrategy = .iso8601
ContentConfiguration.global.use(encoder: encoder, for: .json)

Authentication (JWT)

// configure.swift -- register signing key
guard let jwtSecret = Environment.get("JWT_SECRET") else {
    fatalError("JWT_SECRET environment variable not set")
}
await app.jwt.keys.add(hmac: HMACKey(from: jwtSecret), digestAlgorithm: .sha256)

// Payload definition
struct UserPayload: JWTPayload {
    var subject: SubjectClaim
    var expiration: ExpirationClaim
    var isAdmin: Bool?

    func verify(using algorithm: some JWTAlgorithm) throws {
        try expiration.verifyNotExpired()
    }
}

// Token generation (in login handler)
let payload = UserPayload(
    subject: .init(value: try user.requireID().uuidString),
    expiration: .init(value: Date().addingTimeInterval(3600))
)
let token = try await req.jwt.sign(payload)

Commands Reference

# Initialize project
swift package init --type executable --name MyVaporApp

# Resolve dependencies
swift package resolve

# Build and run
swift build
swift run App serve --hostname 0.0.0.0 --port 8080

# Run tests
swift test
swift test --filter AppTests

# Run database migrations manually
swift run App migrate
swift run App migrate --revert

# Docker build
docker build -t my-vapor-app .
docker compose up -d

Dependencies

PackagePurpose
vapor/vaporCore web framework
vapor/fluentORM abstraction
vapor/fluent-postgres-driverPostgreSQL support
vapor/fluent-sqlite-driverSQLite (development/testing)
vapor/redisRedis caching and sessions
vapor/jwtJWT authentication
vapor/leafTemplate engine
XCTVaporTesting utilities (included with Vapor)

Advanced Topics

For detailed patterns, WebSocket integration, Leaf templates, queues, testing, and deployment, see:

  • references/patterns.md -- Fluent query patterns, relationships, eager loading, WebSocket, Leaf templates, background queues, comprehensive testing, Docker deployment

External References

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

33.67%
按下载量换算40

Claude

29.59%
按下载量换算36

Cursor

19.8%
按下载量换算24

Gemini CLI

9.56%
按下载量换算11

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills