Golang REST API 文件结构这样设计合理吗?

Golang REST API 文件结构这样设计合理吗? 我正在为我的REST API使用这个结构,这样没问题吗?我使用的是gin-gonic。

OtEfM

5 回复

谢谢,但你觉得我的结构怎么样?

更多关于Golang REST API 文件结构这样设计合理吗?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


非常感谢大家的回复,所有功能都完美运行,非常感谢各位。

虽然没有为Go语言相关的REST API制定结构的具体规则,但你可以采用一些最佳实践来设计端点,例如:

图片

RESTful API设计:最佳实践精要

设计HTTP和RESTful API的最佳实践。介绍URL结构、HTTP方法、关系、分页和版本控制。

关于文件结构,我为每个端点使用一个文件,相应地命名,并加上api前缀以区别于常规文件。

嗯,我对你的项目一无所知,所以我的观点可能非常主观,但我可以提出一些观察,不是因为事情做错了,而是因为从我的角度来看,可以做得更好。

然而,一般来说,如果你有大量的端点,将端点放入包中可能是有用的,否则在主程序和包之间进行数据交换会有点烦人。另外,我不知道你为什么使用一个中间的 lib 文件夹,因为看起来你的项目不是一个库,而更像是一些服务(如果我错了,请跳过阅读这一段 😄)。

根据一些约定,大写字母用于常量或某些方法(例如 GET、PUT 等),而不是包名,所以我会避免使用 ROUTES,而使用 routes

另一点是在包路径中使用相对路径,这不是一个好的做法(互联网上有很多关于此的解释)。你应该考虑使用绝对路径、GOPATH、vendoring 或 Go 模块。

这个文件结构设计存在几个问题,建议调整如下:

主要问题:

  1. 控制器直接依赖模型,导致业务逻辑与数据层紧耦合
  2. 缺少服务层处理业务逻辑
  3. 路由定义分散在控制器中

改进后的结构示例:

project/
├── cmd/
│   └── api/
│       └── main.go
├── internal/
│   ├── handler/
│   │   ├── user_handler.go
│   │   └── product_handler.go
│   ├── service/
│   │   ├── user_service.go
│   │   └── product_service.go
│   ├── repository/
│   │   ├── user_repository.go
│   │   └── product_repository.go
│   └── model/
│       ├── user.go
│       └── product.go
├── pkg/
│   ├── config/
│   ├── middleware/
│   └── utils/
├── api/
│   └── routes.go
├── go.mod
└── go.sum

示例代码实现:

// internal/handler/user_handler.go
package handler

import (
	"net/http"
	"yourproject/internal/service"
	
	"github.com/gin-gonic/gin"
)

type UserHandler struct {
	userService service.UserService
}

func NewUserHandler(us service.UserService) *UserHandler {
	return &UserHandler{userService: us}
}

func (h *UserHandler) GetUser(c *gin.Context) {
	id := c.Param("id")
	user, err := h.userService.GetUserByID(id)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, user)
}

// internal/service/user_service.go
package service

import (
	"yourproject/internal/model"
	"yourproject/internal/repository"
)

type UserService interface {
	GetUserByID(id string) (*model.User, error)
}

type userService struct {
	userRepo repository.UserRepository
}

func NewUserService(ur repository.UserRepository) UserService {
	return &userService{userRepo: ur}
}

func (s *userService) GetUserByID(id string) (*model.User, error) {
	return s.userRepo.FindByID(id)
}

// internal/repository/user_repository.go
package repository

import "yourproject/internal/model"

type UserRepository interface {
	FindByID(id string) (*model.User, error)
}

type userRepository struct {
	// db connection
}

func NewUserRepository() UserRepository {
	return &userRepository{}
}

func (r *userRepository) FindByID(id string) (*model.User, error) {
	// database query implementation
	return &model.User{ID: id, Name: "John Doe"}, nil
}

// api/routes.go
package api

import (
	"yourproject/internal/handler"
	"yourproject/internal/repository"
	"yourproject/internal/service"
	
	"github.com/gin-gonic/gin"
)

func SetupRouter() *gin.Engine {
	r := gin.Default()
	
	// Dependency injection
	userRepo := repository.NewUserRepository()
	userService := service.NewUserService(userRepo)
	userHandler := handler.NewUserHandler(userService)
	
	// Routes
	v1 := r.Group("/api/v1")
	{
		v1.GET("/users/:id", userHandler.GetUser)
	}
	
	return r
}

// cmd/api/main.go
package main

import (
	"yourproject/api"
)

func main() {
	r := api.SetupRouter()
	r.Run(":8080")
}

这种分层架构(Handler → Service → Repository)提供了更好的关注点分离、可测试性和可维护性。

回到顶部