3

So I just started learning Go yesterday and I have been following a fairly simple tutorial on creating a restful api. I can run the tests and everything but when I try to run the app and have it listen on a part it gives me undefined: App.

I cannot seem to find the error in this as Initialize and run should be sufficient enough to start the server. The tutorial also has it exactly like this and I followed it carefully.

UPDATE:

As clarification I attempt to run the program with go run main.go and that's what prompts the error.

I also attempted to follow the advice of an answer and ran go run main.go app.go and I get undefined: getUsers and it points to the line where it says users, err := getUsers(a.DB, start, count). I have added them to my app.go code below.

main.go

package main

func main() {
    a := App{}

    a.Initialize("root", "password", "user")

    a.Run(":8080")
}

app.go

package main

import (
    "fmt"
    "log"
    "strconv"
    "encoding/json"
    "net/http"
    "github.com/gorilla/mux"
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
)

type App struct {
    Router *mux.Router
    DB     *sql.DB
}

func (a *App) Initialize(user, password, dbname string) {
    connectionString := fmt.Sprintf("%s:%s@/%s", user, password, dbname)

    var err error

    a.DB, err = sql.Open("mysql", connectionString)

    if err != nil {
        log.Fatal(err)
    }

    a.Router = mux.NewRouter()
    a.initializeRoutes()
}

func (a *App) initializeRoutes() {
    a.Router.HandleFunc("/users", a.getUsers).Methods("GET")
}

func (a *App) Run(addr string) {
    log.Fatal(http.ListenAndServe(addr, a.Router))
}

func (a *App) getUsers(w http.ResponseWriter, r *http.Request) {
    count, _ := strconv.Atoi(r.FormValue("count"))
    start, _ := strconv.Atoi(r.FormValue("start"))

    if count > 10 || count < 1 {
        count = 10
    }

    if start < 0 {
        start = 0
    }

    users, err := getUsers(a.DB, start, count)

    if err != nil {
        respondWithError(w, http.StatusInternalServerError, err.Error())

        return
    }

    respondWithJSON(w, http.StatusOK, users);
}
Mr.Smithyyy
  • 2,157
  • 12
  • 49
  • 95

3 Answers3

2

How do you run it? If with go run try to pass it all the files:

go run main.go app.go

Or even with asterisk to catch them all:

go run *.go

Another option: build application then run it:

go build -o app && ./app
Eugene Lisitsky
  • 12,113
  • 5
  • 38
  • 59
  • Yes sorry I'll edit my post to provide that information I do indeed run it with that command. I tried your solution and ran into some other problems I will update my question. – Mr.Smithyyy Nov 14 '17 at 02:50
  • Do you mean `getUsers` method of an `App` struct? If yes try call it as `a.getUsers` inside other methods. Or there is another go file(s) where it is defined? If so as them to `go run` too. Even with `*`. – Eugene Lisitsky Nov 14 '17 at 03:03
  • `getUsers` is defined in my app.go file so it should run with that. I tried using `go run *.go` and it gave me an error of `*.go: The filename, directory name, or volume label syntax is incorrect.` Sorry for the lack of knowledge on the topic. I come from a javascript background and I've been trying to read all of the guides I can on this but documentation becomes a blur after a while. – Mr.Smithyyy Nov 14 '17 at 03:18
  • Don’t worry. We are have started sometime ago :). Is it the whole file? I see only a method defined on structure but I do not see a standalone function with such parameters. – Eugene Lisitsky Nov 14 '17 at 03:23
  • Oh yeah sorry I'm getting a grip on structs. I have probably 4 more similar functions like that one (get, post, put ,delete) style and they all pretty much look the same with the same parameters so I guess all of the methods are on the struct. I can put them all in the question but I felt it would just clutter the code since they look idential at definition. – Mr.Smithyyy Nov 14 '17 at 03:32
  • If they present in the same folder and package just add their files to `go run` and run from that folder. About `*` - looks like shell issues. – Eugene Lisitsky Nov 14 '17 at 03:35
  • Do I still need to do that if the methods are in the `app.go` file? I figured that they would automatically included when the initialize and run methods were run in the `main.go` file. As for shell issues I don't know if it matter but I am running the commands in the powershell on Visual Studio Code. – Mr.Smithyyy Nov 14 '17 at 03:42
  • Method should be visible to compiler. Now it doesn’t see. Go run is designed to work with individual files. So you can pass all the files explicitly. At a moment do not waste time for a shell issues. – Eugene Lisitsky Nov 14 '17 at 03:48
  • Not sure about Linux but `go run *.go` will certainly not work on Windows. – Peter Gloor Nov 15 '17 at 09:34
0

Just to add to @Eugene Lisitsky's answer.

If *.go doesn't work for you for some reason you'll have to manually list all files on which your program depends.

That means that besides main.go and app.go you also need to list files that define the getUsers, respondWithError and respondWithJSON functions, and if the files in which you define these functions reference some other identifiers that are defined in yet other files you'll also need to include those and so on.

And as you can see this can get pretty annoying pretty quickly so it might be a good idea to put all of your app code, and all other code that's outside of the main.go file into separate packages, then have main.go import those packages, and with that you should be able to run your app with go run main.go.

mkopriva
  • 35,176
  • 4
  • 57
  • 71
0

I have this problem too. Maybe we follow the same tutorial. try this:

go build .  // create a file end with ".exe", my file name is "golang.exe"
./golang.exe

then it's ok!

Macro
  • 1
  • 1