Skip to content

Commit

Permalink
Switch to gorilla/mux for server router
Browse files Browse the repository at this point in the history
Closes #1.
  • Loading branch information
nqv committed Oct 21, 2016
1 parent 68d3e89 commit 703dfdf
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 69 deletions.
22 changes: 14 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ Melon is a partial port of [Dropwizard](http://dropwizard.io/) in Go.
Besides of builtin Go packages, it utilizes a number of [libraries](https://github.com/goburrow/melon/blob/master/THIRDPARTY.md)
in order to build a server stack quickly, including:

* [goji](https://github.com/zenazn/goji): a robust web framework.
* [mux](https://github.com/gorilla/mux): a popular HTTP multiplexer.
* [gol](https://github.com/goburrow/gol): a simple hierarchical logging API.
* [metrics](https://github.com/codahale/metrics): a minimalist instrumentation library.
* [validator](https://github.com/goburrow/validator): extensible value validations.
* [validator](https://github.com/goburrow/validator): an extensible value validator.

Features supported:

Expand All @@ -29,6 +29,11 @@ Features supported:
## Examples
See [example](https://github.com/goburrow/melon/tree/master/example)

- [Hello World](example/helloworld/helloworld.go)
- [Restful](example/restful/restful.go)
- [HTML Template](example/template/template.go)
- [Basic Authentication](example/basicauth/basicauth.go)

```
INFO [2015-02-04T12:00:01.289+10:00] melon/server: starting
______
Expand All @@ -41,14 +46,15 @@ INFO [2015-02-04T12:00:01.289+10:00] melon/server: starting
\/_____/
INFO [2015-02-04T12:00:01.289+10:00] melon/assets: registering AssetsBundle for path /static/
DEBUG [2015-02-04T12:00:01.289+10:00] melon/server: resources = [*rest.XMLProvider,*main.usersResource,*main.userResource]
DEBUG [2015-02-04T12:00:01.289+10:00] melon/server: resources = [*views.JSONProvider,*views.XMLProvider,*views.Resource,*views.Resource,*views.Resource,*views.Resource,*views.Resource]
INFO [2015-02-04T12:00:01.289+10:00] melon/server: endpoints =
GET /users (*main.usersResource)
POST /users (*main.usersResource)
GET /user/:name (*main.userResource)
POST /user/:name (*main.userResource)
DELETE /user/:name (*main.userResource)
GET /static/* (http.HandlerFunc)
GET /users (*views.httpHandler)
POST /users (*views.httpHandler)
GET /user/{name} (*views.httpHandler)
PUT /user/{name} (*views.httpHandler)
DELETE /user/{name} (*views.httpHandler)
INFO [2015-02-04T12:00:01.290+10:00] melon/admin: tasks =
Expand Down
12 changes: 5 additions & 7 deletions THIRDPARTY.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
# Adopt
- https://github.com/codahale/metrics
- https://github.com/goburrow/gol
- https://github.com/zenazn/goji

# Trial
- https://github.com/ghodss/yaml
- https://github.com/goburrow/validator
- https://github.com/goburrow/health
- https://github.com/goburrow/dynamic
- https://github.com/goburrow/gol
- https://github.com/goburrow/health
- https://github.com/goburrow/validator
- https://github.com/gorilla/mux
- https://github.com/zanazn/goji/graceful
2 changes: 1 addition & 1 deletion auth/basic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestBasicAuthenticator(t *testing.T) {

rt := router.New()
rt.AddFilter(f)
rt.Handle("GET", "/", handler)
rt.Handle("GET", "/", http.HandlerFunc(handler))

srv := httptest.NewServer(rt)
defer srv.Close()
Expand Down
8 changes: 4 additions & 4 deletions core/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package core
import (
"bytes"
"fmt"
"net/http"
)

// Server is a managed HTTP server handling incoming connections to both application and admin.
Expand All @@ -14,9 +15,8 @@ type Server interface {

// Router allows users to register a http.Handler.
type Router interface {
// Handle registers the handler for the given pattern.
// An implementation of ServerHandler must at least support http.Handler.
Handle(method, pattern string, handler interface{})
// Handle registers the HTTP handler for the given pattern.
Handle(method, pattern string, handler http.Handler)
// PathPrefix returns prefix path of this handler.
PathPrefix() string
// Endpoints returns registered HTTP endpoints.
Expand Down Expand Up @@ -80,7 +80,7 @@ func (env *ServerEnvironment) logResources() {
var buf bytes.Buffer
for i, component := range env.components {
if i > 0 {
fmt.Fprintf(&buf, ",")
buf.WriteByte(',')
}
fmt.Fprintf(&buf, "%T", component)
}
Expand Down
5 changes: 3 additions & 2 deletions example/restful/restful.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/goburrow/melon"
"github.com/goburrow/melon/core"
"github.com/goburrow/melon/debug"
"github.com/goburrow/melon/server/router"
"github.com/goburrow/melon/views"
)

Expand Down Expand Up @@ -48,7 +49,7 @@ func (s *resource) createUser(w http.ResponseWriter, r *http.Request) {
}

func (s *resource) getUser(w http.ResponseWriter, r *http.Request) {
params := views.Params(r)
params := router.PathParams(r)

s.mu.RLock()
user, ok := s.users[params["name"]]
Expand Down Expand Up @@ -87,7 +88,7 @@ func run(conf interface{}, env *core.Environment) error {
env.Server.Register(
views.NewResource("POST", "/user", http.HandlerFunc(res.createUser),
views.WithTimerMetric("UsersCreate")),
views.NewResource("GET", "/user/:name", http.HandlerFunc(res.getUser)),
views.NewResource("GET", "/user/{name}", http.HandlerFunc(res.getUser)),
views.NewResource("GET", "/user", views.HandlerFunc(res.listUsers)),
)
return nil
Expand Down
53 changes: 20 additions & 33 deletions server/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import (
"strings"

"github.com/goburrow/melon/server/filter"
"github.com/zenazn/goji/web"
"github.com/gorilla/mux"
)

// Router handles HTTP requests.
// It implements core.Router
type Router struct {
// serverMux is the HTTP request router.
serveMux *web.Mux
serveMux *mux.Router
// filterChain is the builder for HTTP filters.
filterChain *filter.Chain

Expand All @@ -27,12 +27,12 @@ type Router struct {

// New creates a new Router.
func New(options ...Option) *Router {
mux := web.New()
serveMux := mux.NewRouter()
chain := filter.NewChain()
chain.Add(mux)
chain.Add(serveMux)

r := &Router{
serveMux: mux,
serveMux: serveMux,
filterChain: chain,
}
for _, opt := range options {
Expand All @@ -42,35 +42,17 @@ func New(options ...Option) *Router {
}

// Handle registers the handler for the given pattern.
func (h *Router) Handle(method, pattern string, handler interface{}) {
var f func(web.PatternType, web.HandlerType)

switch method {
case "GET":
f = h.serveMux.Get
case "HEAD":
f = h.serveMux.Head
case "POST":
f = h.serveMux.Post
case "PUT":
f = h.serveMux.Put
case "DELETE":
f = h.serveMux.Delete
case "TRACE":
f = h.serveMux.Trace
case "OPTIONS":
f = h.serveMux.Options
case "CONNECT":
f = h.serveMux.Connect
case "PATCH":
f = h.serveMux.Patch
case "*":
f = h.serveMux.Handle
default:
panic("server: unsupported method " + method)
func (h *Router) Handle(method, pattern string, handler http.Handler) {
r := h.serveMux.NewRoute()
r.Handler(handler)
if method != "" && method != "*" {
r.Methods(method)
}
if strings.HasSuffix(pattern, "*") {
r.PathPrefix(pattern[:len(pattern)-1])
} else {
r.Path(pattern)
}
f(pattern, handler)

// log endpoint
endpoint := fmt.Sprintf("%-7s %s%s (%T)", method, h.pathPrefix, pattern, handler)
h.endpoints = append(h.endpoints, endpoint)
Expand Down Expand Up @@ -122,3 +104,8 @@ func WithPathPrefix(prefix string) Option {
r.pathPrefix = prefix
}
}

// PathParams returns path parameters from the path of the request.
func PathParams(r *http.Request) map[string]string {
return mux.Vars(r)
}
15 changes: 1 addition & 14 deletions views/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (

"github.com/codahale/metrics"
"github.com/goburrow/melon/core"
"github.com/zenazn/goji/web"
)

// Resource is a view resource.
Expand Down Expand Up @@ -159,7 +158,7 @@ type httpHandler struct {
}

// TODO: migrate to github.com/goji/goji when it supports Go 1.7.
func (h *httpHandler) ServeHTTPC(c web.C, w http.ResponseWriter, r *http.Request) {
func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if h.metricRequests != "" {
h.metricRequests.Add()
}
Expand All @@ -173,7 +172,6 @@ func (h *httpHandler) ServeHTTPC(c web.C, w http.ResponseWriter, r *http.Request
handler: h,
readers: requestReaders,
writers: responseWriters,
params: c.URLParams,
contentType: contentType,
}
ctx := newContext(r.Context(), handlerCtx)
Expand Down Expand Up @@ -240,7 +238,6 @@ type handlerContext struct {
handler *httpHandler
readers []requestReader
writers []responseWriter
params map[string]string

// contentType is expected response content type
contentType string
Expand Down Expand Up @@ -335,16 +332,6 @@ func Error(w http.ResponseWriter, r *http.Request, err error) {
ctx.handler.errorMapper.MapError(w, r, err)
}

// Params returns path parameters from request.
func Params(r *http.Request) map[string]string {
ctx := fromContext(r.Context())
if ctx == nil {
logger.Errorf("no handler in request context: %v", r.Context())
return nil
}
return ctx.params
}

// Entity reads and validates entity v from request r.
func Entity(r *http.Request, v interface{}) error {
ctx := fromContext(r.Context())
Expand Down

0 comments on commit 703dfdf

Please sign in to comment.