Alec
Alec

Reputation: 4482

Pass arguments into HandlerFunc

I am trying to use the svgo package to plot points on an svg file and display that using the web browser. From looking at the net/http documetation, I don't know how I could pass arguments into my svgWeb function.

The example below compiles and displays a triangle and a line in my web-browser, but what I would really like to do is plot xpts and ypts using the Polyline method. How can I pass the appropriate arguments or restructure this example to accomplish that task?

package main

import (
    "github.com/ajstarks/svgo"
    "log"
    "net/http"
)

func svgWeb(w http.ResponseWriter, req *http.Request) {
    w.Header().Set("Content-Type", "image/svg+xml")

    xpts := []int{1, 200, 5}
    ypts := []int{200, 400, 300}
    s := svg.New(w)
    s.Start(500, 500)
    s.Line(5, 10, 400, 400, "stroke:black")
    s.Polyline(xpts, ypts, "stroke:black")
    s.End()
}

//// Main Program function
//////////////////////////////

func main() {

    xpts := []int{}
    ypts := []int{}

    for i := 0; i < 100; i++ {
        xpts = append(xpts, i)
        xpts = append(ypts, i+5)
    }

    http.Handle("/economy", http.HandlerFunc(svgWeb))
    err := http.ListenAndServe(":2003", nil)
    if err != nil {
        log.Fatal("ListenAndServe:", err)
    }
}

Upvotes: 1

Views: 773

Answers (2)

jdi
jdi

Reputation: 92637

If your arguments are meant to be supplied by the client, then they should be passed to your handler via the http.Request.

But if what you are trying to do is to drive your svgWeb handler by points that are not supplied by the client request, but rather by some other functions in your application generating these values internally, then one way would be to structure your handler into a struct and use member attributes.

The struct may look like this:

type SvgManager struct {
    Xpts, Ypts []int
}

func (m *SvgManager) SvgWeb(w http.ResponseWriter, req *http.Request) {
    w.Header().Set("Content-Type", "image/svg+xml")

    s := svg.New(w)
    s.Start(500, 500)
    s.Line(5, 10, 400, 400, "stroke:black")
    s.Polyline(m.Xpts, m.Ypts, "stroke:black")
    s.End()
}

Then in your main:

manager := new(SvgManager)

for i := 0; i < 100; i++ {
    manager.Xpts = append(manager.Xpts, i)
    manager.Ypts = append(manager.Ypts, i+5)
}

// I only did this assignment to make the SO display shorter in width.
// Could have put it directly in the http.Handle()
handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 
    manager.SvgWeb(w, req) 
})
http.Handle("/economy", handler)

Now you have an SvgManager instance that could contain other handlers as well, and can be updated to affect the output of their handlers.

Satisfying the Handler interface

As mentioned by @Atom in the comments, you could completely avoid the closure and the wrapper by simply renaming your method to ServeHTTP. This would satisfy the Handler interface

func (m *SvgManager) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    ...

manager := new(SvgManager)
http.Handle("/economy", manager)

Upvotes: 2

newacct
newacct

Reputation: 122519

You should define your function inside main as an anonymous function. This way, it can refer to the local variables xpts and ypts (the function will be a closure).

Upvotes: 1

Related Questions