Adaugare date la un request in Go

Am gasit acest exemplu interesant in Go care paseaza date prin context din middleware spre handlerele web de dupa el. Eu chiar am avut nevoie in niste situatii de asa ceva.

Exemplu nu e complet in tweet si poate fi neclar pentru cei mai putini familiarizati limbajul Go asa ca am facut o mica implementare cu gorilla/mux unde este relativ simplu de realizat un middleware. Pentru cei interesati am pus codul intr-un gist aici:

Enjoy.

3 Likes

eu am un middleware care-mi verifică dacă userul e authentificat

// UserAuth provides middleware functions for authorizing users and setting the user
// in the request context.
type Auth struct {
	Service *Service
}

// RequireUser will verify that a user is set in the request context. It if is
// set correctly, the next handler will be called, otherwise it will redirect
// the user to the sign in page and the next handler will not be called.
func (a *Auth) RequireUser(next http.Handler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		tmp := r.Context().Value("user")
		if tmp == nil {
			http.Redirect(w, r, "/login", http.StatusFound)
			return
		}
		if _, ok := tmp.(*data.AuthUser); !ok {
			// Whatever was set in the user key isn't a user, so we probably need to
			// sign in.
			http.Redirect(w, r, "/login", http.StatusFound)
			return
		}
		next.ServeHTTP(w, r)
	}
}

și unul care-mi dă userul curent (și-l bagă în context pt a fi folosit de alte handlers)

// UserViaSession will retrieve the current user set by the session cookie
// and set it in the request context. UserViaSession will NOT redirect
// to the sign in page if the user is not found. That is left for the
// RequireUser method to handle so that some pages can optionally have
// access to the current user.
func (a *Auth) UserViaSession(next http.Handler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {

		session, err := a.Service.session.Get(r, "session")
		if err != nil {
			next.ServeHTTP(w, r)
			return
		}
		//a.Service.l.Printf("logged_in: %v\t%T", session.Values["logged_in"], session.Values["logged_in"])
		if session.Values["logged_in"] != true {
			next.ServeHTTP(w, r)
			return
		}

		user_id, _ := session.Values["user_id"].(int)
		user, err := a.Service.store.GetUserByID(user_id)
		if err != nil {
			// If you want you can retain the original functionality to call
			// http.Error if any error aside from app.ErrNotFound is returned,
			// but I find that most of the time we can continue on and let later
			// code error if it requires a user, otherwise it can continue without
			// the user.
			next.ServeHTTP(w, r)
			return
		}
		r = r.WithContext(context.WithValue(r.Context(), "user", user))
		next.ServeHTTP(w, r)
	}
}

iar în main cam așa stă treaba:

sm := mux.NewRouter()
sm.Handle("/settings", web.WrapMiddleware(r2sservice.Settings, authMw.UserViaSession, authMw.RequireUser))

2 Likes

mie nu mia placut go, ideea de not having a feature is a feature, adica less is more, mie se pare acum vrajeala de marketing

ca să nu mai deschid un subiect, las asta aici: The Best Go framework: no framework?

1 Like

Well, aici e o discutie destul de nuantata despre standard library vs frameworks in Go iar aici argumentele importante ar fi dependenta de third party si performanta. Din punctul meu de vedere primul s-ar rezolva simplu prin vendoring iar ultimul… depinde, daca ai nevoie de o performanta maxima atinsa de standard library sau e suficienta cea oferita de un framework sau altul. Altfel e mai avantajos din toate punctele de vedere sa mergi pe ceva ce iti usureaza implementarea. Eu personal folosesc Gorilla toolkit in proiectele mele.

LE: Trebuie avut in vedere si faptul ca daca folosesti doar standard library si vrei sa atingi o functionalitate care e implementata intr-un framework trebuie sa te asiguri ca stii exact cum sa o implementezi optim pentru ca performanta sa nu ajunga chiar sub cea oferita de framework.

Eu am inceput sa invat go cu trainingurile Ardanlabs si am chestia asta in fiecare proiect. Oarecum fara sa vreau, chiar m-am obisnuit asa.
Daca va uitati pe proiectele lor de training, in special ale lui Bill Kennedy si Jakob Walker in trecut, oamenii fac asta de ceva timp :slight_smile: Poate totusi nu faza cu r.Clone(), dar same thing pretty much.

1 Like