I am build a multi-subdomain HTTP service following the example using an host map
I would like to pass my datastore object into the context but the ServeHTTP func uses a newly-allocated one so it never goes down to my handler
Is there any work-around?
Should I use a global datastore object?
Thanks
// Server
e := echo.New()
e.Any("/*", func(c echo.Context) (err error) {
req := c.Request()
res := c.Response()
host := hosts[req.Host()]
if host == nil {
err = echo.ErrNotFound
} else {
c.Set("DataStore", persistence.DataStore) <-- HERE IS MY ISSUE
host.Echo.ServeHTTP(req, res)
}
return err
})
e.Run(standard.New(":8080"))
What about middleware? You can put db object into context in middleware.
sorry but I don't understand how your answer applies to my situation
I am starting from this example: https://echo.labstack.com/recipes/subdomains
thanks
You can put db object into context on subdomain's echo instance declaration
Thanks for your help, but I still don't understand how to accomplish this...
Which function should I call on the Echo object?
Also, please check first three lines of ServeHTTP function:
func (e *Echo) ServeHTTP(req engine.Request, res engine.Response) {
c := e.pool.Get().(*echoContext)
c.Reset(req, res)
a new Context is obtained from the pool and then reset
package main
import (
"net/http"
"github.com/labstack/echo"
"github.com/labstack/echo/engine/standard"
"github.com/labstack/echo/middleware"
)
type (
Host struct {
Echo *echo.Echo
}
)
func main() {
// Hosts
hosts := make(map[string]*Host)
//-----
// API
//-----
api := echo.New()
api.Use(middleware.Logger())
api.Use(middleware.Recover())
api.Use(dataSourceMiddleware(persistence.DataStore)) // Put your dbinstance to context
hosts["api.localhost:1323"] = &Host{api}
api.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "API")
})
//------
// Blog
//------
blog := echo.New()
blog.Use(middleware.Logger())
blog.Use(middleware.Recover())
blog.Use(dataSourceMiddleware(persistence.DataStore)) // Put your dbinstance to context
hosts["blog.localhost:1323"] = &Host{blog}
blog.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Blog")
})
// Server
e := echo.New()
e.Any("/*", func(c echo.Context) (err error) {
req := c.Request()
res := c.Response()
host := hosts[req.Host()]
if host == nil {
err = echo.ErrNotFound
} else {
host.Echo.ServeHTTP(req, res)
}
return
})
e.Run(standard.New(":1323"))
}
thank you very much for your help.
I understand that the data store is now available in the custom middleware.
I still don't understand how I can retrieve my db instance in the handler
for example
blog.GET("/",` func(c echo.Context) error {
ds := ** GET DB INSTANCE HERE **
return c.String(http.StatusOK, "Blog")
})
For example I want to reply with a JSON that lists all the rows from a table
func dataSourceMiddleware(dataStore DB) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) err error {
c.Set("db", dataStore)
return next(c)
}
}
}
blog.GET("/", func(c echo.Context) error {
db, ok := c.Get("db").(DB)
return c.String(http.StatusOK, "Blog")
}
I am going to try it and let you know.
BTW is it a recommended approach or should I leave the DB instance as a global and live my life in peace?
@genez Context is meant for request scope variables only. You should have a struct holding DB instance and use it. Something like below:
type Handler struct {
DB *Mongo
}
func (h *Handler) func Save(c echo.Context) error {
// Save using h.DB
}
e := echo.New()
h := Handler{DB: mongo}
// Register your routes
e.POST("/save", h.Save)
It surely would be nice having an example for something like this
https://joeshaw.org/revisiting-context-and-http-handler-for-go-17/
Most helpful comment