Go MUX controller returns 404 - go

I must be missing something really obvious, but I've created a MUX routed controller and the server returns 404. Running the following:
package main
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/mux"
)
func main() {
router := mux.NewRouter()
router.HandleFunc("/hi", SayHi)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func SayHi(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hi")
}
Visit : http://localhost:8080/hi and I get a 404.
What am I doing wrong?

Just pass router variable as second parameter to http.ListenAndServe() instead of nil

Related

Blank page when using swaggo/http-swagger with julienschmidt/httprouter

I am making an api and used swaggo/swag to build a swagger interface. Previously, I used the net/http package, and everything was working fine.
I switched to julienschmidt/httprouter, but I don't manage to make the swagger interface work again. Here is my code
package main
import (
"fmt"
"log"
"net/http"
"github.com/julienschmidt/httprouter"
httpSwagger "github.com/swaggo/http-swagger"
)
func main() {
router := httprouter.New()
router.ServeFiles("/api/doc/static/*filepath", http.Dir("api/swagger/static"))
router.HandlerFunc(http.MethodGet, "/api/doc/index.html", swaggerHandler)
// router.HandlerFunc(http.MethodGet, "/api/doc", swaggerHandler)
fmt.Println("Server on port 8080")
log.Fatal(http.ListenAndServe(":8080", router))
}
func swaggerHandler(w http.ResponseWriter, r *http.Request) {
swaggerFileUrl := "http://localhost:8080/api/doc/static/swagger.json"
handler := httpSwagger.Handler(httpSwagger.URL(swaggerFileUrl))
handler.ServeHTTP(w, r)
}
I checked if swaggerFileUrl variable is correct, and I am able to access the json file with this url. The interface is a complete blank page titled "Swagger UI". Because the title is replaced, I am assuming, that something happened, but I don't know if the issue comes from httpSwagger or httprouter.
Edit: Issue is caused because javascript files loading the interface are not present. See this github issue
You can do it like this:
routes := httprouter.New()
routes.GET("/doc/:any", swaggerHandler)
func swaggerHandler(res http.ResponseWriter, req *http.Request, p httprouter.Params) {
httpSwagger.WrapHandler(res, req)
}
Do not forget import doc files
import (
_ "example.project/docs"
)

What configuration am I missing for httputil.NewSingleHostReverseProxy?

The code below produces the error further below. When I type "http://www.cnn.com/favicon.ico" straight into any browser it works without issue. I am guessing that I am missing some critical configuration for the reverse proxy. What is the minimum config needed for getting this to work?
package main
import (
"net/http"
"net/http/httputil"
"net/url"
"log"
)
func main(){
url, _ := url.Parse("http://www.cnn.com/favicon.ico")
proxy := httputil.NewSingleHostReverseProxy(url)
http.HandleFunc("/", proxy.ServeHTTP)
log.Fatal(http.ListenAndServe(":9090", nil))
}
Fastly error: unknown domain: localhost. Please check that this domain
has been added to a service.
Details: cache-lax8625-LAX
Happy 4th of July!
I made the following 2 changes to get it working:
Firstly, point the proxy at www.cnn.com instead of www.cnn.com/favicon.ico. Of course, now we must make our request to localhost:9090/favicon.ico.
Next, set the proxied request's Host field to the target host, not the host of the proxy which is localhost.
The code ends up looking like this:
package main
import (
"log"
"net/http"
"net/http/httputil"
"net/url"
)
type Director func(*http.Request)
func (f Director) Then(g Director) Director {
return func(req *http.Request) {
f(req)
g(req)
}
}
func hostDirector(host string) Director {
return func(req *http.Request) {
req.Host = host
}
}
func main() {
url, _ := url.Parse("http://www.cnn.com")
proxy := httputil.NewSingleHostReverseProxy(url)
d := proxy.Director
// sequence the default director with our host director
proxy.Director = Director(d).Then(hostDirector(url.Hostname()))
http.Handle("/", proxy)
log.Fatal(http.ListenAndServe(":9090", nil))
}

goji/httpauth - Cannot use with the standard Golang 'net/http' library

The code
package main
import (
"fmt"
"log"
"net/http"
"github.com/goji/httpauth"
)
func rootHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
data := "TEST"
w.Header().Set("Content-Length", fmt.Sprint(len(data)))
fmt.Fprint(w, string(data))
}
func main() {
r:=http.HandlerFunc(rootHandler)
http.HandleFunc("/", httpauth.SimpleBasicAuth("dave", "somepassword")(r))
log.Fatal(http.ListenAndServe(":8080", nil))
}
returns
:!go build test.go
# command-line-arguments
./test.go:23:71: cannot use httpauth.SimpleBasicAuth("dave", "somepassword")(r) (type http.Handler) as type func(http.ResponseWriter, *http.Request) in argument to http.HandleFunc
What am I doing wrong? I'm new to Go and don't understand why the example here is incomplete and doesn't include a YourHandler function.
I figured it out after much banging my head against the proverbial wall.
Use http.Handle, not http.HandleFunc! :)
So with the main function as
func main() {
r:=http.HandlerFunc(rootHandler)
http.Handle("/", httpauth.SimpleBasicAuth("dave", "somepassword")(r))
log.Fatal(http.ListenAndServe(":8080", nil))
}
You have a complete working example of httpauth with net/http!
This answer has a really great overview of the inner workings as well.

Golang routing in different controllers

I am new to Golang and I am trying to learn how to do efficient routing. For instance I have a controller folder/directory and inside that controller I want to have different Func/methods with their own unique routes but I do not know how to do that. I have downloaded the github.com/gorilla/mux package and my application looks like this
The main section of my application looks like this and it is working perfectly: tim.go
package main
import(
"net/http"
"fmt"
"github.com/gorilla/mux"
)
func HomeHandler(writer http.ResponseWriter, req *http.Request) {
writer.WriteHeader(200)
fmt.Fprintf(writer, "Home!!!\n")
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/home", HomeHandler).Name("bob")
http.Handle("/",r)
http.ListenAndServe(":8000", nil)
}
The issue is how can I get the func/methods inside my Controller file(s) to also display on the browser. My sample.go file does not show in the browser when I go to that URL
package Controllers
import(
"net/http"
"fmt"
"github.com/gorilla/mux"
)
func HomeHandler(writer http.ResponseWriter, req *http.Request) {
writer.WriteHeader(200)
fmt.Fprintf(writer, "New Home")
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/new", HomeHandler).Name("bob")
http.Handle("/",r)
http.ListenAndServe(":8000/new", nil)
}
When I go into my browser and type localhost:8000/new it says file not found. Any suggestions would be great
I suppose you run the tim.go file to start the server.
If so, the problem is you don't have the route you're calling /new, you should have an answer with /home.
To do it, you should move your HomeHandler function to Controllers package and then import this package in your main ad instantiate the routes you need.
Hope this helps.

how to organize gorilla mux routes?

i am using Gorilla Mux for writing a REST API and i am having trouble organizing my routes, currently all of my routes are defined in the main.go file like this
//main.go
package main
import (
"NovAPI/routes"
"fmt"
"github.com/gorilla/mux"
"net/http"
)
func main() {
router := mux.NewRouter().StrictSlash(true)
router.HandleFunc("/hello", func(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "Hello")
})
router.HandleFunc("/user", func(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "User")
})
router.HandleFunc("/route2", func(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "Route2")
})
router.HandleFunc("/route3", func(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "Route3")
})
// route declarations continue like this
http.ListenAndServe(":1128", router)
}
so what i want to do is take out and split this route declaration into multiple files, how would i go about doing that? thanks in advance.
You can modularize your routers independently into different packages, and mount them on the main router
Elaborating just a little on the following issue, you can come up with this approach, that makes it quite scalable (and easier to test, to some degree)
/api/router.go
package api
import (
"net/http"
"github.com/gorilla/mux"
)
func Router() *mux.Router {
router := mux.NewRouter()
router.HandleFunc("/", home)
return router
}
func home(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("hello from API"))
}
/main.go
package main
import (
"log"
"net/http"
"strings"
"github.com/...yourPath.../api"
"github.com/...yourPath.../user"
"github.com/gorilla/mux"
)
func main() {
router := mux.NewRouter()
router.HandleFunc("/", home)
mount(router, "/api", api.Router())
mount(router, "/user", user.Router())
log.Fatal(http.ListenAndServe(":8080", router))
}
func mount(r *mux.Router, path string, handler http.Handler) {
r.PathPrefix(path).Handler(
http.StripPrefix(
strings.TrimSuffix(path, "/"),
handler,
),
)
}
func home(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("Home"))
}
What about something like this ?
//main.go
package main
import (
"NovAPI/routes"
"fmt"
"github.com/gorilla/mux"
"net/http"
)
func main() {
router := mux.NewRouter().StrictSlash(true)
router.HandleFunc("/hello", HelloHandler)
router.HandleFunc("/user", UserHandler)
router.HandleFunc("/route2", Route2Handler)
router.HandleFunc("/route3", Route3Handler)
// route declarations continue like this
http.ListenAndServe(":1128", router)
}
func HelloHandler(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "Hello")
}
func UserHandler(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "User")
}
func Route2Handler(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "Route2")
}
func Route3Handler(res http.ResponseWriter, req *http.Request) {
fmt.Fprintln(res, "Route3")
}
That way you can put your handlers in other files, or even other packages.
If you endup with additionnal dependencies like a database, you can even avoid the need of the global var using a constructor trick:
//main.go
func main() {
db := sql.Open(…)
//...
router.HandleFunc("/hello", NewHelloHandler(db))
//...
}
func NewHelloHandler(db *sql.DB) func(http.ResponseWriter, *http.Request) {
return func(res http.ResponseWriter, req *http.Request) {
// db is in the local scope, and you can even inject it to test your
// handler
fmt.Fprintln(res, "Hello")
}
}
I like checking out other projects in github to grab ideas on how to do stuff, and for these cases I usually take a look first at the Docker repo. This is the way they do it:
For the system's routes, define all handlers in system_routes.go and then initialize those routes on a NewRouter function in system.go.
type systemRouter struct {
backend Backend
routes []router.Route
}
func NewRouter(b Backend) router.Router {
r := &systemRouter{
backend: b,
}
r.routes = []router.Route{
local.NewOptionsRoute("/", optionsHandler),
local.NewGetRoute("/_ping", pingHandler),
local.NewGetRoute("/events", r.getEvents),
local.NewGetRoute("/info", r.getInfo),
local.NewGetRoute("/version", r.getVersion),
local.NewPostRoute("/auth", r.postAuth),
}
return r
}
// Routes return all the API routes dedicated to the docker system.
func (s *systemRouter) Routes() []router.Route {
return s.routes
}
Notice that systemRouter implements the router.Router interface and the Routes function returns a []router.Route, and their handlers are defined as
func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error
instead of Go's standard http handler:
func(w http.ResponseWriter, r *http.Request)
So there's extra code of theirs to convert a Docker API Handler to a Go HTTP Handler at the makeHttpHandler function.
And finally, to add those routes to their mux router, on their server.go they implement several other functions to add middleware to their handlers.
If this is something that you think it's what you are looking for, then take your time to analyze the Docker code for their routes, and if you need me to elaborate more or if I missed anything, post a comment.
Since I am new to Go, I prefer a less verbose solution. In each module, we can create a Route function that expects a main route pointer and creates sub-routes to it. Our main.go file would be as follows
package main
import (
"net/http"
"github.com/user-name/repo-name/auth"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
auth.Router(r)
http.ListenAndServe(":8080", r)
}
then in auth module, we can create a route file
package auth
import "github.com/gorilla/mux"
func Router(r *mux.Router) {
routes := r.PathPrefix("/auth").Subrouter()
routes.HandleFunc("/register", Register)
}

Resources