【问题标题】:Clean and generic project structure for GO applications and mongodb [closed]GO应用程序和mongodb的干净和通用的项目结构[关闭]
【发布时间】:2016-01-11 09:50:39
【问题描述】:

我想使用 GO 和 MongoDB 构建一个基于 API 的应用程序。我来自 Asp.net MVC 背景。如果我使用 MVC Web 应用程序创建架构,可能需要考虑的是

  1. 关注点分离(SoC)

    • 数据模型
    • 商业实体
    • 商业服务
    • 控制器
  2. 依赖注入和工作统一

  3. 单元测试
    • MoQ 或 nUnit
  4. 与 UI 框架集成
    • Angularjs 或其他
  5. 支持 SEO 的 RESTful 网址

下面的架构可能是我在基于 MVC 的应用程序中需要的解决方案

网络上有资源可以构建基于 Asp.Net 或 Java 的应用程序,但我还没有找到 Golang 应用程序架构的解决方案。

是的,GO 与 C# 或 Java 不同,但仍然有 Structs、Interfaces 来创建可重用代码和通用应用程序架构。 考虑以上几点,我们如何在 GO 应用程序中创建一个干净且可重用的项目结构以及用于 DB(Mongodb)事务的通用存储库。任何网络资源也是一个很好的起点。

【问题讨论】:

    标签: go architecture restful-architecture


    【解决方案1】:

    这取决于你自己的风格和规则,在我的公司,我们是这样开发我们的项目的:

    • 配置由环境变量决定,因此我们有一个company/envs/project.sh 文件,必须在之前服务(图片中的项目之外)对其进行评估。
    • 我们添加了一个zscripts 文件夹,其中包含所有额外的脚本,例如添加用户或发布帖子。仅用于调试建议。
    • 数据模型(实体)位于名为 project/models 的包中。
    • 所有控制器和视图(HTML 模板)都归类为“应用程序”或“模块”。我们使用 REST 路径作为主组分隔符,因此路径 /dogs 转到包 project/apps/dogs/catsproject/apps/cats
    • 经理位于项目根 project/manager 的单独包中。
    • 静态文件(.css、.png、.js 等)位于project/static/[app/]。有时需要有可选的[app/] 文件夹,但仅当两个应用程序具有仪表板或文件名冲突时才会发生。大多数情况下,您不需要将[app/] 用于静态资源。

    经理

    我们称之为管理器,一个包含纯函数的包,可以帮助应用程序执行其任务,例如数据库、缓存、S3 存储等。我们在开始监听之前初始化每个调用 package.Startup() 的管理器,并最终确定程序中断时调用package.Finalize()

    经理的例子可以是project/cache/cache.go

    type Config struct {
        RedisURL string `envconfig:"redis_url"`
    }
    
    var config Config
    var client *redis.Client
    
    func Startup(c Config) error {
       config = c
       client, err := redis.Dial(c.RedisURL)
       return err
    }
    
    func Set(k,v string) error {
       return client.Set(k, v)
    }
    

    在 main.go(或 your_thing_test.go)中:

    var spec cache.Config
    envconfig.Process("project", &spec)
    
    cache.Startup(spec)
    

    在应用程序(或模块)中:

    func SetCacheHandler(_ http.ResponseWriter, _ *http.Request){
       cache.Set("this", "rocks")
    }
    

    模块

    模块是与其他模块隔离的视图和控制器的容器,使用我们的配置,我建议不要在模块之间创建依赖关系。模块也称为应用程序。

    每个模块使用路由器、子路由器或您的框架提供的配置其路由,例如(文件project/apps/dogs/configure.go):

    func Configure(e *echo.Echo) {
        e.Get("/dogs", List)
    }
    

    然后,所有处理程序都住在project/apps/dogs/handlers.go

    // List outputs a dog list of all stored specimen.
    func List(c *echo.Context) error {
        // Note the use of models.Xyz
        var res := make([]models.Dog, 0) // A little trick to not return nil.
        err := store.FindAll("dogs", nil, &res) // Call manager to find all dogs.
        // handle error ...
    
        return c.JSON(200, res) // Output the dogs.
    }
    

    最后你在 main 中(或在测试中)配置应用程序:

    e := echo.New()
    dogs.Configure(e)
    // more apps
    
    e.Run(":8080")
    

    注意:对于视图,您可以将它们添加到project/apps/<name>/views 文件夹并使用相同的功能对其进行配置。

    其他

    有时我们还会添加一个project/constants 和一个project/utils 包。

    这是它的样子:

    请注意,在上面的示例中,templates 与应用程序分开,那是因为它是占位符,目录是空的。

    希望它有用。来自墨西哥的问候:D.

    【讨论】:

      【解决方案2】:

      过去,我也一直在为如何构建我的 Go Web API 而苦苦挣扎,并且不知道有任何 Web 资源可以准确地告诉您如何编写 Go Web API。

      我所做的只是查看 Github 上的其他项目,并尝试他们如何构建代码,例如,Docker 存储库的 API 上有非常惯用的 Go 代码。

      另外,Beego 是一个 RESTful 框架,它以 MVC 的方式为您生成项目结构,根据他们的docs,它也可以用于 API。

      【讨论】:

        【解决方案3】:

        我在 golang 中构建 Web API 已经有一段时间了。

        你必须做一些研究,但我可以给你一些起点:

        1. Building Web Apps with Go -- 电子书
        2. github.com/julienschmidt/httprouter -- 用于路由地址
        3. github.com/unrolled/render/ -- 用于呈现各种形式的响应(JSON、HTML 等)
        4. github.com/dgrijalva/jwt-go -- JSON Web 令牌
        5. www.gorillatoolkit.org/pkg/sessions -- 会话管理

        以及一些事情最终如何协同工作的参考:

        Go Web API Repo -- 个人项目

        【讨论】:

          【解决方案4】:

          1。关注点分离 (SoC)

          我没有直接使用 SoC,但我有自己的模式。您可以适应任何模式(MVC、您自己的等)。

          在我的代码中,我将代码分成不同的包:

          myprojectname (package main)      — Holds the very basic setup and configuration/project consts
            * handlers   (package handlers) — Holds the code that does the raw HTTP work
            * models     (package models)   — Holds the models
            * apis       (NOT a package)
              - redis    (package redis)    — Holds the code that wraps a `sync.Pool`
              - twilio   (package twilio)   — Example of layer to deal with external API
          

          注意事项:

          1. 在除 main 之外的每个包中,我都有一个由 main 包调用的 Setup() 函数(带有相关参数)。
          2. apis文件夹下的包,往往只是为了初始化外部Go库。您还可以直接将现有库导入到处理程序/模型中,无需 apis 包。
          3. 我像这样在handlers 包中将我的多路复用器设置为导出的全局...

            Router := mux.NewRouter()
            

            ...然后为每个 URL 创建一个文件(相同 URL 的不同方法在同一个文件中)。在每个文件中,我使用 Go 的 init() 函数,该函数在全局变量初始化之后运行(因此使用路由器是安全的)但在运行 main() 之前运行(因此 main 假设一切都已设置是安全的)。 init() 的伟大之处在于,您可以在单个包中拥有任意数量的这些方法,因此在导入包时它们会自动运行。

            Main 然后导入myprojectname/handlers,然后在main 中提供handlers.Router

          2。依赖注入和工作统一

          我没有使用 Unity of Work,所以我不知道可能的 Go 实现。

          对于 DI,我构建了一个接口,真实对象和模拟对象都将实现。

          在包中,我将这个添加到根目录:

          var DatabaseController DatabaseControllerInterface = DefaultController
          

          然后,每个测试的第一行我可以将DatabaseController 更改为测试需要的任何内容。不测试时不运行单元测试,默认为DefaultController

          3。单元测试

          Go 使用 go test package 命令提供内置测试。您也可以使用go test --cover 来发出覆盖百分比。你甚至可以have coverage displayed in your browser, highlighting the parts that are/aren't covered

          我使用 testify/assert 包来帮助我测试标准库的不足之处:

          // something_test.go
          //
          // The _test signifies it should only be compiled into a test
          // Name the file whatever you want, but if it's testing code
          // in a single file, I like to do filename_test.go.
          
          package main
          
          import (
              "testing"
          
              "github.com/stretchr/testify/assert"
          )
          
          func TestMath(t *testing.T) {
              assert.Equal(t, 3+1, 4)
          }
          

          4。与 UI 框架集成

          我还没有看到任何 Angular。虽然没用过,但是Go有一个不错的template engine built into the standard lib

          5。支持 SEO 的 RESTful URL

          再说一次,我在这里帮不了你。这取决于您:发送正确的状态代码(不要发送带有 404 页面的 200,因为您会因重复页面而停靠),不要重复页面(注意 google.com/somethinggoogle.com/something/;希望您的框架不会搞砸),不要试图欺骗搜索引擎,等等。

          【讨论】:

            【解决方案5】:

            在我看来,生产服务器上的 Go webapp 项目文件夹看起来就像你的图片上的那样简单得多。资产结构没有什么特别之处 - 静态、模板、内容、样式、Img、JSlibs、DBscripts 等常用文件夹。 WebAPI 没有什么特别之处 - 像往常一样,您设计哪个 URI 将响应所需的功能并将请求相应地路由到处理程序。一些细节 - 许多地鼠不相信 MVC 架构,这当然取决于你。并且您部署了一个没有依赖关系的静态链接可执行文件。在您的开发环境中,您可以像在 stdlib 中一样在 $GOPATH 中构建您的和导入/供应的源文件,但在生产环境中只部署一个可执行文件,确保需要静态资产。您可以在 stdlib 中查看如何组织 Go 源代码包。只有一个可执行文件,你会在生产中构建什么?

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-01-24
              • 1970-01-01
              相关资源
              最近更新 更多