Get all data from a table in golang gorm - go

I'm new in golang and programming at all, so I've a problem with this function that supposed gets it all values from a table, but just shows me one. Thanks you all for your knowledge :)
func GetAll(w http.ResponseWriter, r *http.Request) {
results := map[string]interface{}{}
c, _ := connection.GetDB()
c.Table("products").Order("id_producto asc").Find(&results)
fmt.Print(results)
jsonString, _ := json.Marshal(results)
w.Header().Set("Content-Type", "application/json")
fmt.Fprint(w, string(jsonString))
}

Try to create a DTO struct and create a list that contains item of type that struct. Then pass that list to the query. Like this:
type Product struct {
ProductID string
}
func GetAll(w http.ResponseWriter, r *http.Request) {
products := []*Product{}
c, _ := connection.GetDB()
c.Order("id_producto asc").Find(&products).
jsonString, _ := json.Marshal(products)
w.Header().Set("Content-Type", "application/json")
fmt.Fprint(w, string(jsonString))
}

You can code like this:
func GetAll(w http.ResponseWriter, r *http.Request) {
// New a slice to get the results,
// map[string]interface{}{} will only scan one item of results
results := []map[string]interface{}{}
c, _ := connection.GetDB()
c.Table("products").Order("id_producto asc").Find(&results)
fmt.Print(results)
jsonString, _ := json.Marshal(results)
w.Header().Set("Content-Type", "application/json")
fmt.Fprint(w, string(jsonString))
}

Related

How to propagate value from child middleware to parent?

I am trying to customize request pipeline through middleware pattern, the code as follow:
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("Hello, middleware!")
}
func middleware1(next http.HandlerFunc) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
fmt.Println("[START] middleware1")
ctx := r.Context()
ctx = context.WithValue(ctx, middleware1Key, middleware1Value)
r = r.WithContext(ctx)
next(w, r)
fmt.Println("[END] middleware1")
ctx = r.Context()
if val, ok := ctx.Value(middleware2Key).(string); ok {
fmt.Printf("Value from middleware2 %s \n", val)
}
}
}
func middleware2(next http.HandlerFunc) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
fmt.Println("[START] middleware2")
ctx := r.Context()
if val, ok := ctx.Value(middleware1Key).(string); ok {
fmt.Printf("Value from middleware1 %s \n", val)
}
ctx = context.WithValue(ctx, middleware2Key, middleware2Value)
r = r.WithContext(ctx)
next(w, r)
fmt.Println("[END] middleware2")
}
}
func main() {
mux := http.NewServeMux()
middlewares := newMws(middleware1, middleware2)
mux.HandleFunc("/hello", middlewares.then(helloHandler))
if err := http.ListenAndServe(":8080", mux); err != nil {
panic(err)
}
}
and the output is :
[START] middleware1
[START] middleware2
Value from middleware1 middleware1Value
Hello, middleware!
[END] middleware2
[END] middleware1
According to the output, the value could pass from parent to the child , while, if the child add something to the context, it is invisible to the parent
How can I propagate value from child middleware to parent?
What you're doing is creating a new pointer to the modified http.Request via WithContext method. So if you're passing it to next middleware in the chain everything works as expected since you're passing this new pointer as an argument.
If you want to modify the request and make it visible for those who hold the pointer to it, you need to dereference the pointer and set the modified value.
So in your 'child' middleware instead of:
r = r.WithContext(ctx)
Just do the following:
*r = *r.WithContext(ctx)
Good exercise to understand pointers in Go but you SHOULD NOT do similar operations in your production code. The docs are clear about it. See https://pkg.go.dev/net/http#Handler.
Another possible solution (without messing with the request itself) is to pass a map inside a context and read/write from/to map instead. So in your first middleware:
ctx := r.Context()
m := make(map[string]string)
m[middleware1Key] = middleware1Value
ctx = context.WithValue(ctx, dummyStoreKey, m)
r = r.WithContext(ctx)
...
if val, ok := m[middleware2Key]; ok {
fmt.Printf("Value from middleware2 %s \n", val)
}
And in the second one:
ctx := r.Context()
if store, ok := ctx.Value(dummyStoreKey).(map[string]string); ok {
if val, ok := store[middleware1Key]; ok {
fmt.Printf("Value from middleware1 %s \n", val)
}
store[middleware2Key] = middleware2Value
}
You could add a AddStoreMiddleware as the first one in the pipeline and then use it in each successor if needed. Remember, maps in Go are not concurrently safe so in some subtle cases you should serialize access.

Pass uninitialized struct to a function

Let say I have a function that handles request body in general
func GetReqBody(r *http.Request) (interface {}, error){
var data interface{}
decorder := json.NewDecoder(r.Body)
decorder.DisallowUnknownFields()
err := decorder.Decode(&data)
return data, err
}
Then in the controller, I will have to do type assertion
func post(w http.ResponseWriter, r *http.Request) {
data, err := utils.GetReqBody(r)
//req.User is a struct
newUser, ok := data.(req.User)
// ...
}
Is it possible to encapsulate the type assertion login inside the GetReqBody function? To do that I will need to pass the struct into the function, yet as it is not a value I am unable to do so.
"Is it possible to encapsulate the type assertion login inside the GetReqBody function?" -- No, it's not possible, not in any useful way.
However you could simplify your code thus:
func GetReqBody(r *http.Request, data interface{}) error {
decorder := json.NewDecoder(r.Body)
decorder.DisallowUnknownFields()
return decorder.Decode(data)
}
func post(w http.ResponseWriter, r *http.Request) {
var newUser req.User
if err := utils.GetReqBody(r, &newUser); err != nil {
// handle err
}
// ...
}

Lookup a string with a function

I'm designing a router API and I'd like to be able to lookup a path by its function. Something like:
createUser := func(w http.ResponseWriter, r *http.Request) {
// create a user
}
createPost := func(w http.ResponseWriter, r *http.Request) {
// create a post
}
router.Post("/users", createUser)
router.Post("/posts", createPost)
fmt.Println(router.Lookup(createPost))
Here's a playground link: https://play.golang.org/p/ec6U0jJUbfx
This is surprisingly hard to do because you can't test for equality on a function or stick it as a key in a map. Is this even possible?
Are there any other workarounds I'm not thinking of? A reflect solution would be just fine.
You can create a server struct with a ServerHTTP method that handles all the request. When there is a request you can look up for an specific method by the path and function
Here is an example:
type Server struct {
routes []route
}
func (s *Server) handlerServer(db mydb.IDB, ctx context.Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := ServerContext{w, r, db, ctx}
for i := 0; i < len(s.routes); i++ {
currentRoute := s.routes[i]
if isValidMethod(currentRoute, r) {
err := currentRoute.h(&ctx)
if err != nil {
log.Fatal(err)
}
}
}
}
}
I hope this is helpful

Determining if delete actually removed an existing key in a map

I have a map called nearby
func Delete(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
delete(nearby, params["id"])
}
I want to find out if the delete() call actually found a key to delete, I tried reading the return value:
func Delete(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
result := delete(nearby, params["id"])
}
but the compiler didn't like that - how can I find out if a key/val was deleted?
Probe the map before deleting the value:
func Delete(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
_, deleted := nearby[params["id"]]
delete(nearby, params["id"])
fmt.Println(deleted)
}
This snippet and the code in the question have a data race because HTTP handlers can be called concurrently. Add a mutex to protect the map.
var (
nearby = make(map[string]string)
mu sync.Mutex
)
func Delete(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
mu.Lock()
_, deleted := nearby[params["id"]]
delete(nearby, params["id"])
mu.Unlock()
fmt.Println(deleted)
}
The Go builtin delete() doesn't return anything, so you can't tell whether it deleted anything.
But you can check if the map contains the key and delete() it if it is present.
if _, ok := nearby[params["id"]]; ok {
delete(nearby, params["id"])
} else {
// whatever
}

Why does this gorilla session code not work?

I'm a golang noob, so I'm making my first toy app by setting up a seed project for a gorilla based web app. It's going well but the session code doesn't work as I expect it to, here is the full code, and here is just the relevant snippet:
func getMyCounter(w http.ResponseWriter, r *http.Request){
session, _ := sessionStore.Get(r, counterSession)
if session.IsNew {
session.Values[myCounter] = 0
}
val := session.Values[myCounter].(int)
log.Printf("getMyCounter %d", val)
m := make(map[string]int)
m["counter"] = val
js, _ := json.Marshal(m)
w.Header().Set("Content-Type", "application/json")
w.Write(js)
}
func incrementMyCounter(w http.ResponseWriter, r *http.Request){
log.Println("incrementMyCounter")
session, _ := sessionStore.Get(r, counterSession)
if session.IsNew {
session.Values[myCounter] = 0
}
val := session.Values[myCounter].(int)
session.Values[myCounter] = val + 1
getMyCounter(w, r)
}
my calls to getMyCounter and incrementMyCounter always return 0
thanks to JimB for pointing out the painfully obvious, I needed to add a call to session.Save(r, w) after creating/editing the session.

Resources