An API Boilerplate written in Golang with chi-route and Gorm. Write restful API with fast development and developer friendly.
- Architecture
- Boilerplate Structure
- Configuration Manage
- Installation
- Let's Build an API
- Code Examples
- Deployment
- Useful Commands
- ENV YAML Configure
- Use Packages
- Models
- Repository
- Controllers
- More About Uncle Bob’s Architecture
├── config ├── controllers ├── helpers ├── infra │ ├── database │ └── logger ├── migrations ├── models ├── repository ├── routers │ ├── middlewares
- Default ENV Configuration Manage from
.env
. sample file.env.example
# Server Configuration
SECRET=h9wt*pasj6796j##w(w8=xaje8tpi6h*r&hzgrz065u&ed+k2)
DEBUG=True # `False` in Production
ALLOWED_HOSTS=0.0.0.0
SERVER_HOST=0.0.0.0
SERVER_PORT=8000
# Database Configuration
MASTER_DB_NAME=test_pg_go
MASTER_DB_USER=mamun
MASTER_DB_PASSWORD=123
MASTER_DB_HOST=postgres_db
MASTER_DB_PORT=5432
MASTER_DB_LOG_MODE=True # `False` in Production
MASTER_SSL_MODE=disable
REPLICA_DB_NAME=test_pg_go
REPLICA_DB_USER=mamun
REPLICA_DB_PASSWORD=123
REPLICA_DB_HOST=localhost
REPLICA_DB_PORT=5432
REPLICA_DB_LOG_MODE=True # `False` in Production
REPLICA_SSL_MODE=disable
- Server
DEBUG
setFalse
in Production - Database Logger
MASTER_DB_LOG_MODE
andREPLICA_DB_LOG_MODE
setFalse
in production - If ENV Manage from YAML file add a config.yml file and configuration db.go and server.go. See More ENV YAML Configure
- Use chi Route
- Use GORM as an ORM
- Use database
MASTER_DB_HOST
value set aslocalhost
for local development, and usepostgres_db
for docker development
- Check PG Admin on http://0.0.0.0:5050/browser/
- Login with Credential Email
[email protected]
Passwordroot
- Connect Database Host as
postgres_db
, DB Username and Password as per.env
set - Note: if not configure
.env
, default Usernamemamun
and password123
Follow these steps:
- Copy .env.example as
.env
and configure necessary values - To add all dependencies for a package in your module
go get .
in the current directory - Locally run
go run main.go
orgo build main.go
and run./main
- Check Application health available on 0.0.0.0:8000/health
Follow these steps:
- Make sure install the latest version of docker and docker-compose
- Docker Installation for your desire OS https://docs.docker.com/engine/install/ubuntu/
- Docker Composer Installation https://docs.docker.com/compose/install/
- Run and Develop
make dev
- Check Application health available on 0.0.0.0:8000/health
- models folder add a new file name
example_model.go
package models
import (
"time"
)
type Example struct {
Id int `json:"id"`
Data string `json:"data" binding:"required"`
CreatedAt *time.Time `json:"created_at,string,omitempty"`
UpdatedAt *time.Time `json:"updated_at_at,string,omitempty"`
}
// TableName is Database Table Name of this model
func (e *Example) TableName() string {
return "examples"
}
- Add Model to migration
package migrations
import (
"go-fication/models"
"go-fication/infra/database"
)
func Migrate() {
var migrationModels = []interface{}{&models.Example{}}
err := database.GetDB().AutoMigrate(migrationModels...)
if err != nil {
return
}
}
- repository folder add a file
example_repo.go
package repository
import (
"go-fication/helpers/pagination"
"go-fication/models"
)
type ExampleRepo interface {
GetExamples(limit, offset int64) (res interface{}, err error)
CreateExample(exp *models.Example) error
}
func (r *GormRepository) GetExamples(limit, offset int64) (res interface{}, err error) {
var example []*models.Example
res = pagination.Paginate(&pagination.Param{
DB: r.db,
Limit: limit,
Offset: offset,
OrderBy: "id ASC",
}, &example)
return
}
func (r *GormRepository) GetExamplesList() (exp []*models.Example, err error) {
err = r.db.Database.Find(&exp).Error
return
}
func (r *GormRepository) CreateExample(exp *models.Example) (err error) {
err = r.db.Database.Create(exp).Error
return
}
- controller folder add a file
example_controller.go
- Create API Endpoint
- Use any syntax of GORM after
base.DB
, this is wrapper of*gorm.DB
package controllers
import (
"encoding/json"
"go-fication/models"
"go-fication/repository"
"net/http"
"strconv"
)
type ExampleHandler struct {
repo repository.ExampleRepo
}
func NewExampleHandler(repo repository.ExampleRepo) *ExampleHandler {
return &ExampleHandler{
repo: repo,
}
}
func (h *ExampleHandler) GetData(w http.ResponseWriter, request *http.Request) {
q := request.URL.Query()
limit, _ := strconv.Atoi(q.Get("limit"))
offset, _ := strconv.Atoi(q.Get("offset"))
data, err := h.repo.GetExamples(int64(limit), int64(offset))
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(&data)
}
func (h *ExampleHandler) CreateData(w http.ResponseWriter, request *http.Request) {
example := new(models.Example)
err := json.NewDecoder(request.Body).Decode(&example)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
err = h.repo.CreateExample(example)
if err != nil {
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(example)
}
- routers folder add a file
example.go
package routers
import (
"github.com/go-chi/chi/v5"
"go-fication/controllers"
"go-fication/infra/database"
"go-fication/repository"
)
func ExamplesRoutes(router *chi.Mux, db *database.DB) {
repo := repository.NewGormRepository(db)
exampleCtrl := controllers.NewExampleHandler(repo)
router.Group(func(r chi.Router) {
r.Get("/test", exampleCtrl.GetData)
r.Post("/test", exampleCtrl.CreateData)
})
}
- Finally, register routes to index.go
package routers
import (
"github.com/go-chi/chi/v5"
"net/http"
)
//RegisterRoutes add all routing list here automatically get main router
func RegisterRoutes(router *chi.Mux) {
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("\"live\": \"ok\""))
})
//Add All route
ExamplesRoutes(router)
}
- Congratulation, your new endpoint
0.0.0.0:8000/v1/example/
- Run
make build
- Run
make production
database:
driver: "postgres"
dbname: "test_pg_go"
username: "mamun"
password: "123"
host: "postgres_db" # use `localhost` for local development
port: "5432"
ssl_mode: disable
log_mode: false
server:
host: "0.0.0.0"
port: "8000"
secret: "secret"
allow_hosts: "localhost"
debug: false #use `false` in production
request:
timeout: 100
func ServerConfig() string {
viper.SetDefault("server.host", "0.0.0.0")
viper.SetDefault("server.port", "8000")
appServer := fmt.Sprintf("%s:%s", viper.GetString("server.host"), viper.GetString("server.port"))
return appServer
}
func DbConfiguration() string {
dbname := viper.GetString("database.dbname")
username := viper.GetString("database.username")
password := viper.GetString("database.password")
host := viper.GetString("database.host")
port := viper.GetString("database.port")
sslMode := viper.GetString("database.ssl_mode")
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=%s",
host, username, password, dbname, port, sslMode)
return dsn
}
make dev
: make dev for development workmake build
: make build containermake production
: docker production build and upclean
: clean for all clear docker images