How do I serve static files and RESTful endpoints?

1,562 views
Skip to first unread message

Dean Schulze

unread,
Nov 12, 2013, 7:30:08 PM11/12/13
to goril...@googlegroups.com
This code will serve my static files, but it gives a 404 error when I send a GET to the rest URL:

func main() {

r := mux.NewRouter()
    r.HandleFunc("/rest/user/", GetUserHandler).Methods("GET")
    http.Handle("/rest/", r)
    log.Fatal(http.ListenAndServe(":9000", http.FileServer(http.Dir("./"))))
}


The REST url works if I use nil as the Handler.

How do I serve static files as well as restful endpoints with gorilla/mux ?

Thanks.

Kamil Kisiel

unread,
Nov 12, 2013, 7:47:33 PM11/12/13
to goril...@googlegroups.com
You need to pass the router as the handler argument to http.ListenAndServe, instead of http.FileServer. You probably want to add the http.FileServer to the router with r.Handle.

Dean Schulze

unread,
Nov 12, 2013, 8:05:44 PM11/12/13
to goril...@googlegroups.com
That sort of works.  It serves up my index.html file, but it doesn't work with AngularJS.  All of the angular scripts do nothing.

When I use the simple file server without gorilla/mux the angular stuff works properly.

Kamil Kisiel

unread,
Nov 12, 2013, 8:42:08 PM11/12/13
to goril...@googlegroups.com
Can you paste the complete code for your HTTP setup? There's lots of subtle details that can go wrong, so it's hard to say what the problem is without seeing it all.

Dean Schulze

unread,
Nov 12, 2013, 8:59:57 PM11/12/13
to goril...@googlegroups.com
package main

import (
"encoding/json"
"fmt"
"log"
"net/http"
)


func main() {

r := mux.NewRouter()
    r.HandleFunc("/rest/user/", GetUserHandler).Methods("GET")
    r.Handle("/", http.FileServer(http.Dir("./")))
    // http.Handle("/rest/", r)
    // http.Handle("/", http.FileServer(http.Dir("./")))

    log.Fatal(http.ListenAndServe(":9000", r))
}



type User struct {
Email string
FirstName string
}

func GetUserHandler(w http.ResponseWriter, req *http.Request) {

user := User{ Email : "m...@me.com", FirstName: "Me"}

fmt.Println("GetUserHandler(): user: " + user.Email)
b, err := json.Marshal(user)
if err != nil {
fmt.Println(err)
w.WriteHeader(400)
} else {
w.Write(b)
}

  return 

Dean Schulze

unread,
Nov 12, 2013, 9:04:04 PM11/12/13
to goril...@googlegroups.com
I posted the code in another post.

This sometimes will work for a while, but then all of the angular calls fail.  It serves the index.html file without processing any of the angular directives.

If I just run a simple web server like this:

    log.Fatal(http.ListenAndServe(":9000", http.FileServer(http.Dir("./"))))

the angular directives always get handled properly.  I lose my REST functionality, though.

Kamil Kisiel

unread,
Nov 12, 2013, 9:41:12 PM11/12/13
to goril...@googlegroups.com
Unlike the default http router, you need to use PathPrefix with the gorilla mux:

Something like:

    r := mux.NewRouter()
    r.HandlerFunc("/rest/user/", GetUserHandler).Methods("GET")
    r.PathPrefix("/").Handler(http.FileServer(http.Dir("./")))
    log.Fatal(http.ListenAndServe(":9000", r))

Dean Schulze

unread,
Nov 12, 2013, 10:40:11 PM11/12/13
to goril...@googlegroups.com
That seems to have solved it.  Is that documented somewhere?  The web site docs don't tell you the things you need to know like this?

Thanks for all of your help.

Kamil Kisiel

unread,
Nov 13, 2013, 2:19:46 AM11/13/13
to goril...@googlegroups.com
PathPrefix is mentioned in the documentation, but I agree it's not entirely clear. I'll file an issue to better document the key differences between gorilla/mux and the default http router in the standard library.

Dean Schulze

unread,
Nov 13, 2013, 8:59:29 AM11/13/13
to goril...@googlegroups.com
All the docs on the web site say is:

"PathPrefix adds a matcher for the URL path prefix"

I would have no idea from that statement that I need to use it in the way you indicated.  I can't find anything in the golang docs about PathPrefix.
Reply all
Reply to author
Forward
0 new messages