How to access another file in GO - go

I'm trying to access a controller from main.go but I'm getting the following error:
./main.go:34:28: cannot refer to unexported name controllers.getUserDetails
./main.go:34:28: undefined: controllers.getUserDetails
here's a snippet of my main.go, I've removed some extra code
package main
import (
"net/http"
"os"
"log"
"github.com/urfave/negroni"
"github.com/gorilla/mux"
"github.com/joho/godotenv"
"Go-Social/controllers"
)
func main() {
router := mux.NewRouter()
UserRouter := router.PathPrefix("/api/user").Subrouter()
UserRouter.HandleFunc("", controllers.getUserDetails).Methods("GET")
env := os.Getenv("GO_ENV")
if "" == env {
env = "Development"
}
// appending middlewares
server := negroni.Classic()
// router handler with negroni
server.UseHandler(router)
// starting server
server.Run(":" + os.Getenv(env + "_PORT"))
}
my controller.go file
package controllers
import (
"net/http"
"fmt"
)
func getUserDetails(w http.ResponseWriter, r *http.Request) {
fmt.Println("here")
message := "Hello World"
w.Write([]byte(message))
}
Please Help I'm new to Go. Thanks in advance.

to use a function from another package, you need to export it (GetUserDetails)
as said here
An identifier may be exported to permit access to it from another package
func GetUserDetails(w http.ResponseWriter, r *http.Request) {
fmt.Println("here")
message := "Hello World"
w.Write([]byte(message))
}

Since the getUserDetails function is in another package it cannot be accessed. Only functions starting with capital letter can be accessed. That's how encapsulation works in Go.
func GetUserDetails(w http.ResponseWriter, r *http.Request) {
fmt.Println("here")
message := "Hello World"
w.Write([]byte(message))
}
So in your main:
UserRouter.HandleFunc("", controllers.GetUserDetails).Methods("GET")
Language like Java, enCAPSulation in class-based OOP is achieved through private and public class variables / methods.
In Go, encapsulation is achieved on a package level.
In other words, in Go, starting with capital letter for any package object (type, variable or function) will allow you to access it from another package.

Related

Import func from subfolder

I'm trying to import a func from a subfolder.
I have a main package
package main
import (
...
)
func handleRequests() {
http.HandleFunc("/health", health)
...
}
func main() {
handleRequests()
}
And then I have a folder called health in which I have a file called health.go.
package health
import (
...
)
func health(writer http.ResponseWriter, _ *http.Request) {
...
}
What shall my import look like and how do I call my health func?
At this point, your import statement doesn't mean anything, because it health package has no exported function or variable. You should check out the scoping in Go from the language spec. From here
Maybe consider checking out go modules, since it is now the suggested way to handle any go program that has more than a file.
The quick answer is,
your health.go
package health
import (
...
)
func Handler(writer http.ResponseWriter, _ *http.Request) {
...
}
your main.go
package main
import (
github.com/blablabla/yourproject/health
)
func handleRequests() {
http.HandleFunc("/health", health.Handler)
...
}
func main() {
handleRequests()
}
You must name function starting from uppercase symbol ("Health" instead of "health").
For example: health (your case) is private declaration, and Health would be public.
The same principle with types and variables naming.

How in Golang use struct in other package file?

I am new in Golang and need some help.
As you can see in the code below I am tring to create REST API in Golang. I use mux (Gorilla Mux) and pq (PostgreSQL driver) as third party libraries. Don't want to use ORM.
Inside application.go file I have InitializeRoutes function with a list of all aviable routes. GetFactors function process one of these routes. I am tring to define GetFactors function logic in other file called factors.go. Inside factors.go file I want to use Application struct which was defined in application.go. How to make it correctly? Right now as you can see they are in different packages. For thats why factors.go file don't see Application struct.
Project structure:
main.go
application.go
controllers
factors.go
main.go:
package main
func main() {
application := Application{}
application.Initialization()
application.Run("localhost:8000")
}
application.go:
package main
import (
"database/sql"
"github.com/gorilla/mux"
"log"
"net/http"
"rest-api/configurations"
)
type Application struct {
Router *mux.Router
Database *sql.DB
}
func (application *Application) Initialization() {
var err error
application.Database, err = configurations.DatabaseConnection()
if err != nil {
log.Fatal(err)
}
application.Router = mux.NewRouter()
application.Router.StrictSlash(true)
application.InitializeRoutes()
}
func (application *Application) Run(address string) {
log.Fatal(http.ListenAndServe(address, application.Router))
}
func (application *Application) InitializeRoutes() {
application.Router.HandleFunc("/api/factors", application.GetFactors).Methods("GET")
// other code
}
controllers/factors.go:
package controllers
import (
"net/http"
)
func (application *Application) GetFactors(rw http.ResponseWriter, request *http.Request) {
// code
}
Well, finally I decided to redesign the project structure.
main.go
routes
routes.go
controllers
factors.go
models
factors.go
main.go:
import (
"your_project_name/routes"
)
func main() {
// code
router := mux.NewRouter()
routes.Use(router)
// code
}
routes/routes.go:
package routes
import (
"github.com/gorilla/mux"
"your_application_name/controllers"
)
func Use(router *mux.Router) {
router.HandleFunc("/api/factors", controllers.GetFactors).Methods("GET")
}
controllers/factors.go:
package controllers
var GetFactors = func(res http.ResponseWriter, req *http.Request) {
// code
}

Golang - User of package without selector

Please, I searched this a lot and after not been able to find, I am writing and not that I didn't try to search all over first. Couldn't get the right answer. I even tried to check Revel's function and couldn't get the answer from there as well.
When I run this program I get this error for line
./test.go:11: use of package http without selector
This error points at the line below where I have written
*http
inside the struct
Confusing part is that with test and dot I even get auto complete with VIM. So I don't know why is the error. Is it that it has to be somewhat like
*(net/http)
or something like that ?
package main
import (
"fmt"
"net/http"
)
type HandleHTTP struct {
*http
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Path is %s", r.URL.Path[1:])
}
func main() {
test := HandleHTTP{}
test.http.HandleFunc("/", handler)
test.http.ListenAndServe(":8080", nil)
}
If you want to have two or more instances serving from different ports you need to spin up two, or more, server. Would something like this, perhaps, work for you?
package main
import (
"fmt"
"net/http"
)
type HandleHTTP struct {
http *http.Server
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Path is %s", r.URL.Path[1:])
}
func main() {
mux1 := http.NewServeMux()
mux1.HandleFunc("/", handler)
test1 := HandleHTTP{http:&http.Server{Addr:":8081", Handler:mux1}}
mux2 := http.NewServeMux()
mux2.HandleFunc("/", handler)
test2 := HandleHTTP{http:&http.Server{Addr:":8082", Handler:mux2}}
// run the first one in a goroutine so that the second one is executed
go test1.http.ListenAndServe()
test2.http.ListenAndServe()
}

Pass object to struct in other package

I have a main function, where I initiate a variable, a client. For example:
func main() {
myClient := my.MustNewClient("localhost")
}
Now I want to pass this client to another package, but for some reason I cannot figure out how to do this. My package looks like this:
package rest
import (
"net/http"
"github.com/Sirupsen/logrus"
)
type AssetHandler struct {
mc my.Client
}
func (f AssetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
logrus.Info("bla")
// here I want to use the client
mc.SomeFunctionIntheClient()
}
So my question is, how do I use the client (out of main) in my package?
In the package rest you have to add a constructor function like:
func NewAssetHandler(mc my.Client) AssetHandler {
return AssetHandler{mc}
}
Then you have to instantiate the handler from your main function.
Otherwise you would have to create a separate package where you store global variables. The main package itself can not be used for this because it can't be accessed from somewhere else.

Golang routing in different controllers

I am new to Golang and I am trying to learn how to do efficient routing. For instance I have a controller folder/directory and inside that controller I want to have different Func/methods with their own unique routes but I do not know how to do that. I have downloaded the github.com/gorilla/mux package and my application looks like this
The main section of my application looks like this and it is working perfectly: tim.go
package main
import(
"net/http"
"fmt"
"github.com/gorilla/mux"
)
func HomeHandler(writer http.ResponseWriter, req *http.Request) {
writer.WriteHeader(200)
fmt.Fprintf(writer, "Home!!!\n")
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/home", HomeHandler).Name("bob")
http.Handle("/",r)
http.ListenAndServe(":8000", nil)
}
The issue is how can I get the func/methods inside my Controller file(s) to also display on the browser. My sample.go file does not show in the browser when I go to that URL
package Controllers
import(
"net/http"
"fmt"
"github.com/gorilla/mux"
)
func HomeHandler(writer http.ResponseWriter, req *http.Request) {
writer.WriteHeader(200)
fmt.Fprintf(writer, "New Home")
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/new", HomeHandler).Name("bob")
http.Handle("/",r)
http.ListenAndServe(":8000/new", nil)
}
When I go into my browser and type localhost:8000/new it says file not found. Any suggestions would be great
I suppose you run the tim.go file to start the server.
If so, the problem is you don't have the route you're calling /new, you should have an answer with /home.
To do it, you should move your HomeHandler function to Controllers package and then import this package in your main ad instantiate the routes you need.
Hope this helps.

Resources