0

I'm designing a router API and I'd like to be able to lookup a path by its function. Something like:

createUser := func(w http.ResponseWriter, r *http.Request) {
    // create a user
}
createPost := func(w http.ResponseWriter, r *http.Request) {
    // create a post
}
router.Post("/users", createUser)
router.Post("/posts", createPost)
fmt.Println(router.Lookup(createPost))

Here's a playground link: https://play.golang.org/p/ec6U0jJUbfx

This is surprisingly hard to do because you can't test for equality on a function or stick it as a key in a map. Is this even possible?

Are there any other workarounds I'm not thinking of? A reflect solution would be just fine.

Matt
  • 22,224
  • 25
  • 80
  • 116
  • 1
    This sounds like an XY problem. What are you trying to solve? – Marc Aug 16 '20 at 15:35
  • My problem is that I need to lookup a string with a function. I asked this question to know if this is possible. It not being possible would be a surprise to me. I'm hoping someone is clever :-) – Matt Aug 16 '20 at 15:43
  • There are many ways of doing this. For example, don't use a plain function, use a small struct that has the handler method on it and a path. But without knowing the problem you're trying to solve, we can't help. – Marc Aug 16 '20 at 15:43
  • 1
    You could use something other than functions for the lookup, e.g. https://play.golang.org/p/Yp0edoLtxgJ – mkopriva Aug 16 '20 at 16:10
  • You want to achieve this using the standard `http.ServeMux` router? Or a custom one? – colm.anseo Aug 17 '20 at 02:05
  • 1
    does this fit the requirement? https://stackoverflow.com/questions/29684609/how-to-check-if-an-object-has-a-particular-method – whitespace Aug 17 '20 at 07:05

1 Answers1

0

You can create a server struct with a ServerHTTP method that handles all the request. When there is a request you can look up for an specific method by the path and function Here is an example:

type Server struct {
    routes []route
}

func (s *Server) handlerServer(db mydb.IDB, ctx context.Context) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        ctx := ServerContext{w, r, db, ctx}
        for i := 0; i < len(s.routes); i++ {
            currentRoute := s.routes[i]
            if isValidMethod(currentRoute, r) {
                err := currentRoute.h(&ctx)
                if err != nil {
                    log.Fatal(err)
                }
            }
        }
    }
}

I hope this is helpful

German
  • 557
  • 3
  • 5