jwilner / rte Goto Github PK
View Code? Open in Web Editor NEWExtraordinary routing
License: MIT License
Extraordinary routing
License: MIT License
In gin, it is possible, gin-gonic/gin#51, but is it possible to use websocket in RTE?
The generated function types are really an implementation detail; I think it's probably for users if we just make rte.Route.Handler
interface{}
and do the type conversion in the background with a generated switch block -- i.e.:
type Route struct {
...
Handler interface{}
}
func convert(i interface{}) (h handler, e error) {
switch v := i.(type) {
case http.Handler:
h = func0(v.ServeHttp)
case func(http.ResponseWriter, *http.Request):
h = func0(v)
case func(http.ResponseWriter, *http.Request, string):
h = func1(v)
...
default:
e = fmt.Errorf("unsupported handler type: %T", h)
}
return
}
One of the design goals is performance, but we have no real benchmarking suite to measure anything against. go-http-routing-benchmark is a test suite for a bunch of routing stuff -- we could fork and adapt?
I like that sqlboiler generates tests alongside its generated models -- seems like a good idea for the generated code, here, too.
I want to use RTE with mithril.js as frontend. The original mithril.js uncompressed is about 24K bytes. The compressed size is about 8K.
Could you provide an example to handle:
Right now, when we can't parse a non-string path var as expected, it panics -- https://github.com/jwilner/rte/blob/master/cmd/rte-gen/tmpl_func.go#L64 -- but we need to be returning a 400.
We could just do the default w.WriteHeader(http.StatusBadRequest)
, but users should be able to parameterize that behavior -- so we should probably inject that sort of behavior via Bind
, something like:
type Binder interface {
Bind(segIdxes []int, badReqStrat BadRequestStrategy) (http.HandlerFunc, error)
}
Currently there isn't an easy way to. I think inverting the tree and letting "405" be a special method value seems plausible.
Further support for 405s is probably in order.
After #16, it'd be possible to have a function func Parse(is ...interface{}) []Route
so that users can construct routes like:
h := rte.Must(rte.Parse(
"GET", "/foo/:foo_id", func(w http.ResponseWriter, r *http.Request, fooID string) {},
"POST", "/foo/:foo_id/bar/:bar_id", func(w http.ResponseWriter, r *http.Request, fooID, barID string) {
}, myMiddleware
))
Do we want to use go generate? Client code could use go generate
with cmd/rte-gen
, so that they can do something like:
tbl := rte.New(
...
// go:generate rte-gen hndlrs.MyHndlr string hex-int64
hndlrs.MyHndlr(
"GET", "/foo/:str-param/:hex-param",
func(w http.ResponseWriter, r *http.Request, strParam string, hexParam int64) {
...
},
),
)
If we do, seems like a good goal to start using it ourself for the binding handlers we ship in rte_func.go
:
// go:generate rte-gen funcs.S1 string
// go:generate rte-gen funcs.S1H1 string hex-int64
// go:generate rte-gen funcs.S1I1 string int64
Another way of putting this would be that the Gen logic needs a real cli
For general code cleanliness, and given #2 and #3, we probably want to isolate generated code in its own package. Might make sense to give each its own generated file, if we want a simple interface for go:generate
that only generates one file (and its tests). Maybe a nice package name, too?
rte/
|_ funcs/
|_ s1_h1.go
|_test_s1_h1.go
Currently just using a hash map for each segment. It works, but would we be better suited by a trie / radix tree? Probably best to determine w/ the benchmarking suite in #5
Currently, when matching path variables, we parse the path twice on each request for segments / variables (https://github.com/jwilner/rte/blob/master/rte.go#L153 and again within findNSegments
within each handler https://github.com/jwilner/rte/blob/master/rte.go#L200). Since we're not in the business of heap allocations, we can't just save a dynamic slice of strings to pass into the handlers -- but we also of course don't know how many variables we're gonna get from a given path before we parse. That said, when the table is "compiled", we know the maximum number of path variables we'll ever need to match -- e.g. each Binder
could have a factory method for an array (returning it as a slice) and the compiled table could just always use the factory method of the binder with the most path variables.
We should be able to use the standard func(http.Handler) http.Handler
signature -- but we'll need some wrapper logic to adapt it to be able to get func(rte.Handler) rte.Handler
There are a number of routing options I think we should look at as transforms on lists of routes.
E.g. If people want to permit the absence of a slash, it's usually available as a switch in the router API. IMO, that can bloat the router API. Instead I think we should model these sorts of things as transformations on the route data -- e.g. a function that takes in a list of routes and returns a list of routes with slash made optional. Something like:
func SlashOptional(routes ...Route) []Route {
var copies []Route
for _, r := range route {
c := r
if l := len(r.Path); l > 0 && r.Path[l - 1] == "/" {
c.Path = r.Path[:l - 1]
} else {
c.Path = r.Path + "/"
}
copies = append(copies, c, r)
}
return copies
}
The catch here is that we'd want to be more defensive -- if someone already passed in both paths, we wouldn't want to create duplicates -- so we'd some deduping logic.
A similar API:
func Prefixed(prefix string, routes ...Route) []Route {
....
}
I also sort of think we should drop the variadic spreading everywhere.
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.