But even without codegen you'd still a much nicer interface than manually hacking together strings as the Golang example others have linked shows: https://github.com/Masterminds/squirrel
Constructing sql by concat strings has a few issues, its repetitive and hard to assemble certain queries conditionally, and at least in golang its easy to write code vulnerable to sql injection and you can avoid that by using types
My preferred package before Ent was Squirrel [1] but I definitely plan to use Ent for future projects.
https://vluxe.io/golang-router.html
However, Go ecosystem is starting to look interesting library-wise, as long as your project doesn't involve enterprise integration with legacy XML services or SOAP, because Go sucks at mostly anything XML.
For templating I use Jet because the standard templating library is too basic for professional use https://github.com/CloudyKit/jet .
I don't use ORM, I use https://github.com/Masterminds/squirrel for query building and https://github.com/jmoiron/sqlx which helps deals with row<=>struct conversion. For database migrations, I use https://github.com/rubenv/sql-migrate , but if you need an ORM gorm https://github.com/jinzhu/gorm is OK if you do code first and sqlboiler https://github.com/volatiletech/sqlboiler is OK if you do database first.
For session handling I use scs github.com/alexedwards/scs , for converting form encoded data to go structs I use github.com/gorilla/schema, for logging I use zap https://github.com/uber-go/zap. For managing roles in an app I use either the voter pattern https://symfony.com/doc/current/security/voters.html in simple cases or casbin github.com/casbin/casbin . For background jobs I used https://github.com/gocraft/work and https://github.com/gocelery/gocelery , for caching i just use redis https://github.com/go-redis/redis , for data validation I used https://github.com/asaskevich/govalidator or https://github.com/go-ozzo/ozzo-validation . For sending mails to customers I used https://github.com/go-gomail/gomail
If i need html forms, I first describe form elements as a struct then write form helpers in jet templating to display them like that:
type LoginForm struct {
Login, Password string
Form
}
func (form *LoginForm) validate(r *http.Request) error {
r.ParseForm()
form.Decoder().Decode(form, r.Form)
form.Errors = map[string][]string{}
if err := (requiredValidator{}).validate(form.Login); err != nil {
form.Errors["Login"] = append(form.Errors["Login"], err.Error())
}
if err := (requiredValidator{}).validate(form.Password); err != nil {
form.Errors["Password"] = append(form.Errors["Password"], err.Error())
}
return form.getErrors()
}
func (form LoginForm) LoginFormView() LoginFormView {
return LoginFormView{Fields: []Field{
{Name: "Login", Label: "Email", Type: "text", Value: form.Login, Required: true, Errors: form.Errors["Login"]},
{Name: "Password", Label: "Password", Type: "password", Value: form.Password, Required: true, Errors: form.Errors["Password"]},
{Type: "submit", Value: "Submit", Required: true},
{Type: "reset", Value: "Reset", Required: true},
}, Method: "POST", Name: "LoginForm"}
}
Then I can just write an helper in jet to display the the form view: {* tag attributes *}
{{ block attributes() }}
{{range .}}
{{.Key}}="{{.Value}}"
{{end}}
{{ end }}
{* form field *}
{{block field()}}
{{.Label}}
{{if .Type == "textarea" }}
{* textarea *}
{{.Value}}
{{ else if .Type == "select" }}
{* select *}
{{ range .Options }}
{{.Label}}
{{ end }}
{{ else }}
{* basic input *}
{{ end }}
{{end}}
{* form template *}
{{block form()}}
{{ range .Fields }} {{yield field() .}} {{end}}
{{end}}
This is the exact app structure I use to deal with dependencies and filters :https://medium.com/statuscode/how-i-write-go-http-services-a...