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"
)
Related
I am wanting to move to the echo framework for my API due to an openapi package we wish to use (opai-codegen) However our current API is built via gorilla mux. Due to the size of the current codebase we need to run them both side by side.
So I am trying to work out how do I get gorilla mux and the echo framework to work together via the same http.Server
The gorilla mux API is created via:
router := mux.NewRouter().StrictSlash(true)
router.Handle("/..",...)
//etc ...
And then my echo API is created via:
echo := echo.New()
echo.Get("/..", ...)
// etc ...
However I can't get them to run with the same http.ListenAndServe
Love to know if there is any to make these two work together?
Thanks
This is what i can think of, Although you will need to move middle-wares to echo
package main
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
func main() {
// Echo instance
e := echo.New()
// Middleware
e.Use(middleware.Logger())
e.Use(middleware.Recover())
r := mux.NewRouter()
r.HandleFunc("/mux/", Hello).Methods("GET", "PUT").Name("mux")
r.HandleFunc("/muxp/", HelloP).Methods("POST").Name("muxp")
gorillaRouteNames := map[string]string{
"mux": "/mux/",
"muxp": "/muxp/",
}
// Routes
e.GET("/", hello)
// ro := e.Any("/mux", ehandler)
for name, url := range gorillaRouteNames {
route := r.GetRoute(name)
methods, _ := route.GetMethods()
e.Match(methods, url, echo.WrapHandler(route.GetHandler()))
fmt.Println(route.GetName())
}
// Start server
e.Logger.Fatal(e.Start(":1323"))
}
// Handler
func hello(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
}
func Hello(w http.ResponseWriter, req *http.Request) {
fmt.Fprintln(w, "Hello world!")
}
func HelloP(w http.ResponseWriter, req *http.Request) {
fmt.Fprintln(w, "Hello world By Post!")
}
Please, I searched this a lot and after not been able to find, I am writing and not that I didn't try to search all over first. Couldn't get the right answer. I even tried to check Revel's function and couldn't get the answer from there as well.
When I run this program I get this error for line
./test.go:11: use of package http without selector
This error points at the line below where I have written
*http
inside the struct
Confusing part is that with test and dot I even get auto complete with VIM. So I don't know why is the error. Is it that it has to be somewhat like
*(net/http)
or something like that ?
package main
import (
"fmt"
"net/http"
)
type HandleHTTP struct {
*http
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Path is %s", r.URL.Path[1:])
}
func main() {
test := HandleHTTP{}
test.http.HandleFunc("/", handler)
test.http.ListenAndServe(":8080", nil)
}
If you want to have two or more instances serving from different ports you need to spin up two, or more, server. Would something like this, perhaps, work for you?
package main
import (
"fmt"
"net/http"
)
type HandleHTTP struct {
http *http.Server
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Path is %s", r.URL.Path[1:])
}
func main() {
mux1 := http.NewServeMux()
mux1.HandleFunc("/", handler)
test1 := HandleHTTP{http:&http.Server{Addr:":8081", Handler:mux1}}
mux2 := http.NewServeMux()
mux2.HandleFunc("/", handler)
test2 := HandleHTTP{http:&http.Server{Addr:":8082", Handler:mux2}}
// run the first one in a goroutine so that the second one is executed
go test1.http.ListenAndServe()
test2.http.ListenAndServe()
}
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 do I integrate just like http.FileServer with martini?
` package main
import (
"github.com/go-martini/martini"
"net/http"
)
func main() {
m := martini.Classic()
//http.Handle("/", http.FileServer(http.Dir("."))) //It doesn't work!
m.Run()
}`
I believe the FileServer isn't used directly in Martini: see issues/20:
Unfortunately The fileserver middleware throws a 404 if there is no match, which means we will need to roll our own
Hence PR 26 and commit a945713 in static.go that you can see in static_test.go
m := New()
r := NewRouter()
m.Use(Static(currentRoot))
m.Action(r.Handle)
I have a relatively big web application written in Go that uses Gorilla's mux for routing. I recently realised that my web application is quite slow and I would like to profile the web application.
After reading about it, it seems that net/http/pprof is what I need. But I can't make it run with mux; even in the case of the most trivial web application.
Does anyone knows how to make that work?
Here is an example of a trivial code that does not work (i.e. nothing is served at /debug).
package main
import (
"fmt"
"github.com/gorilla/mux"
"math"
"net/http"
)
import _ "net/http/pprof"
func SayHello(w http.ResponseWriter, r *http.Request) {
for i := 0; i < 1000000; i++ {
math.Pow(36, 89)
}
fmt.Fprint(w, "Hello!")
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/hello", SayHello)
http.ListenAndServe(":6060", r)
}
My preferred method for this is to just let net/http/pprof register itself to http.DefaultServeMux, and then pass all requests starting with /debug/pprof/ along:
package main
import (
"net/http"
_ "net/http/pprof"
"github.com/gorilla/mux"
)
func main() {
router := mux.NewRouter()
router.PathPrefix("/debug/pprof/").Handler(http.DefaultServeMux)
if err := http.ListenAndServe(":6060", router); err != nil {
panic(err)
}
}
I find that this approach is a lot more stable than one that depends on the implementation of a hidden initialization method, and also guarantees that you didn't miss anything.
user983716 - Thanks for your question and solution!
I was not able to use the links from the web index (http://[my-server]/debug/pprof), until I added a few lines to your solution, like so:
...
func AttachProfiler(router *mux.Router) {
router.HandleFunc("/debug/pprof/", pprof.Index)
router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
router.HandleFunc("/debug/pprof/profile", pprof.Profile)
router.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
// Manually add support for paths linked to by index page at /debug/pprof/
router.Handle("/debug/pprof/goroutine", pprof.Handler("goroutine"))
router.Handle("/debug/pprof/heap", pprof.Handler("heap"))
router.Handle("/debug/pprof/threadcreate", pprof.Handler("threadcreate"))
router.Handle("/debug/pprof/block", pprof.Handler("block"))
}
...
If anyone has the same problem, I hope this helps!
Sorry for that question. The answer is in the init() function of pprof. One just need to add 4 functions from pprof to the mux router. Here is the fixed code from above.
package main
import (
"fmt"
"github.com/gorilla/mux"
"math"
"net/http"
)
import "net/http/pprof"
func AttachProfiler(router *mux.Router) {
router.HandleFunc("/debug/pprof/", pprof.Index)
router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
router.HandleFunc("/debug/pprof/profile", pprof.Profile)
router.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
}
func SayHello(w http.ResponseWriter, r *http.Request) {
for i := 0; i < 1000000; i++ {
math.Pow(36, 89)
}
fmt.Fprint(w, "Hello!")
}
func main() {
r := mux.NewRouter()
AttachProfiler(r)
r.HandleFunc("/hello", SayHello)
http.ListenAndServe(":6060", r)
}
Previous examples not really work on my side.
To use pprof in an existing golang project with gorrila/mux, try to add :
...previous code
func main() {
r := mux.NewRouter()
r.HandleFunc("/hello", SayHello)
go func() {
log.Fatal(http.ListenAndServe(":6061", http.DefaultServeMux))
}()
http.ListenAndServe(":6060", r)
}
then go to http://localhost:6061/debug/pprof/
I did something else, I added another native http server on a different port and it just works out of the box
package main
import (
"fmt"
"log"
"net/http"
_ "net/http/pprof"
)
func main() {
go func() {
log.Println(http.ListenAndServe(":6060", nil))
}()
log.Fatalln(http.ListenAndServe(":8080", route.Handlers()))
}
Now the pprof endpoint is at :
http://localhost:6060/debug/pprof/ and the applcation is running on port :8080
Just so:
r := mux.NewRouter()
r.PathPrefix("/debug").Handler(http.DefaultServeMux)
Im using https://github.com/julienschmidt/httprouter but i just got this answer from google search.
That's what i did
router := httprouter.New()
router.Handler("GET", "/debug/pprof/profile", http.DefaultServeMux)
router.Handler("GET", "/debug/pprof/heap", http.DefaultServeMux)
I only need this two routes.
This answer is combine of #damien and #user983716 answers.
The following should work:
import (
"net/http"
_ "net/http/pprof"
)
myrouter.PathPrefix("/debug/pprof/").Handler(http.DefaultServeMux)