Original post

package main

import (
        "fmt"
        "net/http"
)

type HelloHandler struct{}

func (h *HelloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        //some matching to GET/POST/PATCH.. method
}
func (h *HelloHandler) Get(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello!")
}

func main() {
        hello := HelloHandler{}
        world := WorldHandler{}
        server := http.Server{
                Addr: "127.0.0.1:8080",
        }
        http.Handle("/hello", &hello)
        http.Handle("/world", &world)
        server.ListenAndServe()
}

this is my current way to make api endpoint.
But in this approach ServeHTTP methods gets repeated despite doing same action for its handler.

Can some one suggest better way of attaching Handler so I can minimize ServeHTTP duplication?
Thanks in advance

Hi!

You’re using http.Handle function which accepts the interface you’re talking about. You can just change it to HandeFunc and use custom functions

package main

import (
        "fmt"
        "net/http"
)

type HelloHandler struct{}

func (h *HelloHandler) Handle1(w http.ResponseWriter, r *http.Request) {
        //some matching to GET/POST/PATCH.. method
}
func (h *HelloHandler) Handle2(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello!")
}

func main() {
        hello := &HelloHandler{}
        server := http.Server{
                Addr: "127.0.0.1:8080",
        }
        http.HandleFunc("/hello", hello.Handle1)
        http.HandleFunc("/world", hello.Handle1)
        server.ListenAndServe()
}

But in that way I will have redirection to various http method in Handle function which will get repeated for all handler function (here Handle2, Handle1).
Want i want from my repo design is :

  • Handlers attached to a uri have http method handller function implementation internally
  • Less repeatitive code for same functionality.

I’m not sure if understand your problem correctly.
For every action on API, you’ll have a separate HandleUserCreate/HandleUserBan function but you’ll have a shared struct between them.
You cannot eliminate calling http.Handle* functions.

I want to create project structure similar to flask-restful.

where adding a handler looks like

api.add_resource(Foo, '/Foo', '/Foo/<string:id>')

where Foo looks like:

class Foo(Resource):
    def get(self):
        pass
    def post(self):
        pass

Why don’t you just use mux? You can easily register routes mapping URL paths to handlers. If an incoming request URL matches one of the paths, the corresponding handler is called passing (http.ResponseWriter, *http.Request) as parameters. Paths can also have variables. They are defined using the format {name} or {name:pattern} . If a regular expression pattern is not defined, the matched variable will be anything until the next slash. Here is a quick example:

package main

import (
        "fmt"
        "log"
        "net/http"

        "github.com/gorilla/mux"
)

func main() {
        router := mux.NewRouter().StrictSlash(true)
        router.HandleFunc("/", indexHandler)
        router.HandleFunc("/books", booksIndexHandler)
        router.HandleFunc("/books/{id}", booksShowHandler)
        router.HandleFunc("/category", categoryIndexHandler)
        router.HandleFunc("/category/{id:[a-zA-Z0-9]+}", categoryShowHandler)

        log.Fatal(http.ListenAndServe(":8080", router))
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "Welcome!")
}

func booksIndexHandler(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "Books Index!")
}

func booksShowHandler(w http.ResponseWriter, r *http.Request) {
        vars := mux.Vars(r)
        bookId := vars["id"]
        fmt.Fprintln(w, "Book show:", bookId)
}

func categoryIndexHandler(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "Category Index!")
}

func categoryShowHandler(w http.ResponseWriter, r *http.Request) {
        vars := mux.Vars(r)
        categoryId := vars["id"]
        fmt.Fprintln(w, "Category show:", categoryId)
}

Thanks for advice.
The code i am proposing can also be used with. Here i am struggling with code organisation for my handler.

It looks you want to build a REST app with some kind of automation/magic. In Go, it’s promoted to do things more explicit, that’s why you won’t find almost nothing that does that.

Using mux is a good idea but I’m not sure if it solves your problem the way you want. You can achieve what you want using reflect package, take a look at the signature of the function and register proper handlers.

In comparison to python, Go is a compiled/statically typed language and this is the reason why it’s harder but – possible. Let me know if you found answer to your question or have problems with implementation.

thanks for suggestion it led me to realise this isn’t web related problem.

the actual problem i face is

package main

import "fmt"

type A struct{}

func (a *A) hello() string {
        return "Hello A"
}

func (a *A) print() {
        fmt.Println(a.hello())
}

type B struct {
        A
}

func (b *B) hello() string{
        return "Hello B"
}

func main() {
        a := A{}
        a.print()
        
        b := B{}
        b.print()
}

How do I call hello method on b using print method?

Go doesn’t work this way. We don’t have inherence but composition. It means that in B you can find A but B doesn’t inherence from A anything. The print statement refers to print function which is in A and Go tries to use this one.

Can You suggest some alternate way to replicate this behavior or Do I have make print explicitly in B?

I’m wondering why you’re trying to do what you’re doing. The Go way is something like this one

package main

import "fmt"

type helloer interface {
        hello() string
}

type A struct {
}

func (a A) hello() string {
        return "Hello A"
}

type B struct {
}

func (b B) hello() string {
        return "Hello B"
}

type printer struct {
        h helloer
}

func (a *printer) print() {
        fmt.Println(a.h.hello())
}

func main() {
        a := printer{A{}}
        a.print()

        b := printer{B{}}
        b.print()
}

thank you very much. This will be very helpful. thanks a lot.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.