An example project layout for Go applications written with the Gin framework. I'm also using GORM as an ORM and golang-migrate to handle database migrations.
This template / example is an ongoing work in progress, so depending on the timing there may be bugs.
I've borrowed heavily from @benbjohnson/standard-package-layout and golang-standards/project-layout
- golang-migrate
brew install golang-migrate
- Mocks are generated with mockery
brew install mockery
$ docker-compose up
$ make db-up
$ make seed
$ make run
- API docs are available at http://localhost:8081
$ make unit-test
- For example, after adding a method to a repository interface
$ make mocks
Contains the docker-compose.yml
, Makefile
for executing common tasks (test, run, etc.), go.mod
file and so on.
The API documentation. Is this case, it's an openapi.yml
file.
The go source code used to set up and run the application. Effectively the executable to run on the command line. You can either run go run cmd/api/main.go
to start the application or go run cmd/seed/main.go
to seed the DB with some test data.
Database migrations go here. I'm using golang-migrate to apply the migrations.
Repository mocks are all in here. They are auto-generated using mockery (see the Makefile) and can be used to mock out the DB when unit testing.
Any scripts you might have for your own convenience can go here.
The Go source files here all implement application / business logic. It is effectively the "service layer". The source here basically does everything that does not depend on any knowledge re: the specifics of storing data to a DB, handling HTTP requests, etc.
If you take a look at the source, you will see some structs (used to represent business entities), some interfaces (that allow the service layer to
get what it needs from other, infrastructure focused layers) and some methods (that simply implement business logic and don't have any infrastructure
dependencies). You'll also see an accompanying *_test.go
file that tests the logic here.
The code here deals with all of the details of receiving requests, marshalling / unmarshalling JSON and returning responses. It is basically the "handler" code.
The code here represents the "repository" layer and deals with the specifics of getting data into and out of a MySQL DB. The code here implements an interface defined in the service layer. It can be passed in during application start-up to give the service layer a way of storing or retrieving data (or not if you want to unit test with mocks). In addition to implementing the repository logic, the code here also defines some structs. This may seem redundant as I've already defined my types in the service layer, but the types defined in the repository layer are defined to match perfectly to the DB tables that they represent, whereas the types defined in the service layer are defined to work as well as possible in the service layer without being bound to whatever the DB table structure may be.
I also like to keep my repository layer structs and service layer structs separate because I don't want something like a new column added to a table leaking in to a service that doesn't have any use for that new column.
Lastly, the code to connect to the DB and get the ORM set up is here as well.