š go-todo-backend - Awesome Go Library for Miscellaneous
Go Todo Backend example using modular project layout for product microservice.
Detailed Description of go-todo-backend
go-todo-backend
Go Todo Backend Example Using Modular Project Layout for Product Microservice. It's suitable as starting point for a medium to larger project.
This example uses Chi for http router and REL for database access.
Feature:
- Modular Project Structure.
- Full example including tests.
- Docker deployment.
- Compatible with todobackend.
Installation
Prerequisite
Running
- Prepare
.env
.cp .env.sample .env
- Start postgresql and create database.
docker-compose up -d
- Prepare database schema.
rel migrate
- Build and Running
make
Project Structure
.
āāā api
ā āāā handler
ā ā āāā todos.go
ā ā āāā [other handler].go
ā āāā middleware
ā āāā [other middleware].go
āāā bin
ā āāā api
ā āāā [other executable]
āāā cmd
ā āāā api
ā ā āāā main.go
ā āāā [other cmd]
ā āāā main.go
āāā db
ā āāā schema.sql
ā āāā migrations
ā āāā [migration file]
āāā todos
ā āāā todo.go
ā āāā create.go
ā āāā update.go
ā āāā delete.go
ā āāā service.go
ā āāā todostest
ā āāā todo.go
ā āāā service.go
āāā [other domain]
ā āāā [entity a].go
ā āāā [business logic].go
ā āāā [other domain]test
ā ā āāā service.go
ā āāā service.go
āāā [other client]
āāā [entity b].go
āāā client.go
āāā [other client]test
āāā client.go
This project structure is based on a modular project structure, with loosely coupled dependencies between domain, Think of making libraries under a single repo that only exports certain functionality that used by other service and http handler. One of domain that present in this example is todos.
Loosely coupled dependency between domain is enforced by avoiding the use of shared entity package, therefore any entity struct should be included inside it's own respective domain. This will prevent cyclic dependency between entity. This shouldn't be a problem in most cases, becasause if you encounter cyclic dependency, there's huge chance that the entity should belongs to the same domain.
For example, consider three structs: user, transaction and transaction items. transaction and its transaction items might need cyclic dependency and items doesn't works standalone (items without transaction should not exists), thus it should be on the same domain. In the other hand, user and transaction shouldn't require cyclic dependency, transaction might have a user field in the struct, but user shouldn't have a slice of transaction field, therefore it should be on a separate domain.
Domain vs Client
Domain and Client folder is very similar, the difference is client folder doesn't actually implement any business logic (service), but instead a client that calls any internal/external API to works with the domain entity.