Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly import a package from sub-directory in Golang?

Tags:

I am pretty new to Golang and trying to make a simple REST api app work.

Initially, everything was all fine since I had all code in the same directory under the main package.

But, now I am at a stage where I need to start refactoring code into sub-directories and packages. Unfortunately, I have not been able to compile the app successfully.

My GOPATH is set to: ~/.workspace The current app is at: ~/.workspace/src/gitlab.com/myapp/api-auth

This is how my current code organization is:

enter image description here

Here is my main.go

package main

import (
    "net/http"
    "os"
    "strings"

    "github.com/gorilla/context"
    "github.com/justinas/alice"
    "gopkg.in/mgo.v2"

    "gitlab.com/myapp/api-auth/middlewares"
)

func main() {
    privateKey := []byte(strings.Replace(os.Getenv("JWT_KEY"), "\\n", "\n", -1))

    conn, err := mgo.Dial(os.Getenv("MONGO_CONN"))

    if err != nil {
        panic(err)
    }

    defer conn.Close()
    conn.SetMode(mgo.Monotonic, true)

    ctx := appContext{
        conn.DB(os.Getenv("MONGO_DB")),
        privateKey,
    }

    err = ctx.db.C("users").EnsureIndex(mgo.Index{
        Key:        []string{"username"},
        Unique:     true,
        Background: true,
        Sparse:     false,
    })

    if err != nil {
        panic(err)
    }

    commonHandlers := alice.New(LoggingHandler, context.ClearHandler, RecoveryHandler, AcceptHandler, ContentTypeHandler)

    router := NewRouter()
    router.Post("/users", commonHandlers.Append(BodyParserHandler(UserResource{})).ThenFunc(ctx.userCreationHandler))
    router.Post("/sessions", commonHandlers.Append(BodyParserHandler(UserResource{})).ThenFunc(ctx.sessionCreationHandler))

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

type appContext struct {
    db         *mgo.Database
    privateKey []byte
}

Here is one of the middleware accept.go (Rest of the middleware are constructed similarly)

package middlewares

import "net/http"

// AcceptHandler ensures proper accept headers in requests
func AcceptHandler(next http.Handler) http.Handler {
    fn := func(w http.ResponseWriter, r *http.Request) {
        if r.Header.Get("Accept") != "application/vnd.api+json" {
            writeError(w, errNotAcceptable)
            return
        }

        next.ServeHTTP(w, r)
    }

    return http.HandlerFunc(fn)
}

This is the error I get when I run go build from root of my app.

# gitlab.com/utiliti.es/api-auth
./main.go:11: imported and not used: "gitlab.com/myapp/api-auth/middlewares"
./main.go:42: undefined: LoggingHandler
./main.go:42: undefined: RecoveryHandler
./main.go:42: undefined: AcceptHandler
./main.go:42: undefined: ContentTypeHandler
./main.go:45: undefined: BodyParserHandler
./main.go:46: undefined: BodyParserHandler
like image 336
Moon Avatar asked Feb 06 '16 17:02

Moon


People also ask

How do I import a package into Golang?

Create a file father.go inside the father folder. The file inside the father folder should start with the line package father as it belongs to the father package. The init function can be used to perform initialization works and can also be used to confirm the correctness of the program before the execution begins.

Which one is the correct way to import multiple packages libraries in Golang?

Both single and multiple packages can be imported one by one using the import keyword.

How can you tell Go to import a package from a different location?

Go first searches for package directory inside GOROOT/src directory and if it doesn't find the package, then it looks for GOPATH/src . Since, fmt package is part of Go's standard library which is located in GOROOT/src , it is imported from there.

How to import local files in Golang?

How To Import Local Files In Golang In 4 Easy Steps Step 1: Initialize a new module in your project. The first step is to initialize a new module in your Go project. ... Step 2: Create a Go package in your project. The next step is to create a new Go package in your project. Will follow a... Step ...

What is a package in Golang?

A package is essentially a container of source code for some specific purpose. For example, the io package contains the code for the input-output system, while the fmt package handles the formatting of string and logging to console. To use a package we must import one. Go throws error when we import package but don’t use it.

What is a directory in Golang?

In Golang, a directory is known as a package. Every file inside that directory is automatically assigned to that directory aka a Go package. The root of a project is always known as the main package.

How do I import a local Go Package?

To import a local Go package you must first identify the module name and then point to the directory where the Go package lives.


1 Answers

The Go Programming Language Specification

Qualified identifiers

A qualified identifier is an identifier qualified with a package name prefix. Both the package name and the identifier must not be blank.

QualifiedIdent = PackageName "." identifier .

A qualified identifier accesses an identifier in a different package, which must be imported. The identifier must be exported and declared in the package block of that package.

math.Sin  // denotes the Sin function in package math

Import declarations

An import declaration states that the source file containing the declaration depends on functionality of the imported package (§Program initialization and execution) and enables access to exported identifiers of that package. The import names an identifier (PackageName) to be used for access and an ImportPath that specifies the package to be imported.

    ImportDecl       = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
    ImportSpec       = [ "." | PackageName ] ImportPath .
    ImportPath       = string_lit .

The PackageName is used in qualified identifiers to access exported identifiers of the package within the importing source file. It is declared in the file block. If the PackageName is omitted, it defaults to the identifier specified in the package clause of the imported package. 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.

The interpretation of the ImportPath is implementation-dependent but it is typically a substring of the full file name of the compiled package and may be relative to a repository of installed packages.

Implementation restriction: A compiler may restrict ImportPaths to non-empty strings using only characters belonging to Unicode's L, M, N, P, and S general categories (the Graphic characters without spaces) and may also exclude the characters !"#$%&'()*,:;<=>?[]^`{|} and the Unicode replacement character U+FFFD.

Assume we have compiled a package containing the package clause package math, which exports function Sin, and installed the compiled package in the file identified by "lib/math". This table illustrates how Sin is accessed in files that import the package after the various types of import declaration.

    Import declaration          Local name of Sin

    import   "lib/math"         math.Sin
    import m "lib/math"         m.Sin
    import . "lib/math"         Sin

An import declaration declares a dependency relation between the importing and imported package. It is illegal for a package to import itself, directly or indirectly, or to directly import a package without referring to any of its exported identifiers. To import a package solely for its side-effects (initialization), use the blank identifier as explicit package name:

    import _ "lib/math"

The error

./main.go:11: imported and not used: "gitlab.com/myapp/api-auth/middlewares"

says that you have no uses of package middlewares in package main, which is true.

The error

./main.go:42: undefined: AcceptHandler

says that you haven't defined AcceptHandler in package main, which is true.

"A qualified identifier is an identifier qualified with a package name prefix. A qualified identifier accesses an identifier in a different package, which must be imported."

For example, in package main, use the qualified identifier middlewares.AcceptHandler, which is a use of import "gitlab.com/myapp/api-auth/middlewares".

like image 145
peterSO Avatar answered Oct 21 '22 15:10

peterSO