-
-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
new: method handlers made easy - example and test included. Internals…
…: small helpers for http testing using the native library
- Loading branch information
Showing
13 changed files
with
255 additions
and
88 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"net/http" | ||
|
||
"github.com/kataras/muxie" | ||
) | ||
|
||
func main() { | ||
mux := muxie.NewMux() | ||
mux.PathCorrection = true | ||
|
||
mux.HandleFunc("/users", listUsersWithoutMuxieMethods) | ||
|
||
mux.Handle("/user/:id", muxie.Methods(). | ||
HandleFunc(http.MethodGet, getUser). | ||
HandleFunc(http.MethodPost, saveUser). | ||
HandleFunc(http.MethodDelete, deleteUser)) | ||
|
||
log.Println("Server started at http://localhost:8080\nGET: http://localhost:8080/users\nGET, POST, DELETE: http://localhost:8080/user/:id") | ||
log.Fatal(http.ListenAndServe(":8080", mux)) | ||
} | ||
|
||
// The `muxie.Methods()` is just a helper for this common matching. | ||
// | ||
// However, you definitely own your route handlers, | ||
// therefore you can easly make these checks manually | ||
// by matching the `r.Method`. | ||
func listUsersWithoutMuxieMethods(w http.ResponseWriter, r *http.Request) { | ||
if r.Method != http.MethodGet { | ||
w.Header().Set("Allow", http.MethodGet) | ||
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) | ||
return | ||
} | ||
|
||
fmt.Fprintf(w, "GET: List all users\n") | ||
} | ||
|
||
func getUser(w http.ResponseWriter, r *http.Request) { | ||
fmt.Fprintf(w, "GET: User details by user ID: %s\n", muxie.GetParam(w, "id")) | ||
} | ||
|
||
func saveUser(w http.ResponseWriter, r *http.Request) { | ||
fmt.Fprintf(w, "POST: save user with ID: %s\n", muxie.GetParam(w, "id")) | ||
} | ||
|
||
func deleteUser(w http.ResponseWriter, r *http.Request) { | ||
fmt.Fprintf(w, "DELETE: remove user with ID: %s\n", muxie.GetParam(w, "id")) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package muxie | ||
|
||
import ( | ||
"net/http" | ||
"strings" | ||
) | ||
|
||
// Methods returns a MethodHandler which caller can use | ||
// to register handler for specific HTTP Methods inside the `Mux#Handle/HandleFunc`. | ||
// Usage: | ||
// mux := muxie.NewMux() | ||
// mux.Handle("/user", muxie.Methods(). | ||
// Handle("GET", getUserHandler). | ||
// Handle("POST", saveUserHandler)) | ||
func Methods() *MethodHandler { | ||
// | ||
// Design notes, the latest one is selected: | ||
// | ||
// mux := muxie.NewMux() | ||
// | ||
// 1. mux.Handle("/user", muxie.ByMethod("GET", getHandler).And/AndFunc("POST", postHandlerFunc)) | ||
// | ||
// 2. mux.Handle("/user", muxie.ByMethods{ | ||
// "GET": getHandler, | ||
// "POST" http.HandlerFunc(postHandlerFunc), | ||
// }) <- the only downside of this is that | ||
// we lose the "Allow" header, which is not so important but it is RCF so we have to follow it. | ||
// | ||
// 3. mux.Handle("/user", muxie.Method("GET", getUserHandler).Method("POST", saveUserHandler)) | ||
// | ||
// 4. mux.Handle("/user", muxie.Methods(). | ||
// Handle("GET", getHandler). | ||
// HandleFunc("POST", postHandler)) | ||
// | ||
return &MethodHandler{handlers: make(map[string]http.Handler)} | ||
} | ||
|
||
// MethodHandler implements the `http.Handler` which can be used on `Mux#Handle/HandleFunc` | ||
// to declare handlers responsible for specific HTTP method(s). | ||
// | ||
// Look `Handle` and `HandleFunc`. | ||
type MethodHandler struct { | ||
// origin *Mux | ||
|
||
handlers map[string]http.Handler // method:handler | ||
|
||
methodsAllowedStr string | ||
} | ||
|
||
// Handle adds a handler to be responsible for a specific HTTP Method. | ||
// Returns this MethodHandler for further calls. | ||
func (m *MethodHandler) Handle(method string, handler http.Handler) *MethodHandler { | ||
method = strings.ToUpper(method) | ||
if m.methodsAllowedStr == "" { | ||
m.methodsAllowedStr = method | ||
} else { | ||
m.methodsAllowedStr += ", " + method | ||
} | ||
|
||
m.handlers[method] = handler | ||
|
||
return m | ||
} | ||
|
||
// HandleFunc adds a handler function to be responsible for a specific HTTP Method. | ||
// Returns this MethodHandler for further calls. | ||
func (m *MethodHandler) HandleFunc(method string, handlerFunc func(w http.ResponseWriter, r *http.Request)) *MethodHandler { | ||
m.Handle(method, http.HandlerFunc(handlerFunc)) | ||
return m | ||
} | ||
|
||
func (m *MethodHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||
if handler, ok := m.handlers[r.Method]; ok { | ||
handler.ServeHTTP(w, r) | ||
return | ||
} | ||
|
||
// RCF rfc2616 https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html | ||
// The response MUST include an Allow header containing a list of valid methods for the requested resource. | ||
// | ||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Allow#Examples | ||
w.Header().Set("Allow", m.methodsAllowedStr) | ||
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package muxie | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
) | ||
|
||
func TestMethodHandler(t *testing.T) { | ||
mux := NewMux() | ||
mux.PathCorrection = true | ||
|
||
mux.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) { | ||
if r.Method != http.MethodGet { | ||
w.Header().Set("Allow", http.MethodGet) | ||
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) | ||
return | ||
} | ||
|
||
fmt.Fprintf(w, "GET: List all users\n") | ||
}) | ||
|
||
mux.Handle("/user/:id", Methods(). | ||
HandleFunc(http.MethodGet, func(w http.ResponseWriter, r *http.Request) { | ||
fmt.Fprintf(w, "GET: User details by user ID: %s\n", GetParam(w, "id")) | ||
}). | ||
HandleFunc(http.MethodPost, func(w http.ResponseWriter, r *http.Request) { | ||
fmt.Fprintf(w, "POST: save user with ID: %s\n", GetParam(w, "id")) | ||
}). | ||
HandleFunc(http.MethodDelete, func(w http.ResponseWriter, r *http.Request) { | ||
fmt.Fprintf(w, "DELETE: remove user with ID: %s\n", GetParam(w, "id")) | ||
})) | ||
|
||
srv := httptest.NewServer(mux) | ||
defer srv.Close() | ||
|
||
expect(t, http.MethodGet, srv.URL+"/users").statusCode(http.StatusOK). | ||
bodyEq("GET: List all users\n") | ||
expect(t, http.MethodPost, srv.URL+"/users").statusCode(http.StatusMethodNotAllowed). | ||
bodyEq("Method Not Allowed\n").headerEq("Allow", "GET") | ||
|
||
expect(t, http.MethodGet, srv.URL+"/user/42").statusCode(http.StatusOK). | ||
bodyEq("GET: User details by user ID: 42\n") | ||
expect(t, http.MethodPost, srv.URL+"/user/42").statusCode(http.StatusOK). | ||
bodyEq("POST: save user with ID: 42\n") | ||
expect(t, http.MethodDelete, srv.URL+"/user/42").statusCode(http.StatusOK). | ||
bodyEq("DELETE: remove user with ID: 42\n") | ||
|
||
expect(t, http.MethodPut, srv.URL+"/user/42").statusCode(http.StatusMethodNotAllowed). | ||
bodyEq("Method Not Allowed\n").headerEq("Allow", "GET, POST, DELETE") | ||
} |
Oops, something went wrong.