Golang RESTful API boilerplate with modern architectures.
- Database:
MySQL
orPostgres
- Minio Server
- Redis
- Go v1.14.x
Download this project:
git clone https://github.com/trisna-ashari/go-rest-skeleton
Download project dependencies:
go mod download
Before run this project, you should set configs with yours.
Create & configure your .env
based on: .env.example
Create app secret (private and public key):
go run main.go create:secret
NOTE: you can use this generated key pair for APP_PRIVATE_KEY
and APP_PUBLIC_KEY
for your .env
Run migration:
go run main.go db:migrate
Run initial seeder:
go run main.go db:init
Fast run with:
go run main.go
# running on default port 8888
or Enable hot reload with Air:
go get -r github.com/cosmtrek/air
then simply run:
air
NOTE: hot reload very useful on development processes
This skeleton has builtin API documentation using swagger. Just run this project and open this link:
http://localhost:8888/swagger.index.html
To rebuild api docs, simply run:
swag init
├── application
├── config
├── docs // swagger
├── domain
│ ├── domain
│ ├── registry
│ ├── repository
│ ├── seeds
├── graph // an example of graphQL rpcServer
├── grpc // an example of gRPC rpcServer
├── infrastructure
│ ├── authorization
│ ├── message
│ ├── notify
│ ├── persistence
│ └── storage
├── interfaces
│ ├── cmd
│ ├── handler
│ │ ├── v1.0 // handler version 1.0
│ │ │ └── ...
│ │ └── v2.0 // hanlder version 2.0
│ │ │ └── ...
│ └── middleware
│ └── routers
│ └── service
├── languages
├── pkg // internal package
├── tests
└── main.go
All RESTful endpoint has prefix
and versioning
support. Prefix format is: /api
/v1
/external
/routes.
Supported HTTP Method:
POST
GET
PUT
PATCH
DELETE
OPTIONS
Api response generally consists by three keys
(max four):
code
asHTTP Code
data
asactual response (various type of data)
message
ascontext message (success or error)
meta
asadditional response
. Check example
On api response's headers
, its also included additional headers:
Accept-Language
X-API-Version
X-Request-Id
curl http://localhost:8888/ping
will return:
{
"code": 200,
"data": null,
"message": "pong"
}
Builtin meta pagination that easy to configure.
This is an example of response with meta pagination including page
, per_page
, total
:
{
"code": 200,
"data": [
{
"uuid": "5d082e28-7e8f-42a6-913e-8a939b77d1eb",
"first_name": "Hortense",
"last_name": "Lebsack",
"email": "[email protected]",
"phone": "734-109-1286"
},
{
"uuid": "b467e87e-0858-476e-b47a-174045dcdf71",
"first_name": "Sylvan",
"last_name": "Krajcik",
"email": "[email protected]",
"phone": "107-398-4261"
}
],
"message": "Successfully get userEntity list",
"meta": {
"page": 2,
"per_page": 2,
"total": 9
}
}
This skeleton has builtin JWT
based authentication. For an example:
curl --location --request POST 'http://localhost:8888/api/v1/external/login' \
--header 'Accept-Language: ' \
--header 'Content-Type: application/json' \
--data-raw '{
"email": "[email protected]",
"password": "123456"
}'
will return:
{
"code": 200,
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NfdXVpZCI6ImUxY2U1NmI0LTM3MjQtNDA1OS1hOTY5LWUwMTY4YTBjYTllMiIsImF1dGhvcml6ZWQiOnRydWUsImV4cCI6MTU5NDIxODUwMCwidXVpZCI6ImNhZWIwZWZlLTFmZDEtNGQ1YS1iOWNkLTIyMTNiOTc2OGU5MyJ9.2uSkiwISaL4R5wwpAgx7isRpnpSE6GtE8gumOY_yR1E",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTQ4MjI0MDAsInJlZnJlc2hfdXVpZCI6ImUxY2U1NmI0LTM3MjQtNDA1OS1hOTY5LWUwMTY4YTBjYTllMisrY2FlYjBlZmUtMWZkMS00ZDVhLWI5Y2QtMjIxM2I5NzY4ZTkzIiwidXVpZCI6ImNhZWIwZWZlLTFmZDEtNGQ1YS1iOWNkLTIyMTNiOTc2OGU5MyJ9.oGrudpMa57pNz9qGOx1DpLjg1He-xWmqT2gGS84hEww",
},
"message": "Successfully login"
}
There also builtin authentication using Basic Auth
by passing auth through header.
Basic auth constructed from based64 encoded of:
email:password
[email protected]:123456
Example:
curl --location --request GET 'http://localhost:8888/api/v1/external/profile' \
--header 'Accept-Language: en' \
--header 'Authorization: Basic dHJpc25hLngyQGdtYWlsLmNvbToxMjM0NTY='
There are builtin oauth2 server and client. For an example click this link:
http://localhost:8181/oauth/login
There is builtin middleware called policy
. It a middleware uses to handle access permission for each URI based on (method on the handler). This policy
works by defined custom role
and permission
.
- Each
userEntity
can have more than onecustom role
. - Each
custom role
can have multiple permissions. - Based on the database to achieve dynamic and custom roles.
See this example how easy to implement.
Yes, this skeleton has builtin db migration and seeders.
Why auto migrate? This feature is very helpful to keep your table(s) schema
always update depends on changes in each entities
.
AutoMigrate
automatically run when you manually
start the application or with triggered by hot reload
.
This builtin seeder can help you to fill your schema with dummy data, so you don't need wast your time to type an lorem ipsum
.
Internationalization made easy with this skeleton. go-i18n was used to handle multilingual support. All translations text stored in *.yaml
file on languages
directory.
. . .
├── languages
│ ├── global.en.yaml
│ └── global.id.yaml
. . .
YAML
file was choosen because nested declaration
can be done easily instead of TOML
, JSON
, etc. For more example please check this language example.
Yes, logger
is very useful in development process. This skeleton has built in logger to watch any request are coming to your rest API. It was configurable :).
This is examples of what logger prints:
2020/11/04 16:01:56 /Users/sentinel/Gitrepos/go-rest-skeleton/infrastructure/persistence/user_repository.go:176
[7.798ms] [rows:1] SELECT * FROM `users` WHERE email = "[email protected]" AND `users`.`deleted_at` IS NULL LIMIT 1
4:01PM INF Request headers={"Accept":"*/*","Accept-Encoding":"gzip, deflate, br","Accept-Language":"id","Cache-Control":"no-cache","Connection":"keep-alive","Content-Length":"66","Content-Type":"application/json","Postman-Token":"fff3d097-e315-4103-8ec2-7fb945fb654f","User-Agent":"PostmanRuntime/7.26.5"} ip=127.0.0.1 latency=160.543176 method=POST path=/api/v1/external/login request-form={} request-id=ba38e9a6-4f7e-4e67-b499-7620ef3bef0a request-payload={"email":"[email protected]","password":"123456"} response={"code":200,"data":{"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NfdXVpZCI6IjNiYzdiZTk4LTgzOWMtNDExZi04ZGZhLWMyNjU4OGQ5Njg5YiIsImF1dGhvcml6ZWQiOnRydWUsImV4cCI6MTYwNDQ4NDExNiwidXVpZCI6IjNhY2E2NWE5LWQ3MWUtNGJhNy05YzQxLThmMGE0ZjFiZGVhYiJ9.EcniXexsASuPapM0SpKDNrkUE-RR0TmgwfsNXn7DC5A","refresh_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MDUwODUzMTYsInJlZnJlc2hfdXVpZCI6IjNiYzdiZTk4LTgzOWMtNDExZi04ZGZhLWMyNjU4OGQ5Njg5YisrM2FjYTY1YTktZDcxZS00YmE3LTljNDEtOGYwYTRmMWJkZWFiIiwidXVpZCI6IjNhY2E2NWE5LWQ3MWUtNGJhNy05YzQxLThmMGE0ZjFiZGVhYiJ9.LO2W2DUpFuEM9gWbPR0s1Enud-dNZq1IkuXARA1tBuw"},"message":"Berhasil masuk"} status=200 user-agent=PostmanRuntime/7.26.5
[GIN] 2020/11/04 - 16:01:56 | 200 | 165.35311ms | 127.0.0.1 | POST "/api/v1/external/login"
Absolutely yes, just run:
go test -p 1 ./... -cover -coverprofile=coverage.out
or using the Makefile:
make unit test
make integration test
- Go - The Go Programming Language
- gin - Gin is HTTP web framework written in Go (Golang)
- gorm - The fantastic ORM library for Golang
- swag - Automatically generate RESTful API documentation with Swagger 2.0 for Go
- oauth2 - OAuth 2.0 server library for the Go programming language
- ozzo-validation - An idiomatic Go (golang) validation package
MIT License. See LICENSE for details.
Copyright (c) 2020 Trisna Novi Ashari.
Buy me a cup of coffee ☕ :)