News for hackers. Stuff that matters.
Re:Ask HN: What is the current state of web frameworks in Go... by nostalgeek on Saturday July 14, 2018 @05:06AM (#17529495)
There is no real good framework and anybody can write a trie based router in 2 hours:

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>
        {{.Label}}
        <br/>
        {{if .Type == "textarea" }}
        {* textarea *}
        <textarea  name="{{.Name}}" {{ yield attributes() .Attributes }} >{{.Value}}</textarea>
        {{ else if .Type == "select" }}
        {* select *}
        <select name="{{.Name}}" {{yield attributes() .Attributes }}>
            {{ range .Options }}
            <option value="{{.Value}}" {{ if .Selected }} selected {{ end }}>{{.Label}}</option>
            {{ end }}
        </select>
        {{ else }}
        {* basic input *}
        <input type="{{.Type}}" name="{{.Name}}" {{ if isset(.Value) }} value="{{.Value}}" {{ end }}
        {{ yield attributes() .Attributes }} {{ if .Checked == true }} checked {{end}} />
        {{ end }}
    </label>
    {{end}}
    {* form template *}
    {{block form()}}
    <form action="{{.Action}}" name="{{.Name}}" method="{{.Method}}">
        <fieldset>
            {{ range .Fields }} {{yield field() .}} {{end}}
        </fieldset>
    </form>
    {{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...

Re:Ask HN: What is the current state of web frameworks in Go... by jeevatkm on Saturday July 14, 2018 @03:03PM (#17531801)
You have written your experience in detail.

If you don't mind. I would like to request you to have a look aah framework [1]? and share your candid feedback. I'm interested in your viewpoint. I'm the author of aah.

[1]: https://aahframework.org