Чистая и общая структура проекта для приложений GO и mongodb

Я хочу создать приложение на основе API, используя GO и MongoDB. Я из Asp.net фон MVC. Вероятно, если я создам архитектуру с веб-приложением MVC, то следует учитывать

  1. разделение проблем (SoC)

    • DataModel
    • BusinessEntities
    • BusinessServices
    • контроллеры
  2. Dependeny инъекции и единство работы

  3. единица Тестирование
    • MoQ или nUnit
  4. интеграция с UI framework
    • Angularjs или другие
  5. RESTful urls, который позволяет SEO

ниже архитектура может быть решением для моей потребности в приложениях на основе MVC

enter image description here

есть ресурсы по всему интернету, чтобы построить Asp.Net или приложения на основе Java, но я не нашел решения для Golang архитектура приложения.

Yes GO отличается от C# или Java, но все же есть структуры, интерфейсы для создания многоразового кода и общей архитектуры приложения. Рассмотрите выше моменты в виду, как мы можем сделать чистую и многоразовую структуру проекта в приложениях GO и общих репозиториях для транзакций DB(Mongodb). Любые веб-ресурсы также отличная точка для начала.

5 ответов


это зависит от вашего собственного стиля и правила, в моей компании, мы разрабатываем наши проекты таким образом:

  • конфигурация определяется переменными среды, поэтому у нас есть company/envs/project.sh файл, который должен быть оценен до сервис (вне проекта на изображении).
  • добавляем zscripts папка, содержащая все дополнительные скрипты, такие как добавление пользователей или публикация сообщения. Предназначен для использования только для отладки предложений.
  • модели данных (сущности) находятся в пакете с именем project/models.
  • все контроллеры и представления (шаблоны HTML) подразделяются на "приложения" или "модули". Мы используем путь REST в качестве основного разделителя группы, поэтому path /dogs идет в пакет project/apps/dogs и /cats to project/apps/cats.
  • менеджеры находятся в отдельном пакете в корне проекта project/manager.
  • статические файлы (.стиль CSS. ,формат PNG. ,js, etc.) находятся в project/static/[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")
}

модули

модуль-это контейнер представлений и контроллеров, изолированных от других модулей, используя нашу конфигурацию, я бы рекомендовал не создавать зависимости между модулями. Модули также называются приложениями.

каждый модуль настраивает свои маршруты с помощью маршрутизатора, суб-маршрутизатора или того, что предоставляет ваша платформа, например (file 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 пакета.

вот как это выглядит:

Example of project structure

обратите внимание, что в приведенном выше примере, templates отделены от приложений, это потому, что его прототип, каталог пуст.

надеюсь, это было полезно. Привет из Мексики :Д.


Я также боролся о том, как структурировать мой Go Web APIs в прошлом и не знаю никаких веб-ресурсов, которые говорят вам точно, как написать Go web API.

то, что я сделал, это просто проверить другие проекты на Github и попробовать, как они структурировали свой код, например,настройки РЕПО имеет очень idomatic код перейти на его API.

и похожа на любой - это RESTful framework, который генерирует структуру проекта для вас способом MVC и согласно их docs, Он также может использоваться для API.


Я построение веб-интерфейсов в golang для некоторое время теперь.

вам придется провести некоторые исследования, но я могу дать вам некоторые отправные точки:

  1. создание веб-приложений с 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 -- личный проект


на мой взгляд, папка проекта webapp на рабочем сервере может выглядеть на вашей картинке намного проще. Ничего особенного в структуре активов-статика, Шаблоны, контент, стили, Img, JSlibs, DBscripts и т. д. обычные папки. Ничего особенного в WebAPI - как обычно, вы разрабатываете, какой URI будет отвечать требуемым функциям и маршрутизировать запросы обработчикам соответственно. Некоторые особенности-многие суслики не верят в архитектуру MVC,это зависит от вас. И вы развернуть один staticaly связаны исполняемый файл без зависимостей. В вашей среде разработки вы структурируете свои и импортированные / вендорные файлы sorce в $GOPATH, как в stdlib, но развертываете только один исполняемый файл в производственной среде, конечно, со статическими активами. Вы можете увидеть, как организовать исходные пакеты Go только в stdlib. Имея только один исполняемый файл, что бы вы структурировали на производстве?


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. в каждом пакете, кроме основного, у меня есть Setup() функция (с соответствующими аргументами), вызываемая основным пакетом.
  2. для пакетов под apis папка, они часто просто инициализируют внешние библиотеки Go. Вы также можете напрямую импортировать существующие библиотеки в обработчики/модели без apis пакета.
  3. я настраиваю свой mux как экспортированный глобальный в handlers пакет такой...

    Router := mux.NewRouter()
    

    ...а затем создайте файл для каждого URL-адреса (разные методы с одним и тем же URL-адресом находятся в одном файле). В каждом файле, я использую гоу init() функция, которая выполняется после глобальных переменных инициализируются (поэтому безопасно использовать маршрутизатор), но до main() выполняется (поэтому для main безопасно предположить, что все было настроено). Самое замечательное в init() это то, что вы можете иметь столько этих методов, сколько хотите в одном пакете, поэтому они автоматически запускаются при импорте пакета.

    Main затем импортирует myprojectname/handlers а затем служит handlers.Router в Main.

2. Инъекция зависимости и единство работы

I не работал с Unity of Work, поэтому я понятия не имею о возможных реализациях Go.

для DI я создаю интерфейс, который будет реализован как реальный объект, так и макетные объекты.

в пакете я добавляю это в корень:

var DatabaseController DatabaseControllerInterface = DefaultController

тогда первую строку каждого теста я могу изменить DatabaseController что этот тест должен. Когда не тестируется, модульные тесты не должны выполняться, и по умолчанию это DefaultController.

3. Блок Тестирование

Go обеспечивает встроенное тестирование с помощью . Вы можете использовать go test --cover также излучать процент покрытия. Вы можете даже покрытие отображается в вашем браузере, выделяя части, которые / не покрыты.

я использую показания/утверждать пакет, чтобы помочь мне с тестированием, где стандартная библиотека не хватает:

// 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 рамки

я не видел ни одного углового. Хотя я не использовал его, Go имеет хороший шаблонный движок, встроенный в стандартный lib.

5. RESTful url, что позволяет SEO

опять же, я не могу помочь вам здесь. Это зависит от вас: отправьте правильные коды состояния (не отправляйте 200 со страницей 404, так как вы будете закреплены за дубликатами страниц), не дублируйте страницы (обратите внимание на google.com/something vs google.com/something/; надеюсь, ваша структура будет не испортите это), не пытайтесь обмануть поисковую систему и так далее.