Небольшой микросервис на Go.
Пока он просто читает настройки из .env-файла и выводит их в консоль.
- HTTP-сервер на
gorilla/mux+negroni; - DI-контейнер на
go.uber.org/dig; - пример домена Book: создание книги через
POST /books.
.
├── cmd/
│ └── app/
│ └── main.go
├── config/
│ └── local.env
├── internal/
│ ├── app/
│ │ └── app.go
│ ├── config/
│ │ ├── config.go
│ │ ├── config_helper.go
│ │ └── database/
│ ├── entities/
│ │ └── book/
│ │ └── book_entity.go
│ ├── models/
│ │ └── book/
│ │ └── book_create_models.go
│ ├── repositories/
│ │ └── book/
│ │ └── book_repositories.go
│ └── services/
│ └── book/
│ └── book_service.go
├── api/
│ ├── controllers/
│ │ └── book/
│ │ ├── book_controller.go
│ │ └── book_controller_route.go
│ └── router/
│ └── router.go
├── server/
│ └── server.go
├── go.mod
├── go.sum
└── README.md
cmd/app/main.go — точка входа в приложение (отсюда всё запускается).
configs/local.env — файл с настройками (логин/пароль БД, хост, порт и т.п.).
internal/config — работа с конфигурацией всего приложения.
internal/config/database — отдельная структура с настройками для базы данных.
internal/app — сборка DI-контейнера на go.uber.org/dig.
api/router — описание HTTP-маршрутов (обёртка над gorilla/mux).
server — HTTP-сервер, который собирает negroni + mux и запускает ListenAndServe.
-
cmd/app/main.goТочка входа в приложение. Собирает DI-контейнер (internal/app), достаёт из негоserver.Serverи запускает HTTP-сервер. -
config/local.envЛокальные настройки (порт сервера, параметры БД и т.п.). Читаются вinternal/config.
Всё, что не должно использоваться извне (внешними модулями). «Внутренности» микросервиса.
-
internal/configРабота с конфигурацией:- чтение
.env; - маппинг в структуру
Config; - отдельный под-пакет
databaseпод настройки БД.
- чтение
-
internal/app/app.goСборка DI-контейнера наgo.uber.org/dig:- регистрируются конфиг, сервер, роутер;
- отдельно регистрируются все компоненты домена Book (репозиторий, сервис, контроллер, маршрутизация).
-
internal/entities/book/book_entity.goEntity — внутренняя сущность книги для БД:type Entity struct { Uuid uuid.UUID Name string }
Это «карточка книги» внутри системы: как она хранится и живёт в логике, независимо от HTTP.
-
internal/models/book/book_create_models.goCreateModel — модель входных данных для сервиса:type CreateModel struct { Name string `json:"name" form:"name"` }
То, что присылает клиент в
POST /books(JSON/форма). -
internal/repositories/book/book_repositories.goRepository — слой доступа к данным для книг.Хранит слайс
[]Entity(учебная «БД в памяти») и умеет добавлять книги:Repository — отдельный слой в приложении, который отвечает за работу с хранилищем данных. Сервис говорит ему: «Сохрани/найди/удали вот эту
Entity», а как именно — знает только он. -
internal/services/book/book_service.goService — бизнес-логика для книг.При создании книги:
- принимает
CreateModelот контроллера; - собирает
Entity(генерируетuuid, копируетName); - передаёт
Entityв репозиторий.
Сервис — «адвокат по сути дела»: здесь должны жить правила, проверки, транзакции.
- принимает
Всё, что касается HTTP-слоя.
-
api/controllers/book/book_controller.goController — обёртка над сервисом для HTTP.Делает 4 вещи:
- Читает тело HTTP-запроса.
- Превращает его в Go-структуру (
CreateModel). - Передаёт модель в сервис.
- Формирует HTTP-ответ.
Контроллер — это прослойка между HTTP-миром и сервисом.
-
api/controllers/book/book_controller_route.goControllerRoute — описывает, какие URL и методы привязаны к контроллеру:- вешает
POST /booksнаController.CreateBook; - при необходимости здесь же будут и другие маршруты (
GET /books,DELETE /books/{id}и т.д.).
- вешает
-
api/router/router.goОбщий роутер приложения:- создаёт
*mux.Router; - вызывает
BookRoutes.Route(router), чтобы зарегистрировать все эндпоинты книг; - в будущем сюда можно добавить маршруты других доменов (users, orders и т.п.).
- создаёт
-
server/server.goHTTP-сервер:- принимает
*router.Router, вызываетInitRoutes()и получает настроенный*mux.Router; - оборачивает его в
negroni(логирование, recovery и др. middleware); - запускает
ListenAndServeна порту из конфига.
- принимает
Путь запроса POST /books:
-
Клиент отправляет JSON:
{"name": "Мастер и Маргарита"} -
Router (
api/router) направляет запрос на контроллер книг по правилу изControllerRoute. -
Controller (
CreateBook):- декодирует JSON в
CreateModel; - вызывает
service.Create(model).
- декодирует JSON в
-
Service:
- из
CreateModelсобираетEntity(генерируетuuid.New()); - передаёт
Entityв репозиторий.
- из
-
Repository:
- добавляет сущность в своё хранилище (слайс в памяти);
- сейчас просто печатает список книг в консоль.
-
Controller возвращает клиенту
HTTP 200 OK(позже можно отдавать созданную книгу с еёuuid).
Такой разрез по слоям позволяет легко:
- менять хранилище (репозиторий) без переписывания контроллеров;
- добавлять бизнес-правила в сервис;
- расширять HTTP-API новыми методами, не трогая ядро домена.