zenazn / goji Goto Github PK
View Code? Open in Web Editor NEWGoji is a minimalistic web framework for Golang that's high in antioxidants.
License: MIT License
Goji is a minimalistic web framework for Golang that's high in antioxidants.
License: MIT License
Perhaps this is known, but when trying to install on Ubuntu I got the following:
/usr/lib/go/src/pkg/github.com/zenazn/goji/graceful/middleware.go:38: undefined: http.CloseNotifier
/usr/lib/go/src/pkg/github.com/zenazn/goji/graceful/middleware.go:93: undefined: http.CloseNotifier
/usr/lib/go/src/pkg/github.com/zenazn/goji/graceful/middleware.go:118: undefined: http.CloseNotifier
/usr/lib/go/src/pkg/github.com/zenazn/goji/graceful/signal.go:50: undefined: signal.Stop
/usr/lib/go/src/pkg/github.com/zenazn/goji/web/middleware.go:198: syntax error: unexpected :, expecting ]
have some code example?
gorilla/mux provides a StrictSlash method that redirects routes missing a trailing slash to one with a slash (or vice versa), primarily for SEO and secondly for browser history clarity.
It would be nice if Goji could provide a similar feature as part of its own router.
Hi,
Is there a way to define route groups similar to Martini?
m.Group("/books", func(r martini.Router) {
r.Get("/:id", GetBooks)
r.Post("/new", NewBook)
r.Put("/update/:id", UpdateBook)
r.Delete("/delete/:id", DeleteBook)
})
By the way, goji looks really great!
I know there are a lot of tools around for this. Not many of them work though. I was wondering with graceful shutdown and reloading built-in, will there ever be a dev
mode for reloading server when files change.
It is not a bug.
It's a link to Go routers performance comparison for anyone interested:
https://github.com/julienschmidt/go-http-routing-benchmark
From readme:
Goji looks very decent. It has great performance while also having a great range of features, more than any other router / framework in the top group.
Thank you for your hard work.
I have tried changing the bind port and am running into issues. Do you happen to have a simple example handy?
I suggest that this project should tag releases on Github.
Just rising a concern real quick (I'm sorta new to Go, so bear with me ;)).
I noticed that the mux in default.go is global. My concern is if one of my dependencies uses mux, can they expose routes to my app? How potentially "unsafe" is it since the goji mux is global?
Is it safer just to usegithub.com/zenazn/goji/web
directly?
PS. great work.
Is there some middleware or libs?
Hi,
I'm trying to nut out an issue where a sub-router w/ some middleware applied is returning a 200 OK status instead of 404 Not Found.
The relevant routes—the route returning 200 (when it should not) is the /administrate/dashboard
route. r.Handle is part of the top-level router (r := web.New()
).
// Admin dashboard
admin := web.New()
// Log all admin requests separately from the downstream server.
admin.Use(middleware.Logger)
admin.Use(AdminOnly)
r.Handle("/administrate/*", admin)
// admin.Get("/administrate/dashboard", appHandler(adminDashboardHandler))
// admin.Get("/administrate/edit/:id", appHandler(adminEditHandler))
Here's the middleware:
// AdminOnly is a middleware that checks the userID in the session is an admin (boolean).
// It does not set any 'admin' flags in the session itself (it checks on each request).
func AdminOnly(c *web.C, h http.Handler) http.Handler {
fn := appHandler(func(c web.C, w http.ResponseWriter, r *http.Request) (int, error) {
session, err := store.Get(r, "workwithgo")
if err != nil {
return 500, err
}
// Re-direct to the login page if no ID is found in the session.
id, ok := session.Values["userID"].(string)
if !ok {
http.Redirect(w, r, loginURL, http.StatusFound)
return 302, nil
}
// Lookup the id from the session
user := models.User{Id: id}
admin, err := user.IsAdmin()
if err != nil {
return 500, nil
}
// Return 200 (and proceed) if the user is an administrator.
if admin == true {
log.Println("admin == true")
return 200, nil
}
// Return a HTTP 401 if the user is NOT an administrator.
return http.StatusUnauthorized, fmt.Errorf("User ID %q is not authorized to login", user.Id)
})
return fn
}
I believe the issue is triggered by if admin == true
block: instead of raising a 404 on the wrapped handler (which is commented out at the moment), it just renders an empty body with a 200 OK status header.
Hitting any sub-route that is wrapped by the middleware exhibits the same issue.
The ServeHTTPC method on the custom handler type does not do anything fancy with a 200 status - it only does something when err != nil, so it should not be interfering.
// Allows appHandler to satisfy http.Handler
func (ah appHandler) ServeHTTPC(c web.C, w http.ResponseWriter, r *http.Request) {
if status, err := ah(c, w, r); err != nil {
switch status {
case http.StatusNotFound:
...
// More cases
}
}
}
Ultimately, I want to apply the middleware to the subrouter and have it 404 (as it should) when routes don't exist. For routes that do, the middleware should just do its job and pass requests through to the next handler in the chain.
Is it possible to serve parts of html and build a page using goji?
For example if I wanted to serve the of results.html, write , and then in a for loop write contents of the body of that page, and then . Or will I have to use standard Golang features like:
func viewHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[len("/view/"):]
p, _ := loadPage(title)
fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body)
}
When using Einhorn I know we can specify a PID file to write to such as "einhorn -e einhorn.pid ./main" but whenever I kill that PID the entire process dies.
How do I get the PID of the worker and not the master so I can do "kill -USR2 PID"
Hello there !
I like goji, it's all simple and light and I have a question : How would you do simple error handling ?
Like, may be in this post : http://blog.golang.org/error-handling-and-go ?
Having some handler funcs that look like this :
func viewStuff(w http.ResponseWriter, r *http.Request) *appError
With appError looking like this :
type appError struct {
Error error
Message string
Code int
}
So then in the handler I could :
if err := datastore.Get(c, key, record); err != nil {
return &appError{err, "Record not found", 404}
}
Thanks !
I get the following error while building on windows
# github.com/zenazn/goji/bind
..\..\zenazn\goji\bind\einhorn.go:40: cannot use fd (type int) as type syscall.H
andle in function argument
..\..\zenazn\goji\bind\systemd.go:28: cannot use systemdMinFd + i (type int) as
type syscall.Handle in function argument
# github.com/zenazn/goji/graceful
..\..\zenazn\goji\graceful\einhorn.go:21: undefined: syscall.SIGUSR2
Is there a plan of commit to a stable API moving forward—at least for the core packages?
I can understand if the middleware package may change down the track and/or breaking changes made when absolutely needed.
im surprised with the lack of detailed coverage on how to run golang web app in the background process i.e. when i close my ssh window it doesnt go down together with it.
and a good tool to just do a simple start, stop, AND RESTART!
how do we do it with goji? running it as a background process using supservisord seems fine with centos but the during restart, the program will just hang.
and using einhorn. i can start it. but cant restart it...
the einhorn only claimed "You can also seamlessly restart your workers without dropping any requests" but never document the HOW part.
im seriously frustrated with the current condition. golang is so beautiful n powerful n yet the deployment is a bitch.
I'm trying to access c.URLParams in a middleware function of mine, however c.URLParams doesn't seem to be initiated. I am either doing something wrong on my end or maybe URLParams is initiated after all the middleware calls. Anyone able to clarify.
On the website.
Hi,
Do you have plans for other middleware? Sessions, OAuth2, ...
I am learning so I am not much help, but it would be nice if you could provide some more common middleware like martini?
Thanks
Hi can you please give me an example on how to use with http.FileServer for serving static assets?
Apologies if I am being a noob / novice, but I am just getting started with Go.
I'm trying to run the sample programme and I am getting an error.
Here is the contents of hello.go:
package main
import (
"fmt"
"net/http"
"github.com/zenazn/goji"
"github.com/zenazn/goji/web"
)
func hello(c web.C, w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %s!", c.URLParams["name"])
}
func main() {
goji.Get("/hello/:name", hello)
goji.Serve()
}
hello.go:7:9: cannot find package "github.com/zenazn/goji" in any of:
/usr/local/go/src/pkg/github.com/zenazn/goji (from $GOROOT)
/Users/Irfan/Projects/Go/src/github.com/zenazn/goji (from $GOPATH)
hello.go:8:9: cannot find package "github.com/zenazn/goji/web" in any of:
/usr/local/go/src/pkg/github.com/zenazn/goji/web (from $GOROOT)
/Users/Irfan/Projects/Go/src/github.com/zenazn/goji/web (from $GOPATH)
What am I doing wrong?
Heroku (and possibly others) are using the environment variable HTTP_X_REQUEST_ID
for request ids. It would be nice if the Goji request_id middleware did so too.
https://devcenter.heroku.com/articles/http-request-id
Is this something you would consider @zenazn, or should I make my own logger and abandon the built in logger?
such as following:
2014/08/20 17:20:25.099016 [PC-CORP/O6smW20tuK-000001] Started GET "/admin/" from [::1]:35653
2014/08/20 17:20:25.099016 [PC-CORP/O6smW20tuK-000001] Started GET "/admin/" from [::1]:35653
2014/08/20 17:20:25.101017 [PC-CORP/O6smW20tuK-000001] Returning 200 in 2.001ms
2014/08/20 17:20:25.101017 [PC-CORP/O6smW20tuK-000001] Returning 200 in 2.001ms
I'm looking to contribute some middleware—specifically CSRF protection (which I am comfortable in writing out) and possibly some BasicAuth and NoCache middleware.
The CSRF middleware of course needs a session store to store the "real" token to compare with the masked token from form data and/or the request header. I'll wrap gorilla/sessions and look to allowing a package user to provide their own sessions.Store
, else it defaults to a sessions.CookieStore
.
Is there a preferred/idiomatic way to provide an exported configuration struct, initialise it and pass it to the middleware handler?
My current approach would be something like this:
type CSRFOptions struct {
Store *sessions.Store
Options *sessions.Options
CookieName string
}
func NewCSRFOptions(store *sessions.Store, opts *sessions.Options, name string) *CSRFOptions {
c := &CSRFOptions{
...
}
return &c
}
func (c *CSRFOptions) CSRF(c web.C, h http.Handler) http.Handler {
...
}
...
store := NewCSRFOptions(myStore, myOpts, "_csrftoken")
...
goji.Use(store.CSRF)
Do you have a preference for an alternate approach and/or is this compatible with Goji's middleware interfaces? Perhaps a CSRFDefaults() *CSRFOptions
function that makes it easier to get started with?
Hey there. New to Goji (and Go too, a little) and I'm curious if I can have middleware that runs on some routes and not others? For instance, I want some endpoints (most) to require authentication and a few to be public. An auth middleware makes sense, but how can I selectively use it?
Thanks. loving Goji so far!
bind is fantastic, but it defines a -bind
cli flag even when you are not making use of it. I'm aware that people out there may be relying on that specific behaviour but it would be nice to have a mechanism to override it, any ideas?
In the documentation for web.C
it states the following:
If you are closing over a context (especially relevant for middleware), you should not close over either the URLParams or Env objects, instead accessing them through the context whenever they are required.
Could somebody post a small example of a middleware function that violates this edict? I want to make sure I understand the implications of this correctly. Does failing to follow this advice result in the possibility of variables in Env
bleeding across requests?
Instead of having multiple subrouter.Use(SomeMiddleware)
calls, it may be a worthwhile turning it into Use(middleware interface{], middleware ...interface{})
.
The order of middleware passed to Use
would define the ordering (from first -> last) when applied to the router.
r := web.New()
r.Use(middleware.Recovery)
r.Get("/", ShowIndex)
admin := web.New()
r.Handle("/administrate/*", admin)
admin.Use(middleware.Logger)
admin.Use(AdminOnly)
admin.Use(nosurf.NewPure)
admin.Use(gorillacontext.ClearHandler)
// ... would instead just be:
admin.Use(middleware.Logger, AdminOnly, nosurf.NewPure, gorillacontext.ClearHandler)
Potential downsides may be the interaction with middleware inherited from the parent router (in this case, the panic recovery middleware) — one solution would be to make the parent middleware first (implicitly).
This should not be an API breaking change either.
Hi,
After building my application, and putting it under a nginx proxy_pass, I saw that the ip logged was always localhost. After looking at the source, I saw that you use r.RemoteAddr(), which is good for non-proxy use.
Could there be a way to implement goji looking at the headers to get the real ip?
Thanks,
Hello,
I'd like to have extensions types for my routes, but with only one Handler.
/stuff
-> render default type [html]
/stuff.json
-> marshal my data to json
/stuff.html
-> render a template showing data
/stuff.xml
-> marshal my data to xml
/stuff.jsonp
-> marshal my data to jsonp with my default param or the one provided
But if I do
goji.Get("/stuff:_format", getStuff )
The only way it will match is by curling stuff/json
and it won't match on stuff
or stuff.json
.
I havent tried goji.Get("/stuff/:id:_format", getStuff )
I could do :
goji.Get("/stuff.json", getJsonStuff )
goji.Get("/stuff.html", getHtmlStuff )
With handlers wrapping my real controller
But that seems wrong and repetitive, isn't it ?
Is Goji going to support that kind of url matching, may be it already does ? ( I could try to contribute with - still my low go skills - if needed! )
Cheers !
getting something like this on my json response :
"Description":"Firing more than 1 weapon in a turn will increase all damage by 5 / 10 / 15 / 20%!"(MISSING)
it only appears on goji, tried to query the json request using another golang framework, it works fine for them.
is there some issue with goji?
In my middleware I call controllers like this:
controllers.XXXCtrl(c, w, r);
...then in my controller I would like to get db connection form the context
db, _ := c.Env["db"].(database.DB)
...but c.Env["db"] is missing
any better idea how to make it work?
At first glance, this appears to be quite similar to gocraft-web. I was curious what spurred the decision to start a new project and how it differs from some similar libraries?
There's also martini and revel, among several others, but gocraft-web seems to be pretty close in API and design, particularly with its use of web contexts. Several of these projects are mentioned on the home page but it's not clear which unique feature desires sparked goji.
It would be helpful to give a high-level overview of the differences (for example einhorn + systemd are new, while it appears nested routing is exclusive to gocraft).
Whenever I try to run Goji under Einhorn I always get the bindErr: "bind: could not bind einhorn@%d: not running under einhorn"
Any examples on how to run it successfully?
I would like to use Goji for a project hosted on Google App Engine. Unfortunately, Google App Engine does not support the unsafe package (link).
Is it possible to refactor the router to not have to use the unsafe package? This would open Gojil up for developers on Google App Engine.
I didn't find any documentation on how to run multiple goji instances within the same go program. That would be a nice addition, even if just documented here on this issue.
I know there was a reddit and hackernews post, but you could announce this on Golang nuts too. Help spread the word :).
Is it designed to check if the Env map is nil first before assigning values in middle-ware?
goji.Get("subdomain.domain.xyz", root)
any idea how to handle this?
I try to use Goji with Einhorn and it shows this:
2014/06/11 02:42:50 graceful: Einhorn detected, adding SIGUSR2 handler
2014/06/11 02:42:50 dup: bad file descriptor
[MASTER 11532] INFO: ===> Exited worker 11778 before it was ACKed
dup: bad file descriptor
error appears.
Sometimes Einhorn starts normally (and I don't know why exactly - I tried to remove some libraries and it works but then after some time this error appears again):
[MASTER 14292] INFO: [client 2:11] client connected
2014/06/11 02:50:12 bind: ACKing to einhorn
But when I use "upgrade" from einhornsh it shows:
2014/06/11 02:51:00 graceful: Einhorn detected, adding SIGUSR2 handler
2014/06/11 02:51:00 dup: bad file descriptor
[MASTER 14292] INFO: ===> Exited worker 14399 before it was ACKed
[MASTER 14292] INFO: Last spinup was 3.754994809s ago, and spinup_interval is 2.25s, so spinning up a new process (there have been 2 consecutive unacked worker deaths)
Command: go build && einhorn -b 127.0.0.1:8000 -m manual -n 2 ./app
System: Ubuntu 13.10
Non-standard packages:
"launchpad.net/goamz/aws"
"launchpad.net/goamz/s3"
"github.com/twinj/uuid"
I see that the current middleware could just be used on the whole handlers. Is it possible to use them just in some handlers?
No doubt I'm missing something simple: how do I satisfy the web.Handler
interface? I have a common pattern that I use to simplify my app handlers so I don't have to explicitly call an error handler over and over and explicitly return
nothing.
Contrived/example:
type appHandler func(web.C, http.ResponseWriter, *http.Request) *appError
type appError struct {
Code int
Error error
}
// This is the hold up as I need to support the request context (without it, this works fine)
func (fn appHandler) ServeHTTP(c web.C, w http.ResponseWriter, r *http.Request) {
if e := fn(c, w, r); e != nil {
switch e.Code {
case http.StatusOK:
break
case http.StatusBadRequest:
...
case http.StatusNotFound:
http.NotFound(w, r)
case http.StatusInternalServerError:
...
default:
...
}
}
}
func myHandler(c web.C, w http.ResponseWriter, r *http.Request) *appError {
// do things
return &appError{200, nil} // or return nil
}
Currently there is waitForSignal
call from an init()
in the goji/graceful package:
This is somewhat troublesome for an app I'm building that has both "web" and "background worker" processes, where both are run out of the same main package (via a command-line switch). Because the goji/graceful package is imported by this main package, the corresponding goji/graceful init function is called for the web processes - which is fine - but also for the worker process. This results in an unwanted signal handler being installed for the worker processes and associated signal-related logging coming out of that worker process.
It's not a huge deal, but would be nice to fix if possible. Is there any way we could move this waitForSignal
call to a site that would be explicitly called by processes using the package, like graceful.Serve(l)
?
In the meantime, I'm calling graceful.ResetSignals()
in the worker process case as a workaround.
When a path matches but the method doesn't, I'd like to respond with a custom MethodNotAllowed handler. Is this something you'd consider?
Hi All,
I'm pretty new here and new to goji and even new to golang. I trying to execute the simple example program provided in the goji website but getting compilation error "can't find import: "github.com/zenazn/goji"".
I have downloaded "github.com/zenazn/goji" using "go get" command but after executing the command i didn't get any message in the CLI so i'm not sure if the download was successfully but i see some directories/files in my GOPATH. And following is my go env output
root@ubuntu:# go version# go env
go version go1.3 linux/amd64
root@ubuntu:
GOARCH="amd64"
GOBIN=""
GOCHAR="6"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/jennshan/go"
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0"
CXX="g++"
CGO_ENABLED="1"
Any pointers to fix my goji installation would be helpful.
Many Thanks,
Jenni Reuben
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.