README
Webapp Boilerplate for Go
Creating a web server with Go is easy, but making it good requires quite some work - especially logging, error handling, database connection and static resources are in most cases required, but need a lot of work to implement every time.
This module replaces your boilerplate code and decreases your time to get started with the actual work. It's slightly opinionated (i.e. you'll have to use Gin and Zerolog, otherwise you're free to use whatever you want - Pkger is the recommended way to package static assets, Ent is the recommended ORM, and Swag with gin-swagger the recommended way to document your API).
To make your life even easier, there are also helpers for request arguments, as well as for environment variables.
To get started with a new project, initialize a new Go module with go mod init ...
and create a cmd/.../main.go
file according to the
example:
package main
import (
"codeberg.org/momar/webapp-boilerplate"
"codeberg.org/momar/webapp-boilerplate/environment"
"database/sql"
"github.com/gin-gonic/gin"
"github.com/markbates/pkger"
"github.com/rs/zerolog/log"
"io/ioutil"
".../ent"
)
//go:generate pkger
var db *ent.Client
var prefix = env.Read("PREFIX").Default("example-").AsString().Get()
func main() {
// Open static files
staticFiles, err := pkger.Open("/")
boilerplate.Must(err)
app := boilerplate.CreateApp().
WithLogging().
WithDatabase(func(driverName string, dataSourceName string) (err error) {
// Connect to the database
log.Info().Str("driver", driverName).Str("dataSource", dataSourceName).Msg("Connecting to database.")
db, err = ent.Open(driverName, dataSourceName)
return
}, func(string, string) (err error) {
// Apply schema
return db.Schema.Create(context.Background());
}).
WithGin().
WithStatic("/", staticFiles, true)
app.Engine.GET("/api/:key", func(c *gin.Context) {
// Retrieve value from database
value := db.Data.
GetX(c, prefix + c.Param(key)).
Value
c.String(200, value)
})
app.Engine.PUT("/api/:key", func(c *gin.Context) {
// Read body
value, err := ioutil.ReadAll(c.Request.Body)
boilerplate.Must(err)
// Try to update existing field in database
n := db.Data.
UpdateID(prefix + c.Param("key")).
SetValue(string(value)).
SaveX(c)
if n == 0 {
// If no field exist, create a new one
db.Data.Create().
SetID(prefix + c.Param("key")).
SetValue(string(value)).
SaveX(c)
}
c.String(200, "ok")
})
app.Start()
}
Additionally, you should copy & adjust the .gitignore
, Dockerfile
and docker-compose.yml
from this repository to get a clean & fully
packaged web application.
You can also create a symlink from .dockerignore
to .gitignore
(ln -s .gitignore .dockerignore
) to use the same ignore configuration for
both Git and Docker.
When creating an API, you should create your own error handling function for all routes that are using Ent (see error-handling.go in wuks/reservator for an example) - in this project, you can also find an example on how to do API documentation with Swag & gin-swagger.
Available methods
WithLogging()
Sets up Zerolog for nice console output & improved Gin logging.
You can use the following environment variables to modify the runtime behaviour:
LOG_LEVEL
: minimum level for logging, available values aretrace
,debug
,info
,warn
anderror
, the default isinfo
. Fortrace
anddebug
, Gin is set to debug modeLOG_FORMAT
: format for logging, eitherjson
orconsole
, the latter is the default value.
WithDatabase(...func(driverName string, dataSourceName string) error)
Parses environment variables to determine the database connection &
calls the supplied functions with the driverName
& dataSourceName
as
expected by database/sql
. It currently supports MySQL, PostgreSQL and
SQLite, using the following environment variables:
SQLITE_DATABASE
: filename of the SQLite3 database. By default, an in-memory SQLite3 database will be used!MYSQL_DATABASE
: database name for MySQL. Required when using MySQL!MYSQL_HOST
: hostname of the MySQL server, defaults to127.0.0.1
.MYSQL_PORT
: port of the MySQL server, defaults to3306
.MYSQL_USER
: username for the MySQL connection, defaults toroot
.MYSQL_PASSWORD
: password for the MySQL connection, defaults to either the value ofMYSQL_ROOT_PASSWORD
if the user isroot
, or an empty string.POSTGRES_DB
: database name for MySQL. Required when using PostgreSQL!POSTGRES_HOST
: hostname of the PostgreSQL server, defaults to127.0.0.1
.POSTGRES_PORT
: port of the PostgreSQL server, defaults to5432
.POSTGRES_SSLMODE
: encryption mode for the connection, defaults todisable
. See pq documentation for more information.POSTGRES_USER
: username for the PostgreSQL connection, defaults topostgres
.POSTGRES_PASSWORD
: password for the PostgreSQL connection, defaults to an empty string.
WithGin()
Sets up a Gin engine with a logger (if LOG_LEVEL
is at least debug
)
and recovery & handling of panic()
(send 500 & log only to STDOUT) and
c.AbortWithError()
(send the error to the client).
HOST
: the hostname to listen on, defaults to[::]
(everywhere).PORT
: the port to listen on, defaults to80
ifos.Geteuid()
is0
(root), otherwise8080
.
WithStatic(prefix, fs, allowIndex)
Adds a static file middleware to the Gin engine at the specified prefix. As opposed to the equivalent Gin functions, this will not block subordinate routes from being assigned.
Start()
Start the Gin webserver.
Future
- Full example application
- Recommendation for Authentication (JWT, OAuth2, LDAP, SAML) & Permissions
- Recommendation for i18n
- Recommendation for admin/config dashboards (like Django)
- Documentation for adding a Vue 3 frontend
- Kubernetes support
Documentation
Index ¶
Constants ¶
Variables ¶
Functions ¶
Types ¶
type Builder ¶
type Builder struct{}
func (*Builder) WithDatabase ¶
func (*Builder) WithGin ¶
func (b0 *Builder) WithGin() *BuilderWithGin
func (*Builder) WithLogging ¶
type BuilderWithGin ¶
func (*BuilderWithGin) Start ¶
func (b *BuilderWithGin) Start()
func (*BuilderWithGin) WithStatic ¶
func (b *BuilderWithGin) WithStatic(prefix string, fs http.FileSystem, allowIndex bool) *BuilderWithGin