gocraft / web Goto Github PK
View Code? Open in Web Editor NEWGo Router + Middleware. Your Contexts.
License: MIT License
Go Router + Middleware. Your Contexts.
License: MIT License
The error message in ShowErrorsMiddleware has a heading for "Parameters" that is incorrectly spelt "Paramenters"
<h3>Paramenters:</h3>
(line 179)
Hi,
I was looking at adding the ability to advertise web
routes to Vulcan in a package outside of gocraft/web. This would be kinda similar to how Mailgun's scroll registers its routes into etcd, so then vulcand can send it traffic:
https://github.com/mailgun/scroll
However the Routes are currently all private, and there is no way to get them once they have been added. This could be as easy as adding a Routes() []*Routes
or similar function, so then it is possible to introspect the routes on a router.
Works
router := web.New(Context{})
router = router.Subrouter(Context{}, "/")
router.Get("/", index)
Panics
router := web.NewWithPrefix(Context{}, "/test")
router = router.Subrouter(Context{}, "/")
router.Get("/", index)
Works
router := web.NewWithPrefix(Context{}, "/test")
router = router.Subrouter(Context{}, "")
router.Get("", index)
Have a idea to protect our production from spam on middleware level, set up X-RateLimit-Limit and X-RateLimit-Remaining and cancel request when rate limit reach. Maybe anybody know good middleware for this?
Shouldn't subrouter's be using the same middleware chained to the parent? I found this wasn't the case and seemed unintuitive.
Hi,
when I try to upload a file via a multipart/form-data request I get the error multipart: NextPart: EOF
My code looks like this:
func (c *TypeContext) UserUploadProfilePicture(rw web.ResponseWriter, req *web.Request) {
var (
err error
file multipart.File
handler *multipart.FileHeader
)
req.ParseMultipartForm(32 << 20)
file, handler, err = req.FormFile("profile_picture")
if err != nil {
return
}
defer file.Close()
f, err := os.OpenFile("./test/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
return
}
defer f.Close()
io.Copy(f, file)
}
Apologies if this is duplicated elsewhere (and fantastic error messaging, thanks!)
I'm generating standard handler funcs for regular pages, so I have a makeHandler() func that returns a handler func that looks like:
rt = web.New(Context{})
for _,name in RouteList{
rt.Get("/"+strings.ToLower(name),makeHandler(name))
}
func makeHandler(name string) func(*Context, web.ResponseWriter, *web.Request) {
return func(c *Context, w web.ResponseWriter, r *web.Request) {
//*** handler gubbins ****
}
}
Compiles fine, but panics on execution with:
* You are adding a handler to a router with context type 'Context'
*
*
* Your handler function can have one of these signatures:
*
* // If you don't need context:
* func YourFunctionName(rw web.ResponseWriter, req *web.Request)
*
* // If you want your handler to accept a context:
* func (c *Context) YourFunctionName(rw web.ResponseWriter, req *web.Request) // or,
* func YourFunctionName(c *Context, rw web.ResponseWriter, req *web.Request)
*
* Unfortunately, your function has this signature: func(*main.Context, http.ResponseWriter, *http.Request)
*
obviously I have a function main() so any attempt to add Context to main failed ;)
Also a bit bemused by the http lib references when my func clearly uses nothing but web lib references.
Any clues on how to overcome? I can work around it for now but this is the way I'd like to go with the code if possible.
I am sorry if this was answered before, but I can't seems to find a way to use multiple domains ..
I have multiple domains on the same server and I am trying to set a domain to a specific route.
I have tried this, but I get 404 Not found:
router.NotFound((*Context).NotFound)
router.Middleware(web.StaticMiddleware("static", web.StaticOption{Prefix: "/", IndexFile: "index.html"}))
router.Get("domain.com/something/", (*Context).SomethingRoot)
router.Get("/:link", (*Context).Root)
fmt.Println("Server started on port " + strconv.Itoa(port) + "..")
http.ListenAndServe(":"+strconv.Itoa(port), router)
Thank you in advance!
In the process of playing around with gocraft/web I've attempted to bring across a custom handler type that I use to save me some repetition when needing to return errors.
type appHandler func(w http.ResponseWriter, r *http.Request) *appError
type appError struct {
code int
err error
}
// Ensures appHandler satisfies the http.Handler interface
func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if e := fn(w, r); e != nil {
// Handle error cases
}
}
The problem I'm having is integrating this into gocraft/web - which provides it's own wrappers (web.ResponseWriter
and *web.Request
).
type appHandler func(w web.ResponseWriter, r *web.Request) *appError
// Ensures appHandler satisfies the http.Handler interface
func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// We can't pass in w, r here as they aren't web.ResponseWriter or web.Request
if e := fn(w, r); e != nil {
// Handle error cases
}
}
Is there a way to achieve this? Looking at the docs, the GenericHandler
type has a signature of func(web.ResponseWriter, *web.Request)
but I'm not sure on how to reconcile this with wanting a ServeHTTP method for my handler types.
Hello,
I've created simple application:
package main
import (
"github.com/gocraft/web"
"net/http"
)
type Context struct{
}
func main() {
router := web.New(Context{}).
Middleware(web.LoggerMiddleware).
Middleware(web.ShowErrorsMiddleware).
Middleware(web.StaticMiddleware("public"))
http.ListenAndServe("localhost:8080", router)
}
in the same folder I have "public" directory with "index.html" file inside.
If I make "http://localhost:8080/index.html" request, I got "404 page not found"
any idea why ?
Here is a snippet of a continuation of the nested routers and use of pointers with Context example from the docs:
https://gist.github.com/bundah/d29cfc5fed6a6cb8428c
Removing the struct pointer for User and following same pattern in web.New yields less crash but still incorrect behaviour:
adminRouter := rootRouter.Subrouter(AdminContext{CurrentAdmin: User{Name: "Bill"}}, "/admin") // and also change the struct
And finally, if we change these bits to:
type AdminContext struct {
*Context
CurrentAdmin User
}
actx := AdminContext{CurrentAdmin: User{Name: "Bill"}}
adminRouter := rootRouter.Subrouter(actx, "/admin")
adminRouter.Get("/reports", (actx).Reports) //(*AdminContext).Reports)
and curl that one, the name prints... Except that all requests now share actx instance and changing anywere at runtime via middleware etc crosses the request boundary (and can poison other requests).
Please advise...
Today I accidentally passed a gocraft/web
subrouter to the net/http
package. This was an accident on my part, but resulted in some strange behavior. It appears that for each request, it was performed twice. I was not even aware a subrouter could be pased to net/http
.
This example demonstrates my mistake, but does not replicate the behavior.
// serve_subrouter.go
package main
import "net/http"
import "github.com/gocraft/web"
import "sync/atomic"
import "fmt"
var numcall uint32
type Context struct{}
func printNumCalls(rw web.ResponseWriter, req *web.Request, next web.NextMiddlewareFunc) {
count := atomic.AddUint32(&numcall, 1)
fmt.Printf("Call #%d\n", count)
next(rw, req)
}
func helloHttp(rw web.ResponseWriter, req *web.Request) {
rw.WriteHeader(http.StatusOK)
fmt.Fprint(rw, "Hello HTTP\n")
}
func main() {
router := web.New(Context{})
subrouter := router.Subrouter(Context{}, "/foo")
subrouter.Middleware(printNumCalls)
subrouter.Get("/bar", helloHttp)
http.ListenAndServe(":8080", subrouter) //use subrouter by accident
}
As you can see, subrouter
can be used as it implements http.Handler
. However, all I got was a panic when I used curl
to get "http://localhost:8080/foo/bar".
ericu@ericu-desktop:~$ go run ./serve_subrouter.go
2014/11/05 22:18:28 http: panic serving [::1]:51597: runtime error: makeslice: cap out of range
goroutine 20 [running]:
net/http.func·011()
/home/ericu/builds/go/src/pkg/net/http/server.go:1100 +0xb7
runtime.panic(0x6cb260, 0x8bc0fc)
/home/ericu/builds/go/src/pkg/runtime/panic.c:248 +0x18d
github.com/gocraft/web.(*Router).ServeHTTP(0xc208058180, 0x7fe673d358c8, 0xc20803cbe0, 0xc208029040)
/home/ericu/gotmp/src/github.com/gocraft/web/router_serve.go:32 +0x82
net/http.serverHandler.ServeHTTP(0xc208004180, 0x7fe673d358c8, 0xc20803cbe0, 0xc208029040)
/home/ericu/builds/go/src/pkg/net/http/server.go:1673 +0x19f
net/http.(*conn).serve(0xc20803e200)
/home/ericu/builds/go/src/pkg/net/http/server.go:1174 +0xa7e
created by net/http.(*Server).Serve
/home/ericu/builds/go/src/pkg/net/http/server.go:1721 +0x313
^Cexit status 2
ericu@ericu-desktop:~$ go run ./serve_subrouter.go
2014/11/05 22:18:42 http: panic serving [::1]:51598: runtime error: makeslice: cap out of range
goroutine 20 [running]:
net/http.func·011()
/home/ericu/builds/go/src/pkg/net/http/server.go:1100 +0xb7
runtime.panic(0x6cb260, 0x8bc0fc)
/home/ericu/builds/go/src/pkg/runtime/panic.c:248 +0x18d
github.com/gocraft/web.(*Router).ServeHTTP(0xc208056180, 0x7f74ab7559c8, 0xc20803cbe0, 0xc208029450)
/home/ericu/gotmp/src/github.com/gocraft/web/router_serve.go:32 +0x82
net/http.serverHandler.ServeHTTP(0xc208004180, 0x7f74ab7559c8, 0xc20803cbe0, 0xc208029450)
/home/ericu/builds/go/src/pkg/net/http/server.go:1673 +0x19f
net/http.(*conn).serve(0xc20803e200)
/home/ericu/builds/go/src/pkg/net/http/server.go:1174 +0xa7e
created by net/http.(*Server).Serve
/home/ericu/builds/go/src/pkg/net/http/server.go:1721 +0x313
The obvious solution is not to pass subrouter
to net/http
. But it seems this mistake could be avoided by making the subrouter not implement the http.Handler
type. This would generate a very obvious compile time error. If I come up with some patches to do this, would you be willing to accept them?
Have tried the following
Middleware(web.StaticMiddleware("./static"))
Middleware(web.StaticMiddleware("static"))
Middleware(web.StaticMiddleware("/static"))
If the directory exists I get the error
seeker can't seek
If it doesn't exists the page loads with the exception of the static files I get 404's as I would expect.
Little more investigation on this. If you do not have an index file in the static directory then it try's to send the directory to the http.ServeContent() function which is then not able to seek to the end of the file to get the length so send with the request cause it is a directory. So you get the error "seeker can't seek"
was able to work around this by putting this before the serveContent()
if file == "/" {
next(w, req)
return
}
You route as a TREE is an excellent idea. The benchmark too.
This article should interest you: "https://gdstechnology.blog.gov.uk/2013/12/05/building-a-new-router-for-gov-uk/", similar approach, using a TRIE instead (see code on github).
If your tree is not to remained always balanced, a TREAP could enhance your solution further (see example of implementation here: stathat and https://github.com/zond/treap).
I have no time to contribute to gocraft/web now but will when time available.
Hi Folks,
I've wrapped your package in a library for a set of web services that always return JSON data (except for one case, this one, when downloading a file). I set the Content-Type with a piece of middleware:
rRouter := &Router{}
rRouter.mDispatch = web.New(Context{})
rRouter.mDispatch.Middleware(func(rw web.ResponseWriter, r *web.Request, next web.NextMiddlewareFunc) {
rw.Header().Set("Content-Type", "application/json; charset=utf-8")
next(rw, r)
})
In one of my handlers, I want to override this for a file download:
rw.WriteHeader(201)
bytes := getContent(filename)
rw.Header().Set("Content-Type","application/pdf")
rw.Header().Set("Content-Disposition", "Attachment; filename="filename")
rw.Write(bytes)
When the endpoint is called, the content type comes down as application/json
and not application/pdf
as expected. I also have verified that the content type is set properly in the rw.Header
map:
log.Printf("%+v", rw.Header())
2018/06/13 21:08:03 map[Content-Type:[application/pdf]]
If I remove the middleware, this works fine. Any suggestions or insight as to what may be happening? Am I working with a copy of the rw
var?
Thanks in advance.
Hello,
Is there a simple sample project that glues together web, dbr and health? I am new to golang and these 3 projects are exciting but would appreciate some initial hand holding setup wise that a sample app would help with.
Currently, there is no way to set the path prefix of the root router. It should be allowed as the application may not listen at the root of a server. An example is a REST API that may want to prefix all routes with /api or /v1 etc.
Given a route with the following path "foo/:*"
is impossible to retrieve with the classic methods such Request.FormValue("key")
the value of the param if the request has the following url "foo/bar?key=value"
Hi. I was directed to file an issue here by one of your engineers in lieu of posting to an email list dedicated to this project.
I'm evaluating gocraft/web for use in a reference application my colleagues will use to pattern new microservices after in Go. The purpose of the reference app is to make choices around how to structure the code and model dependencies (database, service discovery, etc) configuration/injection so application developers don't have to individually make all these choices all over again themselves.
One of the specific questions I have around gocraft/web concerns how to idiomatically integrate OAuth2 token validation for a given endpoint. An endpoint is defined as the combination of an HTTP-verb:url-path.
Take this example from your readme:
router.Put("/users/:id", (*YourContext).UsersUpdate)
Imagine that you want to constrain consumption of this resource to users who present an OAuth2 bearer token with a specific scope. Say this scope has to be "admin/update-user". I'm wondering how you recommend enforcing such a constraint in a canonical gocraft/web app. One way is to insert a middleware that extracts the token from the request, places derived token detail information including scope into YourContext, then have the UsersUpdate method either allow or disallow the request based on some allowed, essentially hardcoded scope in the YourContext method itself.
For example, UsersUpdate pseudocode might look like this:
func (c *YourContext) UsersUpdate(rw web.ResponseWriter, req *web.Request) {
if c.token.scope != "admin/update-user" {
return unauthorized
}
do work
}
The downside of this approach is that the endpoints are burdened with this sort of security check. A closure around the method might work, which closes over the required scope, but frankly I'm not sure how to articulate that in this situation.
Another way, which I cannot quite yet see my way clear to in idiomatic gocraft/web, is to imbue the middleware code with a table of tuples that look like HTTP-verb:URL-path:required-scope(s) and allow or deny the request in the middleware before the request makes it to UsersUpdate. This suggests some duplication in the articulation of the tuple with information already in the router.PUT() path-with-placeholders. iow, "/users/:id" would appear twice: once in the router.PUT() binding, and once in the middleware constraint rules. Even then, the middleware would have to match the request against the /path/:placeholder template, if such a match is easily performed with some gocraft/web stateless function.
Thank you for reading this far. Does the community have recommendations or strong patterns on how to handle such a requirement in gocraft/web?
Many thanks.
Mark
gocraft/web looks quite attractive, but there doesn't seem to be a license specified anywhere I can find. Using it for real work without an explicit license would be a great way to get lawyers angry at me. I don't want lawyers angry at me. Probably no one else does, either.
Please help us placate our legal overlords!
First off, thanks for building a flexible, yet simple router & middleware system.
I was wondering, though -- Do you have any thoughts on how I might go about implementing "Outerware" (often called output filters)? Essentially, middleware that will get executed after the route handler gets processed? You could imagine that for ever web request you serve, you want to have a standard way of recording stats for that request without having to put the code in each handler. For instance:
type YourContext struct {
startTime time.Time
}
func (c *YourContext) StartRequest(rw web.ResponseWriter, req *web.Request, next web.NextMiddlewareFunc) {
c.startTime = time.Now()
next(rw, req)
}
func (c *YourContext) EndRequest(rw web.ResponseWriter, req *web.Request, next web.NextOuterwareFunc) {
fmt.Fprint(rw, "request_time=", time.Since(c.startTime), " request_url=", req.URL.Path)
next(rw, req)
}
router := web.New(YourContext{})
router.Middleware((*YourContext).StartRequest)
router.Get("/users", (*YourContext).UsersList)
router.Post("/users", (*YourContext).UsersCreate)
router.Put("/users/:id", (*YourContext).UsersUpdate)
router.Delete("/users/:id", (*YourContext).UsersDelete)
router.Patch("/users/:id", (*YourContext).UsersUpdate)
router.Get("/", (*YourContext).Root)
router.Outerware((*YourContext).EndRequest)
You could also imagine this process would be useful for having the handlers prep the context with the output data, and a common outerware takes that data and generates the JSON response. I think the alternative would be to call a common function at the end of every handler. That solution just is not as flexible in terms of attaching different outerware to different routers and subrouters (not demonstrated in the above example).
Thanks!
when using gocraft/web
one has to server websockets on a different port than the legacy http service.
i've added example code below, as one can see:
i want both to listen on 8080, how to do that?
func main() {
server := ws.NewServer("/websocket")
go server.Listen()
go http.ListenAndServe("localhost:12345", nil) // Start the WS server!
go inotifyWatchDir("output"); // FIXME hardcoded path
router := web.New(Context{}). // Create your router
Middleware(web.LoggerMiddleware). // Use some included middleware
Middleware(web.ShowErrorsMiddleware). // ...
//Middleware(web.StaticMiddleware("../output")).
Middleware(web.StaticMiddleware("output")). // FIXME hardcoded path
Middleware((*Context).SetHelloCount). // Your own middleware!
Get("/", (*Context).SayHello) // Add a route
http.ListenAndServe("localhost:8080", router) // Start the server!
}
example websocket implementation i'm using:
https://github.com/golang-samples/websocket/
as pointed out in #24 i would also consider using gorilla websockets but i do not have a clue how to use the Hijacker interface
.
@phea ideas?
The HTTP package in go has a Filesystem interface so that you don't have to back your server with a real fileserver.
In static_middleware.go
, the string param type means that you can't use anything other than a real OS file; a call-path that accepted any http.Filesystem would let me use (e.g.) github.com/jteeuwen/go-bindata
This leads to inability to correctly use StaticMiddleware on a subrouter.
Using a trivially modified example that sleeps in the middle of an output:
func (c *Context) SayHello(rw web.ResponseWriter, req *web.Request) {
Fprint(rw, strings.Repeat("Hello ", c.HelloCount), "World!")
rw.Flush()
time.Sleep(2 * time.Second)
Fprint(rw, strings.Repeat("Hello ", c.HelloCount), "World!")
}
Running curl 127.0.0.1:3000
won't print anything until the entire output is finished.
Adding a newline to the printed strings will make this example behave as expected.
Is this an issue with gocraft/web, or is the problem at another layer?
Do you forsee any issues with leaving requests open like this?
I'm assuming that each request is inside its own gofunc, and so could be used to trivially implement server-sent events, an alternative to websockets that uses "plain" HTTP.
I've added middleware which will connect to a database if there's not already a database connection for that context.
Currently the DB url is hardcoded, but the plan is to have it passed in as a command line parameter by the user. What's the recommended way to pass the in the DB url to the middleware? Are there any examples of middleware objects that are initialized with options?
I use rethinkdb.
Is the context thread safe to hold dB sessions ?
Also I need to write none http servers. I would like to use as much shared code across both.
I am still learning, but what advicecan you offer here.
Thanks in advance. And sorry for such open questions
Hi Folks,
I'm attempting to wrap your library in an additional abstraction library of my own design. The intention is to create convenience functions to create REST services. This may be more of a Go question than anything, but I have tracked the problem down to your validation code when adding handlers (isValidHandler
).
Your functions require the following signature:
func YourFunctionName(rw web.ResponseWriter, req *web.Request)
So that all of my libraries that create handlers aren't required to include your library as well as my new one, I have created a set of types to accommodate your signatures:
type PathHandler func(rw WebWriter, req *WebRequest)
type WebWriter web.ResponseWriter
type WebRequest web.Request
In this manner, my functions can adhere to this type PathHandler
func Read(rw WebWriter, req *WebRequest) {
...
}
func GenerateReadEndpoint() PathHandler {
return Read
}
The code panics when trying to add the handler via router.Get()
etc., as the isValidHandler
function rejects the types I have created.
Is there any way to accomplish this, or do you have a function type that I may have missed that I can use to abstract your library?
Thanks.
Concurrently configuring the router causes data race
e.g.
go router.Get("/foo", foo)
go router.Post("/bar", bar)
causes data-race.
Read by: web/router_setup.go:239
Previous write by main goroutine: web/router_setup.go:122
Is it possible to start tagging versions for this project again? I'm currently using glide, which I know is not standard, but it supports versions though github tags.
It seems like the versions were getting tagged, but that stopped a while back.
Unfortunately you can't use Gocraft's Handler for websockets as it does not implement the required Hijacker interface. Passing web.ResponseWriter will fail at this line:
https://github.com/gorilla/websocket/blob/master/server.go#L134
Would you mind create version tag? It'll make possible use your package through http://gopkg.in
I like a lot of the things gocraft/web
does, and figured that it could do with a little home page to get a little more face time with web framework seeking Gophers.
I've hacked together a quick "first pass" at what it could look like, using content from the existing README as some temporary filler. It currently exists in the gh-pages branch of my fork—you'll need to create a gh-pages branch for me to push to.
Let me know what you think. I'm not married to the colors and/or syntax highlighting theme so more than happy to take feedback (dark version here).
PS: I'd also be keen to add some godoc-style comments to the codebase. The README
and examples/
are pretty darned good, but some extra comments in the code could be useful for godoc.org addicts like myself.
Hello!
Thank you for the great library - we use it daily. Recently we ran into a small issue.
This is a go vet
bug in my opinion, but until that is addressed, people running go vet
on their code (including /vendor
folder) will run into the following warning when using the Error
handler:
arg (*Context).Error in Error call is a function value, not a function call
You can also see this by running go vet
in the root of this project. I think go vet
is incorrectly picking up keywords here (error, panic, etc) and incorrectly reporting that warning, as renaming Error
to Panic
also fails, where OnError
passes (for example).
Packages like appengine and go.net/context provide contexts that are immutable – functions that modify a context return a new context with the desired changes rather than mutating an existing one. (See https://godoc.org/code.google.com/p/go.net/context#WithValue and https://cloud.google.com/appengine/docs/go/reference#Timeout as well as https://cloud.google.com/appengine/docs/go/datastore/reference#RunInTransaction , and note how http://godoc.org/github.com/mjibson/appstats expects handlers to not call appengine.NewContext, but use the context that the appstats middleware provides.)
gocraft/web makes the opposite assumption – it instantiates a new context for every request (meaningless for immutable contexts), and, IIUC, forces middleware that needs to have an effect on the context to do so through mutation – middleware receives the context object but can't pass a different context to the "next" handler function.
Is this correct? (I've only skimmed the documentation, not played with the code.) If so, what are your thoughts on this – how would you feel about extending gocraft/web to allow it to work with immutable contexts? The motto is "Go Router + Middleware. Your Contexts", after all, so immutable contexts aren't obviously out of scope; and I believe that appengine and go.net/context are setting a good precedent by providing immutable contexts, since they are automatically thread-safe, and allow setting timeouts etc. with a form of dynamic scope rather than per-request (which would force such settings to be the same across all goroutines that relate to the same request).
I haven't thought about what exactly it would take, but I think we'd need to at least allow middleware to call the "next" function with a different context; and allowing interfaces as the context type might also be helpful. I don't know if there are type system issues with either or both of these. Before I go any further – have you thought about this before and rejected it?
Ive been trying to integrate and use middleware provided by go libraries that make use of the http.Handler pattern, but for the life of me can't figure out how to get those to work with GoCraft on a subrouter.
Any pointers would be appreciated :-)
Looks like it's the same comment as NotFound, got copied over.
It would be really helpful, if we include the request URL in the error log message.
https://github.com/gocraft/web/blob/master/router_serve.go#L244
ERROR.Printf("%v\n", req.URL)
ERROR.Printf("%v\n", err)
ERROR.Printf("%s\n", string(stack))
Also, I think we should combine those 3 single Printfs into one...
I think it will be usefull to create some kind of Helper/Middleware that auto-creates route /sitemap.xml
route and writes XML to io.Writer
.
I already have an implementation. If you see this issue as necessary I can add it via PR.
Hi
Atm I am doing something like:
router.Get("/foo", (*controllers.RootContext).RedirectToDashboard)
func (c *RootContext) RedirectToDashboard(w web.ResponseWriter, req *web.Request) {
http.Redirect(w, req.Request, "/a/dashboard", http.StatusFound)
}
Is this the best way to do it or is there a more succinct way that I am missing?
Maybe it would be nice something like:
router.Redirect("/foo", "/a/dashboard")
Good day.
Do you plan to wrap web.request and web.responsewriter into context for handlers like this:
func helloHandler (ctx * MyCtx);
type MyCtx struct {
req web.request
rw web.respwriter
}
Hi,
I have this use case where I need to pass some pointers to data structure to each new instanciated context; these structures mostly contain pointers to services (datastore, search...) that are created at application startup. Problem is: I don't see any hook I could use to pass these structures to newly created context.
I though maybe it would be useful for me and others to be able to pass a context factory (func() *Context) to the router at creation time. With this, I could do somethinh like:
type Context struct {
Search *SearchService
}
...
search := NewSearchService(...)
router := web.New(Context{}, func() *Context {
return &Context{Search: search}
})
Maybe a little fasthttp support?;)
I have Context struct and tried to register router method from struct with embedded Context struct like below
type desktopContext struct {
Context
}
I would like to have separate controller with their own methods and register them like
func (c *desktopContext) index(rw web.ResponseWriter, req *web.Request) {
}
and use it like
router.Get("/", (*desktopContext).index)
Got the following error
func init() {
rootRouter := web.New(Context{}).Middleware((_Context).LoginRequired)
adminRouter := rootRouter.Subrouter(AdminContext{}, "/admin")
adminRouter.Middleware((_AdminContext).AdminRequired)
// http.Handle("/", rootRouter)
}
I'm trying gocraft in google's app engine. For the code above I found it's a bit unexpected results for me because only LoginRequired middleware been called when I go url "..../admin". I expect the AdminRequired middleware been called too since I've subrouter it.
Add this code:
/*
adminRouter.Get("/", (*AdminContext).Handler)
*/
should work just like sample code. But I expect AdminRequired been called in any of http methods even I don't have the matching handlers. Sounds reasonable?
Hi,
How do I access the root context from my subroute? For example, if I have a Session defined in Context, how do I access from /admin/index?
Accessing "Session" causes a "runtime error: invalid memory address or nil pointer dereference"
See code below.
type Context struct {
Session map[string]string
}
type AdminContext struct {
*Context
CurrentAdmin *User
}
func (ac *AdminContext) Index(rw web.ResponseWriter, req *web.Request) {
fmt.Println(ac.Session["key"]); //runtime error: invalid memory address or nil pointer dereference
}
rootRouter := web.New(Context{})
adminRouter := rootRouter.Subrouter(AdminContext{}, "/admin")
adminRouter.Get("/reports", (*AdminContext).Index)
Would be nice to have a way to set default fields of a context struct that doesn't get zeroed on each request. For example DB session is only initialised once and shouldn't need to be set to the context on each request (if not necessary to overwrite it with a different DB session)
Instead of of workaround using built-in http://golang.org/pkg/net/http/#ServeMux (http://stackoverflow.com/questions/14170799/how-to-get-virtualhost-functionality-in-go) , can we do it directly in go craft web?
Using this code:
path, _ := os.Getwd()
path += "/public/media"
router := web.New(Context{}).
Middleware(web.LoggerMiddleware). // Use some included middleware
Middleware(web.ShowErrorsMiddleware).
Middleware(web.StaticMiddleware(path)).
Get("/index.html", (*Context).Main).
Get("/", (*Context).Main).
NotFound((*Context).NotFound)
One can not just open: localhost:3000 in the browser because one is then always matched against the StaticMiddleware. But I would like that localhost:3000 opens the Main page instead of having to type, say localhost:3000/index.html every time.
Am I missing something here?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.