Skip to content
cccskills
FreePublished on GitHub

crud-handler-http

PowerX HTTP Handler 规则(绑定校验、统一回包、无 DB IO)。

The English summary is being prepared. Showing the original description.

See how to install

Files included (1)

  • SKILL.md7.9 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

PowerX CRUD Handler HTTP

步骤

  1. 打开 本文件内嵌规则。
  2. 按规则执行实现/校对。
  3. 完成后按核对清单验收。

核对点

  • 与 PowerX 当前代码结构、路径与命名一致。
  • 仅在传输层/契约层做职责内改动,不跨层越界。

规则(内嵌)

handler_http.yaml

kind: ruleset
name: crud_handler_http
version: 1.0.0
owner: powerx
status: stable

meta:
  intent: >
    规范 HTTP Handler 的目录、职责与调用形态:参数绑定/校验 → 调用 Service → 统一回包/错误桥接,
    禁止业务与 DB/外部 IO;分页、错误、SSE 事件与 REST 契约/DTO 对齐。
  references:
    - dev_crud_http_guides.md
    - constitution.md

scope:
  applies_to:
    - "internal/transport/http/**/**_handler.go"
    - "internal/transport/http/**/api.go"

principles:
  - Handler 只做 绑定/校验 → 调 Service → 回包;禁止写业务、DB 或外部 IO。   # 指南·Handler职责
  - DTO 独立于模型;参数绑定使用统一函数,错误使用 AppError 桥接返回。      # 指南·DTO/错误桥接
  - 路由注册独立在 api.go;前缀使用 /api/v1/{admin|open|web}。               # 指南·路由与版本
  - 多租户上下文来自中间件;缺失租户返回 400 语义,鉴权在 Service 落实。       # 宪章·多租户

checks:

  # 目录 & 入口
  - id: http.dir.shape
    level: error
    when:
      glob: "internal/transport/http/**/api.go"
    assert:
      - must_define: "func Register*Routes(*gin.RouterGroup, *shared.Deps)"
      - must_prefix_route_one_of: ["/api/v1/admin", "/api/v1/open", "/api/v1/web"]

  # Handler 职责边界
  - id: handler.no_db_or_io
    level: error
    when:
      glob: "internal/transport/http/**/**_handler.go"
    assert:
      - must_not_import: ["database/sql","gorm.io/gorm","net/http"] # 允许 gin 但禁止直接 http client
      - must_not_call: ["sql.DB","gorm.DB","http.DefaultClient.Do","os.Remove","ioutil.ReadAll"]
      - must_define_like: "type *Handler struct { svc *service.* }" # 依赖仅指向 Service

  - id: handler.ctor
    level: error
    when:
      glob: "internal/transport/http/**/**_handler.go"
    assert:
      - must_define_like: "func New*Handler(*service.*) *"
      - must_not_define: "func New*Handler(*gorm.DB)"               # 禁止直注 DB

  # 租户上下文与校验/绑定
  - id: handler.binding_and_tenant
    level: error
    when:
      glob: "internal/transport/http/**/**_handler.go"
    assert:
      - must_call_one_of: ["ValidateRequestWithContext(","ValidateAndBindWithContext("]
      - must_call: ["reqctx.From(c)"]       # 从中间件注入的上下文取 tenant/request_id
      - on_missing_tenant_http: 400

  # 统一回包与错误桥接
  - id: handler.response_envelope
    level: error
    when:
      glob: "internal/transport/http/**/**_handler.go"
    assert:
      - must_use_one_of: ["ResponseSuccess(","RespondOK(","RespondErrorFrom("]
      - http_status_in: [200,201,204,400,401,403,404,409,429,500]

  # 分页语义统一
  - id: handler.pagination_contract
    level: error
    when:
      glob: "internal/transport/http/**/**_handler.go"
    assert:
      - must_bind_dto: ["PaginationRequest"]
      - must_return: ["ResponseList","PaginationResponse"]

  # SSE/WS(若涉及)
  - id: handler.sse_events
    level: warn
    when:
      contains: "WriteToSSE("
    assert:
      - must_use_events:
          ["start","intent","plan","token","data","action","final","end","error","heartbeat"]

  # 契约一致性(与 REST 资源路由)
  - id: handler.crud_shape
    level: error
    when:
      glob: "internal/transport/http/**/api.go"
    assert:
      - must_register_methods:
          - 'POST ""'
          - 'GET ""'
          - 'GET "/:id"'
          - 'PATCH "/:id"'
          - 'DELETE "/:id"'

  # 依赖注入(Deps)
  - id: handler.deps_injection
    level: error
    when:
      glob: "internal/transport/http/**/**_handler.go"
    assert:
      - must_reference: "*shared.Deps"   # Handler 通过 Deps 链路拿到 svc(在 api.go 中)
      - must_not_new_external_clients: true

acceptance:
  checklist:
    - "[ ] api.go 只做路由注册,使用 /api/v1/{admin|open|web} 前缀"
    - "[ ] Handler 仅做绑定/校验/调用 Service/回包,不含 DB 与外部 IO"
    - "[ ] 使用 ValidateRequestWithContext/RespondErrorFrom/ResponseSuccess 等统一工具"
    - "[ ] 分页使用 PaginationRequest/PaginationResponse,列表用 ResponseList"
    - "[ ] SSE 事件(若有)使用统一事件名"
    - "[ ] 租户上下文来自中间件,缺失返回 400;鉴权/审计在 Service 层"
    - "[ ] Handler 构造函数存在,依赖通过 *shared.Deps 提供 svc"

templates:

  handler_go: |
    package {{domain}}

    import (
      "github.com/gin-gonic/gin"
      "github.com/ArtisanCloud/PowerX/internal/app/shared"
      "github.com/ArtisanCloud/PowerX/internal/service/{{domain}}"
      dto "{{module_path}}/internal/transport/http/{{layer}}/{{domain}}/dto"
      "github.com/ArtisanCloud/PowerX/pkg/corex/iam/reqctx"
    )

    type {{Entity}}Handler struct {
      svc *{{domain}}.{{Entity}}Service
    }

    func New{{Entity}}Handler(s *{{domain}}.{{Entity}}Service) *{{Entity}}Handler {
      return &{{Entity}}Handler{svc: s}
    }

    // POST /{{domain}}/{{resource}}
    func (h *{{Entity}}Handler) Create(c *gin.Context) {
      ctx, rc, err := ValidateRequestWithContext(c, &dto.{{Entity}}CreateReq{})
      if err != nil { RespondErrorFrom(c, err); return }
      out, err := h.svc.Create(ctx, rc.TenantID, rc.ActorID, rc.RequestID, rc.TraceID, rc.Payload)
      if err != nil { RespondErrorFrom(c, err); return }
      ResponseSuccess(c, out)
    }

    // GET /{{domain}}/{{resource}}
    func (h *{{Entity}}Handler) List(c *gin.Context) {
      ctx, rc, err := ValidateRequestWithContext(c, &dto.{{Entity}}ListReq{})
      if err != nil { RespondErrorFrom(c, err); return }
      items, pg, err := h.svc.List(ctx, rc.TenantID, rc.Pagination, rc.Filters)
      if err != nil { RespondErrorFrom(c, err); return }
      ResponseSuccess(c, ResponseList{Items: items, Pagination: pg})
    }

    // GET /{{domain}}/{{resource}}/:id
    func (h *{{Entity}}Handler) Get(c *gin.Context) {
      ctx, rc, err := ValidateRequestWithContext(c, &dto.{{Entity}}GetReq{})
      if err != nil { RespondErrorFrom(c, err); return }
      out, err := h.svc.Get(ctx, rc.TenantID, rc.ID)
      if err != nil { RespondErrorFrom(c, err); return }
      ResponseSuccess(c, out)
    }

    // PATCH /{{domain}}/{{resource}}/:id
    func (h *{{Entity}}Handler) Update(c *gin.Context) {
      ctx, rc, err := ValidateRequestWithContext(c, &dto.{{Entity}}UpdateReq{})
      if err != nil { RespondErrorFrom(c, err); return }
      out, err := h.svc.Update(ctx, rc.TenantID, rc.ID, rc.Payload, rc.IfMatch) // 支持 If-Match/ETag(可选)
      if err != nil { RespondErrorFrom(c, err); return }
      ResponseSuccess(c, out)
    }

    // DELETE /{{domain}}/{{resource}}/:id
    func (h *{{Entity}}Handler) Delete(c *gin.Context) {
      ctx, rc, err := ValidateRequestWithContext(c, &dto.{{Entity}}DeleteReq{})
      if err != nil { RespondErrorFrom(c, err); return }
      err = h.svc.Delete(ctx, rc.TenantID, rc.ID, rc.Force) // 默认为软删;Force 需权限
      if err != nil { RespondErrorFrom(c, err); return }
      ResponseSuccess(c, ResponseSuccess{OK: true})
    }

  api_go: |
    package {{domain}}

    import (
      "github.com/gin-gonic/gin"
      "github.com/ArtisanCloud/PowerX/internal/app/shared"
    )

    func Register{{Domain}}Routes(rg *gin.RouterGroup, deps *shared.Deps) {
      h := New{{Entity}}Handler(deps.{{Entity}}Service)
      g := rg.Group("/{{domain}}/{{resource}}")
      {
        g.POST("", h.Create)
        g.GET("", h.List)
        g.GET("/:id", h.Get)
        g.PATCH("/:id", h.Update)
        g.DELETE("/:id", h.Delete)
      }
    }

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

PowerX API 命名与访问规范(/api/v1、/admin、/internal 边界)。

The English summary is being prepared. Showing the original description.

ArtisanCloud/PowerX382Updated Oct 19, 2026

PowerX 底座 Capability 治理与发布准入规则。用于审计 REST/OpenAPI/gRPC/Gin 生成的能力候选、正式 platform_capabilities 目录、Capability Registry 登记、agent_usable/permission_code/risk_level 元数据、ignore 清单和缺失能力;当用户要求“重新识别能力”“能力是否能发布”“补齐能力登记”“检查 capability-gen/audit/check”“底座接口暴露给插件/agent”时使用。

The English summary is being prepared. Showing the original description.

ArtisanCloud/PowerX382Updated Oct 19, 2026

PowerX REST 契约规则(资源命名、分页、错误、版本化)。

The English summary is being prepared. Showing the original description.

ArtisanCloud/PowerX382Updated Oct 19, 2026

PowerX CRUD 依赖注入规则(Deps 单入口、构造注入、跨传输复用)。

The English summary is being prepared. Showing the original description.

ArtisanCloud/PowerX382Updated Oct 19, 2026

PowerX CRUD DTO 规则(输入输出分离、分页、校验)。

The English summary is being prepared. Showing the original description.

ArtisanCloud/PowerX382Updated Oct 19, 2026

PowerX CRUD gRPC 开发规范(proto、server、拦截器、错误映射)。

The English summary is being prepared. Showing the original description.

ArtisanCloud/PowerX382Updated Oct 19, 2026

See all skills by ArtisanCloud

Report a problem with this skill