Git Product home page Git Product logo

web's People

Contributors

austintaylor avatar bluemir avatar brunoksato avatar bzwheeler avatar corneldamian avatar cypriss avatar danielheath avatar fatih avatar flebel avatar hoffoo avatar johnnadratowski avatar mlctrez avatar nikai3d avatar plorefice avatar rememberlenny avatar treacher avatar tyler-smith avatar ydnar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

web's Issues

Typo in ShowErrorsMiddleware

The error message in ShowErrorsMiddleware has a heading for "Parameters" that is incorrectly spelt "Paramenters"

<h3>Paramenters:</h3> (line 179)

Exposing Routes on Router

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.

appendPath func inconsistency

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)

Rate Limit middleware

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?

subrouter middleware chaining

Shouldn't subrouter's be using the same middleware chained to the parent? I found this wasn't the case and seemed unintuitive.

File upload not working

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)
}

package reference in Context signature

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.

Multiple domains and subdomains

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!

Custom Handler Types?

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.

StaticMiddleware() is not working

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 ?

Method Contexts via route reflect does not support pointers in said Context

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...

Subrouters implement http.Handler but don't do anything useful.

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?

Issue with StaticMiddleWare

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
}

Info: similar approach at GOV.UK. the routes are key!

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.

Header change not honored after middleware set it

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.

sample project that glues web, dbr and health?

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.

Allow path prefix of root router to be set

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.

Impossible to get value of query params

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"

Design pattern around routes and enforcing OAuth2 scopes

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

Needs a license.

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!

Integrating Outerware (middleware post handler processing)

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!

websocket support

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:

  • ws server is on port 12345
  • gocraft's router is hosted on port 8080

i want both to listen on 8080, how to do that?

main.go

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/

gorilla websockets

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?

static_middleware hardcoded to accept string instead of http.Dir

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

Trouble with web.ResponseWriter.Flush()

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.

Need help passing in a configuration value to middleware

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?

Context holding dB sessions ?

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

Function Signatures

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.

The router setup is not race safe

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

Tag Versions?

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.

GitHub Pages for gocraft/web

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.

gocraft/web mockup v0.1

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.

go vet warnings

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).

Support immutable contexts

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?

Is gocraft/web compatible with standard http.Handlers?

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 :-)

proposal: sitemap.xml generator

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.

How to handle redirect

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")

context with request and response

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
}

Optinally pass context factory alongside context

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}
})

Router registration doesn't allow method from struct with just embedded context struct

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


  • 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(desktop.desktopContext, web.ResponseWriter, *web.Request)
    *
    *
    **********************************************************************************************************************

a little fault of middleware in the subrouter, or solution needed.

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?

Accessing the Main Context From Subroute

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.

Context

type Context struct {
    Session map[string]string
}

type AdminContext struct {
    *Context
    CurrentAdmin *User
}

Route Handler

func (ac *AdminContext) Index(rw web.ResponseWriter, req *web.Request) {
    fmt.Println(ac.Session["key"]); //runtime error: invalid memory address or nil pointer dereference
}

Server.go

rootRouter := web.New(Context{})
adminRouter := rootRouter.Subrouter(AdminContext{}, "/admin")
adminRouter.Get("/reports", (*AdminContext).Index)

Set default fields for context

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)

StaticMiddleware(path) precedence

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?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.