go-create-chi-handler
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGo Create Chi Handler
Go 生成Chi HTTP处理器
Generate Chi HTTP handler implementations for a Go backend.
为Go后端生成Chi HTTP处理器实现。
Handler Structure
处理器结构
Location:
internal/modules/<module>/http/chi/handler/<resource>_handler.gogo
package handler
import (
"net/http"
"strconv"
"github.com/cristiano-pacheco/bricks/pkg/http/request"
"github.com/cristiano-pacheco/bricks/pkg/http/response"
"github.com/cristiano-pacheco/bricks/pkg/logger"
"github.com/cristiano-pacheco/pingo/internal/modules/<module>/http/dto"
"github.com/cristiano-pacheco/pingo/internal/modules/<module>/usecase"
"github.com/go-chi/chi/v5"
)
type ResourceHandler struct {
resourceCreateUseCase *usecase.ResourceCreateUseCase
resourceListUseCase *usecase.ResourceListUseCase
resourceUpdateUseCase *usecase.ResourceUpdateUseCase
resourceDeleteUseCase *usecase.ResourceDeleteUseCase
errorHandler response.ErrorHandler
logger logger.Logger
}
func NewResourceHandler(
resourceCreateUseCase *usecase.ResourceCreateUseCase,
resourceListUseCase *usecase.ResourceListUseCase,
resourceUpdateUseCase *usecase.ResourceUpdateUseCase,
resourceDeleteUseCase *usecase.ResourceDeleteUseCase,
errorHandler response.ErrorHandler,
logger logger.Logger,
) *ResourceHandler {
return &ResourceHandler{
resourceCreateUseCase: resourceCreateUseCase,
resourceListUseCase: resourceListUseCase,
resourceUpdateUseCase: resourceUpdateUseCase,
resourceDeleteUseCase: resourceDeleteUseCase,
errorHandler: errorHandler,
logger: logger,
}
}位置:
internal/modules/<module>/http/chi/handler/<resource>_handler.gogo
package handler
import (
"net/http"
"strconv"
"github.com/cristiano-pacheco/bricks/pkg/http/request"
"github.com/cristiano-pacheco/bricks/pkg/http/response"
"github.com/cristiano-pacheco/bricks/pkg/logger"
"github.com/cristiano-pacheco/pingo/internal/modules/<module>/http/dto"
"github.com/cristiano-pacheco/pingo/internal/modules/<module>/usecase"
"github.com/go-chi/chi/v5"
)
type ResourceHandler struct {
resourceCreateUseCase *usecase.ResourceCreateUseCase
resourceListUseCase *usecase.ResourceListUseCase
resourceUpdateUseCase *usecase.ResourceUpdateUseCase
resourceDeleteUseCase *usecase.ResourceDeleteUseCase
errorHandler response.ErrorHandler
logger logger.Logger
}
func NewResourceHandler(
resourceCreateUseCase *usecase.ResourceCreateUseCase,
resourceListUseCase *usecase.ResourceListUseCase,
resourceUpdateUseCase *usecase.ResourceUpdateUseCase,
resourceDeleteUseCase *usecase.ResourceDeleteUseCase,
errorHandler response.ErrorHandler,
logger logger.Logger,
) *ResourceHandler {
return &ResourceHandler{
resourceCreateUseCase: resourceCreateUseCase,
resourceListUseCase: resourceListUseCase,
resourceUpdateUseCase: resourceUpdateUseCase,
resourceDeleteUseCase: resourceDeleteUseCase,
errorHandler: errorHandler,
logger: logger,
}
}DTOs (Data Transfer Objects)
DTO(数据传输对象)
Request and response DTOs are defined in .
internal/modules/<module>/http/dto/<resource>_dto.goTypical DTO structure:
go
package dto
type CreateResourceRequest struct {
Field1 string `json:"field1"`
Field2 int `json:"field2"`
}
type CreateResourceResponse struct {
ID uint64 `json:"id"`
Field1 string `json:"field1"`
Field2 int `json:"field2"`
}
type UpdateResourceRequest struct {
Field1 string `json:"field1"`
Field2 int `json:"field2"`
}
type ResourceResponse struct {
ID uint64 `json:"id"`
Field1 string `json:"field1"`
Field2 int `json:"field2"`
}Key points:
- DTOs live in the HTTP transport layer, separate from use case inputs or models
- Use JSON tags for serialization
- Keep DTOs focused on HTTP contract, not domain logic
请求和响应DTO定义在中。
internal/modules/<module>/http/dto/<resource>_dto.go典型DTO结构:
go
package dto
type CreateResourceRequest struct {
Field1 string `json:"field1"`
Field2 int `json:"field2"`
}
type CreateResourceResponse struct {
ID uint64 `json:"id"`
Field1 string `json:"field1"`
Field2 int `json:"field2"`
}
type UpdateResourceRequest struct {
Field1 string `json:"field1"`
Field2 int `json:"field2"`
}
type ResourceResponse struct {
ID uint64 `json:"id"`
Field1 string `json:"field1"`
Field2 int `json:"field2"`
}核心要点:
- DTO位于HTTP传输层,与用例输入或模型分离
- 使用JSON标签进行序列化
- DTO需聚焦于HTTP契约,而非领域逻辑
Handler Method Patterns
处理器方法模式
List (GET /resource)
列表(GET /resource)
go
// @Summary List resources
// @Description Retrieves all resources
// @Tags Resources
// @Accept json
// @Produce json
// @Security BearerAuth
// @Success 200 {object} response.Envelope[[]dto.ResourceResponse] "Successfully retrieved resources"
// @Failure 401 {object} errs.Error "Invalid credentials"
// @Failure 500 {object} errs.Error "Internal server error"
// @Router /api/v1/resources [get]
func (h *ResourceHandler) ListResources(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
output, err := h.resourceListUseCase.Execute(ctx)
if err != nil {
h.logger.Error("failed to list resources", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
resources := make([]dto.ResourceResponse, len(output.Resources))
for i, resource := range output.Resources {
resources[i] = dto.ResourceResponse{
ID: resource.ID,
Name: resource.Name,
// ... map other fields
}
}
err = response.JSON(w, http.StatusOK, resources, http.Header{})
if err != nil {
h.logger.Error("failed to write response", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
}go
// @Summary 列出资源
// @Description 获取所有资源
// @Tags 资源
// @Accept json
// @Produce json
// @Security BearerAuth
// @Success 200 {object} response.Envelope[[]dto.ResourceResponse] "成功获取资源列表"
// @Failure 401 {object} errs.Error "凭证无效"
// @Failure 500 {object} errs.Error "内部服务器错误"
// @Router /api/v1/resources [get]
func (h *ResourceHandler) ListResources(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
output, err := h.resourceListUseCase.Execute(ctx)
if err != nil {
h.logger.Error("failed to list resources", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
resources := make([]dto.ResourceResponse, len(output.Resources))
for i, resource := range output.Resources {
resources[i] = dto.ResourceResponse{
ID: resource.ID,
Name: resource.Name,
// ... 映射其他字段
}
}
err = response.JSON(w, http.StatusOK, resources, http.Header{})
if err != nil {
h.logger.Error("failed to write response", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
}Create (POST /resource)
创建(POST /resource)
go
// @Summary Create resource
// @Description Creates a new resource
// @Tags Resources
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body dto.CreateResourceRequest true "Resource data"
// @Success 201 {object} response.Envelope[dto.CreateResourceResponse] "Successfully created resource"
// @Failure 422 {object} errs.Error "Invalid request format or validation error"
// @Failure 401 {object} errs.Error "Invalid credentials"
// @Failure 500 {object} errs.Error "Internal server error"
// @Router /api/v1/resources [post]
func (h *ResourceHandler) CreateResource(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var createRequest dto.CreateResourceRequest
err := request.ReadJSON(w, r, &createRequest)
if err != nil {
h.logger.Error("failed to parse request body", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
input := usecase.ResourceCreateInput{
Name: createRequest.Name,
// ... map other fields
}
output, err := h.resourceCreateUseCase.Execute(ctx, input)
if err != nil {
h.logger.Error("failed to create resource", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
createResponse := dto.CreateResourceResponse{
ID: output.ID,
Name: output.Name,
// ... map other fields
}
err = response.JSON(w, http.StatusCreated, createResponse, http.Header{})
if err != nil {
h.logger.Error("failed to write response", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
}go
// @Summary 创建资源
// @Description 创建新资源
// @Tags 资源
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body dto.CreateResourceRequest true "资源数据"
// @Success 201 {object} response.Envelope[dto.CreateResourceResponse] "成功创建资源"
// @Failure 422 {object} errs.Error "请求格式无效或验证错误"
// @Failure 401 {object} errs.Error "凭证无效"
// @Failure 500 {object} errs.Error "内部服务器错误"
// @Router /api/v1/resources [post]
func (h *ResourceHandler) CreateResource(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var createRequest dto.CreateResourceRequest
err := request.ReadJSON(w, r, &createRequest)
if err != nil {
h.logger.Error("failed to parse request body", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
input := usecase.ResourceCreateInput{
Name: createRequest.Name,
// ... 映射其他字段
}
output, err := h.resourceCreateUseCase.Execute(ctx, input)
if err != nil {
h.logger.Error("failed to create resource", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
createResponse := dto.CreateResourceResponse{
ID: output.ID,
Name: output.Name,
// ... 映射其他字段
}
err = response.JSON(w, http.StatusCreated, createResponse, http.Header{})
if err != nil {
h.logger.Error("failed to write response", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
}Update (PUT /resource/:id)
更新(PUT /resource/:id)
go
// @Summary Update resource
// @Description Updates an existing resource
// @Tags Resources
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "Resource ID"
// @Param request body dto.UpdateResourceRequest true "Resource data"
// @Success 204 "Successfully updated resource"
// @Failure 422 {object} errs.Error "Invalid request format or validation error"
// @Failure 401 {object} errs.Error "Invalid credentials"
// @Failure 404 {object} errs.Error "Resource not found"
// @Failure 500 {object} errs.Error "Internal server error"
// @Router /api/v1/resources/{id} [put]
func (h *ResourceHandler) UpdateResource(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var updateRequest dto.UpdateResourceRequest
err := request.ReadJSON(w, r, &updateRequest)
if err != nil {
h.logger.Error("failed to parse request body", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
idStr := chi.URLParam(r, "id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
h.logger.Error("invalid resource ID", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
input := usecase.ResourceUpdateInput{
ID: id,
Name: updateRequest.Name,
// ... map other fields
}
err = h.resourceUpdateUseCase.Execute(ctx, input)
if err != nil {
h.logger.Error("failed to update resource", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
response.NoContent(w)
}go
// @Summary 更新资源
// @Description 更新已有资源
// @Tags 资源
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "资源ID"
// @Param request body dto.UpdateResourceRequest true "资源数据"
// @Success 204 "成功更新资源"
// @Failure 422 {object} errs.Error "请求格式无效或验证错误"
// @Failure 401 {object} errs.Error "凭证无效"
// @Failure 404 {object} errs.Error "资源不存在"
// @Failure 500 {object} errs.Error "内部服务器错误"
// @Router /api/v1/resources/{id} [put]
func (h *ResourceHandler) UpdateResource(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var updateRequest dto.UpdateResourceRequest
err := request.ReadJSON(w, r, &updateRequest)
if err != nil {
h.logger.Error("failed to parse request body", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
idStr := chi.URLParam(r, "id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
h.logger.Error("invalid resource ID", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
input := usecase.ResourceUpdateInput{
ID: id,
Name: updateRequest.Name,
// ... 映射其他字段
}
err = h.resourceUpdateUseCase.Execute(ctx, input)
if err != nil {
h.logger.Error("failed to update resource", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
response.NoContent(w)
}Delete (DELETE /resource/:id)
删除(DELETE /resource/:id)
go
// @Summary Delete resource
// @Description Deletes an existing resource
// @Tags Resources
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "Resource ID"
// @Success 204 "Successfully deleted resource"
// @Failure 401 {object} errs.Error "Invalid credentials"
// @Failure 404 {object} errs.Error "Resource not found"
// @Failure 500 {object} errs.Error "Internal server error"
// @Router /api/v1/resources/{id} [delete]
func (h *ResourceHandler) DeleteResource(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
idStr := chi.URLParam(r, "id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
h.logger.Error("invalid resource ID", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
input := usecase.ResourceDeleteInput{
ID: id,
}
err = h.resourceDeleteUseCase.Execute(ctx, input)
if err != nil {
h.logger.Error("failed to delete resource", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
response.NoContent(w)
}go
// @Summary 删除资源
// @Description 删除已有资源
// @Tags 资源
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "资源ID"
// @Success 204 "成功删除资源"
// @Failure 401 {object} errs.Error "凭证无效"
// @Failure 404 {object} errs.Error "资源不存在"
// @Failure 500 {object} errs.Error "内部服务器错误"
// @Router /api/v1/resources/{id} [delete]
func (h *ResourceHandler) DeleteResource(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
idStr := chi.URLParam(r, "id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
h.logger.Error("invalid resource ID", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
input := usecase.ResourceDeleteInput{
ID: id,
}
err = h.resourceDeleteUseCase.Execute(ctx, input)
if err != nil {
h.logger.Error("failed to delete resource", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
response.NoContent(w)
}Get by ID (GET /resource/:id)
详情(GET /resource/:id)
go
// @Summary Get resource
// @Description Retrieves a resource by ID
// @Tags Resources
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "Resource ID"
// @Success 200 {object} response.Envelope[dto.ResourceResponse] "Successfully retrieved resource"
// @Failure 401 {object} errs.Error "Invalid credentials"
// @Failure 404 {object} errs.Error "Resource not found"
// @Failure 500 {object} errs.Error "Internal server error"
// @Router /api/v1/resources/{id} [get]
func (h *ResourceHandler) GetResource(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
idStr := chi.URLParam(r, "id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
h.logger.Error("invalid resource ID", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
input := usecase.ResourceGetInput{
ID: id,
}
output, err := h.resourceGetUseCase.Execute(ctx, input)
if err != nil {
h.logger.Error("failed to get resource", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
resourceResponse := dto.ResourceResponse{
ID: output.ID,
Name: output.Name,
// ... map other fields
}
err = response.JSON(w, http.StatusOK, resourceResponse, http.Header{})
if err != nil {
h.logger.Error("failed to write response", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
}go
// @Summary 获取资源详情
// @Description 通过ID获取资源
// @Tags 资源
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "资源ID"
// @Success 200 {object} response.Envelope[dto.ResourceResponse] "成功获取资源详情"
// @Failure 401 {object} errs.Error "凭证无效"
// @Failure 404 {object} errs.Error "资源不存在"
// @Failure 500 {object} errs.Error "内部服务器错误"
// @Router /api/v1/resources/{id} [get]
func (h *ResourceHandler) GetResource(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
idStr := chi.URLParam(r, "id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
h.logger.Error("invalid resource ID", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
input := usecase.ResourceGetInput{
ID: id,
}
output, err := h.resourceGetUseCase.Execute(ctx, input)
if err != nil {
h.logger.Error("failed to get resource", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
resourceResponse := dto.ResourceResponse{
ID: output.ID,
Name: output.Name,
// ... 映射其他字段
}
err = response.JSON(w, http.StatusOK, resourceResponse, http.Header{})
if err != nil {
h.logger.Error("failed to write response", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
}Swagger Annotation Rules
Swagger注解规则
- @Summary: Brief action description (e.g., "List resources", "Create resource")
- @Description: Full description of what the endpoint does
- @Tags: Plural resource name (e.g., "Resources", "Contacts")
- @Accept: Always
json - @Produce: Always
json - @Security: Add if authentication required
BearerAuth - @Param: Define path params and request body
- Path param:
@Param id path int true "Resource ID" - Request body:
@Param request body dto.CreateResourceRequest true "Resource data"
- Path param:
- @Success: Status code with response type
- 200:
{object} response.Envelope[dto.ResourceResponse] - 201:
{object} response.Envelope[dto.CreateResourceResponse] - 204: No content, just description string
- 200:
- @Failure: Common errors (401, 404, 422, 500) with
{object} errs.Error - @Router:
/api/v1/resources/{id} [method]
- @Summary:简短的操作描述(如“列出资源”、“创建资源”)
- @Description:端点功能的完整描述
- @Tags:复数形式的资源名称(如“资源”、“联系人”)
- @Accept:始终为
json - @Produce:始终为
json - @Security:若需要认证则添加
BearerAuth - @Param:定义路径参数和请求体
- 路径参数:
@Param id path int true "资源ID" - 请求体:
@Param request body dto.CreateResourceRequest true "资源数据"
- 路径参数:
- @Success:包含响应类型的状态码
- 200:
{object} response.Envelope[dto.ResourceResponse] - 201:
{object} response.Envelope[dto.CreateResourceResponse] - 204: 无内容,仅描述字符串
- 200:
- @Failure:常见错误(401、404、422、500)使用
{object} errs.Error - @Router:
/api/v1/resources/{id} [method]
Request/Response Mapping
请求/响应映射
Handler methods bridge HTTP requests/responses (DTOs from ) with use case inputs/outputs.
internal/modules/<module>/http/dto处理器方法作为HTTP请求/响应(来自的DTO)与用例输入/输出之间的桥梁。
internal/modules/<module>/http/dtoRequest to Use Case Input
请求到用例输入
go
// Decode request
var req dto.CreateResourceRequest
err := request.ReadJSON(w, r, &req)
if err != nil {
h.logger.Error("failed to parse request body", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
// Map to use case input
input := usecase.ResourceCreateInput{
Field1: req.Field1,
Field2: req.Field2,
}go
// 解析请求
var req dto.CreateResourceRequest
err := request.ReadJSON(w, r, &req)
if err != nil {
h.logger.Error("failed to parse request body", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
// 映射到用例输入
input := usecase.ResourceCreateInput{
Field1: req.Field1,
Field2: req.Field2,
}Use Case Output to Response
用例输出到响应
go
// Execute use case
output, err := h.resourceCreateUseCase.Execute(ctx, input)
if err != nil {
h.logger.Error("failed to create resource", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
// Map to response DTO
response := dto.CreateResourceResponse{
ID: output.ID,
Field1: output.Field1,
Field2: output.Field2,
}go
// 执行用例
output, err := h.resourceCreateUseCase.Execute(ctx, input)
if err != nil {
h.logger.Error("failed to create resource", logger.Error(err))
h.errorHandler.Error(w, err)
return
}
// 映射到响应DTO
response := dto.CreateResourceResponse{
ID: output.ID,
Field1: output.Field1,
Field2: output.Field2,
}Error Handling Pattern
错误处理模式
Every error follows this pattern:
go
if err != nil {
h.logger.Error("descriptive error message", logger.Error(err))
h.errorHandler.Error(w, err)
return
}Error messages:
- "failed to parse request body" - JSON decode error
- "invalid resource ID" - URL param parsing error
- "failed to list resources" - List use case error
- "failed to create resource" - Create use case error
- "failed to update resource" - Update use case error
- "failed to delete resource" - Delete use case error
- "failed to get resource" - Get use case error
- "failed to write response" - JSON response write error
所有错误均遵循以下模式:
go
if err != nil {
h.logger.Error("descriptive error message", logger.Error(err))
h.errorHandler.Error(w, err)
return
}错误消息:
- "failed to parse request body" - JSON解析错误
- "invalid resource ID" - URL参数解析错误
- "failed to list resources" - 列表用例错误
- "failed to create resource" - 创建用例错误
- "failed to update resource" - 更新用例错误
- "failed to delete resource" - 删除用例错误
- "failed to get resource" - 详情用例错误
- "failed to write response" - JSON响应写入错误
Fx Wiring
Fx依赖注入配置
Add to :
internal/modules/<module>/fx.gogo
fx.Provide(handler.NewResourceHandler),The handler is typically provided to the router, not exposed as a port.
添加到:
internal/modules/<module>/fx.gogo
fx.Provide(handler.NewResourceHandler),处理器通常会注入到路由中,而非作为端口暴露。
Critical Rules
关键规则
- Struct: Include all use cases, , and
response.ErrorHandlerlogger.Logger - Constructor: MUST return pointer
*ResourceHandler - Context: Always get from request:
ctx := r.Context() - Request decoding: Use - declare variable first, then call ReadJSON
request.ReadJSON(w, r, &dto) - URL params: Use and
chi.URLParam(r, "paramName")for IDsstrconv.ParseUint - Error handling: Always log error and call then return
h.errorHandler.Error(w, err) - Response mapping: Map use case output to DTO, don't return use case outputs directly
- Success responses:
- List/Get: Use
response.JSON(w, http.StatusOK, data, http.Header{}) - Create: Use
response.JSON(w, http.StatusCreated, data, http.Header{}) - Update/Delete: Use
response.NoContent(w)
- List/Get: Use
- Swagger: MUST add complete swagger annotations for every handler method
- No comments: Do not add redundant comments inside method bodies
- Validation: Run and
make lintafter generationmake update-swagger
- 结构体:需包含所有用例依赖、和
response.ErrorHandlerlogger.Logger - 构造函数:必须返回指针
*ResourceHandler - 上下文:始终从请求中获取:
ctx := r.Context() - 请求解析:使用- 先声明变量,再调用ReadJSON
request.ReadJSON(w, r, &dto) - URL参数:使用和
chi.URLParam(r, "paramName")处理IDstrconv.ParseUint - 错误处理:始终记录错误并调用后返回
h.errorHandler.Error(w, err) - 响应映射:将用例输出映射到DTO,不要直接返回用例输出
- 成功响应:
- 列表/详情:使用
response.JSON(w, http.StatusOK, data, http.Header{}) - 创建:使用
response.JSON(w, http.StatusCreated, data, http.Header{}) - 更新/删除:使用
response.NoContent(w)
- 列表/详情:使用
- Swagger:必须为每个处理器方法添加完整的Swagger注解
- 无冗余注释:方法体内不要添加多余注释
- 验证:生成后运行和
make lintmake update-swagger
Workflow
工作流程
- Create handler struct with use case dependencies
- Implement constructor
NewResourceHandler - Implement handler methods following patterns above
- Add swagger annotations to all methods
- Add Fx wiring to module's
fx.go - Run and
make lintto verify the static testsmake nilaway - Run to regenerate swagger docs
make update-swagger
- 创建包含用例依赖的处理器结构体
- 实现构造函数
NewResourceHandler - 按照上述模式实现处理器方法
- 为所有方法添加Swagger注解
- 在模块的中添加Fx依赖注入配置
fx.go - 运行和
make lint验证静态测试make nilaway - 运行重新生成Swagger文档
make update-swagger