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.
Related
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
}
I have a question about export a module in a package with typing in Golang.
Example, I'd like to export UserCtrl in package controllers, and package api can use UserCtrl when import package controllers.
Also I want to export UserCtrl with typing, that means in api, I can call named methods, example UserCtrl.findOne(), or UserCtrl.findAll(), not use map[string]interface{}.
So I've created new type UserCtrlType as struct in Golang
package controllers
import (
"github.com/gin-gonic/gin"
)
// UserCtrlType : Type controller for User
type UserCtrlType struct {
FindAll gin.HandlerFunc
FindOneByID gin.HandlerFunc
FindOneByUsername gin.HandlerFunc
}
// UserCtrl : Controller for User
var UserCtrl = UserCtrlType{
findAll,
findOneByID,
findOneByUsername,
}
func findAll(ctx *gin.Context) {
}
func findOneByID(ctx *gin.Context) {
}
func findOneByUsername(ctx *gin.Context) {
}
And in package api, I import controller and use:
package api
import (
Controllers "github.com/huynhsamha/gin-go-app/controllers"
"github.com/gin-gonic/gin"
)
var userCtrl = Controllers.UserCtrl
func setUpUserRoutes(router *gin.RouterGroup) {
router.GET("/", userCtrl.FindAll)
router.GET("/n/:username", userCtrl.FindOneByUsername)
router.GET("/d/:id", userCtrl.FindOneByID)
}
I'm working with Gin, therefore the struct UserCtrlType is repeated many times with type gin.HandlerFunc.
Is there any other way to resolve my problem, which can export UserCtrl (typed) and reduce repeating type gin.HandlerFunc declarations.
When I'm working on Node.JS, I found it is very simple to export modules. Can we simplify this issue in Golang?
Typically in Go you wouldn't create a structure just to wrap a bunch of function declarations like this; you'd just directly export the functions.
package controllers
import "github.com/gin-gonic/gin"
func FindAll(ctx *gin.Context) { ... }
router.GET("/", controllers.FindAll)
If you really want to have a struct that contains them as variable function references, there is syntax to not repeat the type:
type UserCtrlType struct {
FindAll, FindOneByID, FindOneByUsername gin.HandlerFunc
}
In general in Go you will probably find this is the least of your repeated code (if err != nil { return err } appears a lot). "With typing" isn't a special concept in Go; you can never refer to an object as a map if it isn't one (without going through the reflect package, which should be a special case).
I've found an answer for my problem. I think because of my limited knowledge about Golang, I didn't think of a simpler way for my problem before.
This is my answer for my problem:
package controllers
import "github.com/gin-gonic/gin"
// UserCtrl : Controller for User
type UserCtrl struct{}
// FindAll :
func (ctrl UserCtrl) FindAll(ctx *gin.Context) {
}
// FindOneByID :
func (ctrl UserCtrl) FindOneByID(ctx *gin.Context) {
}
// FindOneByUsername :
func (ctrl UserCtrl) FindOneByUsername(ctx *gin.Context) {
}
And in package api
package api
import (
Controllers "github.com/huynhsamha/gin-go-app/controllers"
"github.com/gin-gonic/gin"
)
var userCtrl = Controllers.UserCtrl{}
func setUpUserRoutes(router *gin.RouterGroup) {
router.GET("/", userCtrl.FindAll)
router.GET("/n/:username", userCtrl.FindOneByUsername)
router.GET("/d/:id", userCtrl.FindOneByID)
}
I will close this question. Thanks for your attentions.
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.
main_test.go
package main_test
import (
"log"
"os"
"testing"
"."
)
func TestMain(m *testing.M) {
a = main.App{}
a.Init(
os.Getenv("TEST_DB_USERNAME"),
os.Getenv("TEST_DB_PASSWORD"),
os.Getenv("TEST_DB_NAME"))
ensureTableExists()
code := m.Run()
clearTable()
os.Exit(code)
}
app.go
package main
import (
"database/sql"
"fmt"
"log"
"github.com/gorilla/mux"
_ "github.com/lib/pq"
)
type App struct {
Router *mux.Router
DB *sql.DB
}
func (a *App) Init(user, password, dbname string) {
connection := fmt.Sprintf("user=%s password=%s dbname=%s", user, password, dbname)
var err error
a.DB, err = sql.Open("postgres", connection)
if err != nil {
log.Fatal(err)
}
a.Router = mux.NewRouter()
}
func (a *App) Run(addr string) { }
main.go
package main
import "os"
func main() {
a := App{}
a.Init(
os.Getenv("APP_DB_USERNAME"),
os.Getenv("APP_DB_PASSWORD"),
os.Getenv("APP_DB_NAME"))
a.Run(":8080")
}
Hey everyone, I am brand new to Golang and working with some tutorials. In the tutorial, they are using the import statement "." which is throwing an error for me. The exact error is "Non-canonical import-path." I tried using a relative path and full path to access the main file in my project but when I use anything other than "." the var a.main.App throws an error saying that main is an unresolved type. My $GOPATH is set to c:/users/me/go/src my project lives in the src folder. I am not entirely sure what is wrong my code at the moment. If it is something glaringly obvious I apologize.
Here is what I am trying to import. This lives in a file called app.go which is called through main.go
type App struct {
Router *mux.Router
DB *sql.DB
}
You don't need to import main for using struct App. You simply change the package of main_test to main then you can able to use that struct, like below i simply passed the main_test file.
package main
import (
"os"
"testing"
)
func TestMain(m *testing.M) {
a := App{}
a.Init(
os.Getenv("TEST_DB_USERNAME"),
os.Getenv("TEST_DB_PASSWORD"),
os.Getenv("TEST_DB_NAME"))
ensureTableExists()
code := m.Run()
clearTable()
os.Exit(code)
}
Here what i get from execute the test:
Success: Tests passed.
Example:
package "main"
import "fmt"
func main() {
fmt.Println("hey there")
}
Could be written:
package "main"
import blah "fmt"
func main() {
blah.Println("hey there")
}
But is there anyway to import fmt to achieve:
package "main"
import "fmt" // ???
func main() {
Println("hey there")
}
In C# by contrast, you can do this by using a static import (e.g., using static System.Console). Is this possible in Go?
Use the . (explicit period) import. The specification says:
If an explicit period (.) appears instead of a name, all the package's exported identifiers declared in that package's package block will be declared in the importing source file's file block and must be accessed without a qualifier.
Example:
package main
import (
. "fmt"
)
func main() {
Println("Hello, playground")
}
The use of the explicit period is discouraged in the Go community. The dot import makes programs more difficult to read because it's unclear if a name is a package-level identifier in the current package or in an imported package.
Another option is to declare a package-level variable with a reference to the function. Use a type alias to reference types.
package main
import (
"fmt"
)
var Println = fmt.Println
type ScanState = fmt.ScanState // type alias
func main() {
Println("Hello, playground")
}