我想使用GO和MongoDB构建基于API的应用程序。我来自Asp.net MVC背景。可能如果我使用MVC Web应用程序构建一个需要考虑的东西
关注点分离(SoC)
Dependeny注射和工作统一
以下架构可以解决我在基于MVC的应用程序中的需求
Web上有资源来构建基于Asp.Net或Java的应用程序,但我还没有找到Golang应用程序架构的解决方案。
是GO与C#或Java不同,但仍有Structs,Interfaces用于创建可重用代码和通用应用程序架构。 考虑以上几点,我们如何在GO应用程序中创建一个干净且可重用的项目结构,以及如何在DB(Mongodb)事务中创建一个通用的存储库。任何网络资源也是一个很好的起点。
答案 0 :(得分:11)
这取决于你自己的风格和规则,在我的公司,我们以这种方式开发项目:
company/envs/project.sh
文件,必须在服务之前进行评估(在图片中的项目之外)。zscripts
文件夹,其中包含所有额外脚本,例如添加用户或发布帖子。仅用于调试建议。project/models
的包中。/dogs
转到包project/apps/dogs
,/cats
转到project/apps/cats
。project/manager
的独立包中。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。
答案 1 :(得分:4)
我过去一直在努力构建如何构建我的Go Web API,并且不知道任何可以告诉您如何编写Go Web API的Web资源。
我所做的只是查看Github上的其他项目,并尝试他们如何构建代码,例如,Docker repo在其API上有非常独特的Go代码。
答案 2 :(得分:3)
我一直在golang中构建一个Web API。
你必须做一些研究,但我可以给你一些起点:
关于最终如何协同工作的参考:
Go Web API Repo - 个人项目
答案 3 :(得分:3)
在我看来生产服务器上的Go webapp项目文件夹看起来就像你的图片简单得多。资产结构没有什么特别之处 - 静态,模板,内容,样式,Img,JSlibs,DBscripts等常用文件夹。 WebAPI没有什么特别之处 - 像往常一样,您设计哪个URI将响应所需的功能并相应地将请求路由到处理程序。一些细节 - 许多地鼠不相信MVC架构,它肯定取决于你。并且您部署一个静态链接的可执行文件而没有依赖项。在您的开发环境中,您可以像在stdlib中那样在$ GOPATH中构建您的和导入/销售的sorce文件,但在生产环境中只部署一个可执行文件,当然需要静态资产。您可以在stdlib中看到如何对Go源包进行orginize。只有一个可执行文件,你会在生产中构建什么?
答案 4 :(得分:3)
我没有直接与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
备注:强>
Setup()
函数(带有相关参数),由主包调用。apis
文件夹下的软件包,它们通常只是初始化外部Go库。您还可以直接将现有库导入到处理程序/模型中,而无需apis
包。我将mux设置为handlers
包中的导出全局,如下所示...
Router := mux.NewRouter()
...然后为每个URL创建一个文件(具有相同URL的不同方法在同一个文件中)。在每个文件中,我使用Go的init()
函数,该函数在全局变量初始化之后运行(因此使用路由器是安全的)但是在运行main()
之前(因此对于main来说,假设所有内容都是安全的)已设置)。关于init()
的好处是你可以在一个包中拥有任意数量的方法,因此在导入包时它们会自动运行。
Main然后导入myprojectname/handlers
,然后在main中提供handlers.Router
。
我没有使用Unity of Work,所以我不知道可能的Go实现。
对于DI,我构建了一个真实对象和模拟对象都将实现的接口。
在包中,我将其添加到根目录:
var DatabaseController DatabaseControllerInterface = DefaultController
然后,每个测试的第一行我可以将DatabaseController
更改为测试所需的任何内容。不测试时,不应运行单元测试,默认为DefaultController
。
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)
}
我没见过Angular。虽然我没有使用它,但Go有一个很好的 template engine built into the standard lib。
再说一次,我在这里帮不了你。这取决于您:发送正确的状态代码(不要发送带有404页面的200,因为您将停靠重复页面),不要复制页面(注意google.com/something
vs {{1}希望你的框架不会弄乱这个),不要试图欺骗搜索引擎,等等。