my golang code arch is as bellow:
├── embeded.go
├── go.mod
├── json
│ └── file
└── main.go
and this is my embede.go code:
package main
import "embed"
//go:embed json/*
var templatesFS embed.FS
func TemplatesFS() embed.FS {
return templatesFS
}
now in my main.go I can't access file in json directory:
package main
import (
"fmt"
"log"
"os"
"text/template"
)
func main() {
tmpl := template.Must(
template.New("json/file").
ParseFS(TemplatesFS(), "json/file"))
if err := tmpl.Execute(os.Stdout, "config"); err != nil {
log.Fatal(err)
}
}
when I run above code I got error template: json/file: "json/file" is an incomplete or empty template
but I can access the file like this:
file, err := TemplatesFS().ReadFile("json/file")
so why I can't access it in templte.execute ?
How Can I Solve It ?
The template parser successfully read a template from the embedded file system.
The Execute method reports that the template tmpl is incomplete. The variable tmpl is set to the template created by the call to New. The template is incomplete because the application did not parse a template with the template's name, json/file.
ParseFS names templates using the file's base name. Fix by using using the file's base name in the call to New.
tmpl := template.Must(
template.New("file").ParseFS(TemplatesFS(), "json/file"))
Related
The code first.
package main
import (
"log"
"io/fs"
"embed"
"net/http"
"github.com/gorilla/mux"
)
//go:embed static/*
var static embed.FS
func main() {
router := mux.NewRouter()
fSys, err := fs.Sub(static, "static")
if err != nil {
panic(err)
}
staticServer := http.FileServer(http.FS(fSys))
router.Handle("/", staticServer)
if err := http.ListenAndServe(":3001", router); err != nil {
log.Fatalf("server could not run")
}
}
So I have this application and two others app2, app3 on ports 3002 and 3003 accordingly.
I need to proxy those apps using apache2 server.
Urls should be http:///app1 http:///app2 http:///app3
If I write:
ProxyPass /app1 http://localhost:3001/
ProxyPassReverse /app1 http://localhost:3001/
so index.html file loads fine but css style not loaded.
html and css files are on the same "virtual" disk. How can I fix css loading?
├── go.mod
├── go.sum
├── main.go
└── static
├── index.html
└── style.css
index.html looks like
<link rel="stylesheet" href="./style.css">
<h1>Hello</h1>
Error: mesage in browser console:
The resource from “http://localhost:3001/style.css” was blocked due to MIME type (“text/plain”) mismatch (X-Content-Type-Options: nosniff)
Go 1.16 is out and I want to use the new embed features. I can get it to work if everything is in the main package. But it's not clear how to handle accessing resources from subfolders/packages. Trying to do it with embed.FS support.
e.g. I have a main.go and also an HTTP handler in a handlers package/folder
If I put the handler in the main, it works. If I put it in the handlers package, it can't find the templates. I get:
handlers/indexHandler.go:11:12: pattern templates: no matching files found exit status 1
Similarly, I can get it to serve an image from the static folder if I serve it from /. But I can't serve both a handler from / and the static/images from /. If I put images on /static/ it can't find the images.
I think it has to do with relative paths. But I can't find the right combination through trial and error... Could it be too early to rely on these features?
Previously I was using go-rice and I did not have these problems. But I would like to use the std library as much as possible.
main.go:
package main
import (...)
//go:embed static
var static embed.FS
func main() {
fsRoot, _ := fs.Sub(static, "static")
fsStatic := http.FileServer(http.FS(fsRoot))
http.Handle("/", fsStatic)
http.HandleFunc("/index", Index)
http.ListenAndServe(":8080", nil)
}
handlers/indexHandler.go:
package handlers
import (...)
//go:embed templates
var templates embed.FS
// Index handler
func Index(w http.ResponseWriter, r *http.Request) {
tmpl := template.New("")
var err error
if tmpl, err = tmpl.ParseFS(templates, "simple.gohtml"); err != nil {
fmt.Println(err)
}
if err = tmpl.ExecuteTemplate(w, "simple", nil); err != nil {
log.Print(err)
}
}
Structure is as follows...
.
├── go.mod
├── go.sum
├── handlers
│ └── indexHandler.go
├── main.go
├── static
│ ├── css
│ │ └── layout.css
│ └── images
│ └── logo.png
└── templates
└── simple.gohtml
I finally figured it out...
You can keep the templates folder in the main folder and embed them from there. Then you need to inject the FS variable into the other handler package. It's always easy after you figure it out.
e.g.
package main
//go:embed templates/*
var templateFs embed.FS
func main() {
handlers.TemplateFs = templateFs
...
package handlers
var TemplateFs embed.FS
func handlerIndex() {
...
tmpl, err = tmpl.ParseFS(TemplateFs, "templates/layout.gohtml",...
...
Currently in Go 1.17 , embed is not supporting subfolders/packages, see https://github.com/golang/go/issues/41191#issuecomment-686616556
Go 1.16 added the new embed package. I would like to use this package to embed a directory and serve it over HTTP. Consider the following setup:
myproject/
|-- main.go
|-- static/
| |-- index.html
| |-- styles.css
| |-- scripts.js
package main
import (
"embed"
"log"
"net/http"
)
//go:embed static
var staticFS embed.FS
func main() {
http.Handle("/", http.FileServer(http.FS(staticFS)))
log.Fatal(http.ListenAndServe(":8080", nil))
}
With this setup, my expectation is that I can point my browser to localhost:8080 and have it load index.html. What I am observing instead, is that I need to point my browser to localhost:8080/static to have it load index.html.
How can an embedded filesystem be served from the root path of the URL?
When declaring a variable of type embed.FS, that variable represents a filesystem that already contains a root directory. All resources from the //go:embed directive are copied into this root directory of the filesystem. That means that the staticFS variable does not refer to the static folder that was being embedded directly, but to the root directory that contains the static folder. With that in mind, to achieve the desired result of being able to access the static folder from localhost:8080, Go's fs.Sub can be used to pass a filesystem to the server where the static folder is the root:
package main
import (
"embed"
"io/fs"
"log"
"net/http"
)
//go:embed static
var embeddedFS embed.FS
func main() {
serverRoot, err := fs.Sub(embeddedFS, "static")
if err != nil {
log.Fatal(err)
}
http.Handle("/", http.FileServer(http.FS(serverRoot)))
log.Fatal(http.ListenAndServe(":8080", nil))
}
Alternatively to fs.Sub you can declare embedding inside the static directory.
package static
//go:embed *.html *.css *.js
var FS embed.FS
And then import it.
package main
import (
"embed"
"log"
"net/http"
"import/path/to/static"
)
func main() {
http.Handle("/", http.FileServer(http.FS(static.FS)))
log.Fatal(http.ListenAndServe(":8080", nil))
}
The downside of adding embedding into static directory is that *.go file may be also added as embedded unless strict file masks are used (e.g. //go:embed *.html *js instead of //go:embed *).
Edit: Removed additionally proposed http.StripPrefix because it does not actually help with issue.
I keep getting the following error and I have been trying out some of the other suggestions in other Stack Overflow threads.
./main.go:15:13: undefined: checkEnv
Folder Structure:
├── README.md
├── main.go
└── validate
└── args.go
$GOPATH
/Users/myusername/go
main.go
package main
import (
"fmt"
"log"
"os"
"projectName/validate"
"gopkg.in/urfave/cli.v1"
)
func main() {
app := cli.NewApp()
app.Name = "thirsty"
app.Action = func(c *cli.Context) error {
result := checkEnv(c.Args().Get(0))
fmt.Println(result)
return nil
}
err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}
validate/args.go
package validate
import "strings"
func checkEnv(environment string) bool {
env := strings.ToLower(environment)
return env != "qa" && env != "dev"
}
My project is in the src directory of my $GOPATH. If this is not the proper way to do code splitting, is there a generally used convention to follow?
Any feedback appreciated.
There are two problems here.
The checkEnv method is not exported [in validate/args.go]. ie it is usable only inside the same package and not other packages To export just capitalize the first letter of the method CheckEnv. Now CheckEnv can be used from other packages
While calling a method from other package, the syntax should be packagename.ExportedMethod(params...). so in your code [in main.go] it should be result := validate.CheckEnv(c.Args().Get(0))
I have a small go lang project which in the main.go file has a few handlers that refer to session related methods in a session.go file. Both have package main at the top of the file. The functions in the session.go file all begin with an uppercase letter (i.e. they are public/exported methods). Yet when I run the main.go file, it says the methods located in session.go and called from main.go are undefined. Why is that, how to fix it.
I am running the project like go run main.go
main.go
func logout(w http.ResponseWriter, r *http.Request) {
ClearSession(w, r)
....
}
session.go
func ClearSession(w http.ResponseWriter, r *http.Request) {
}
As #ptd said, the command needs all the files named.
I prefer use another package:
/ main.go
|_session/
|_session.go
|_validations.go
|_errors.go
So, you can organize your code and simplify your named files.
e.g.:
file: main.go
package main
import "session"
func main() {
var validator session.Validator
var session session.Session
...
if session.IsValid() == false {
// return session.InvalidSession
fmt.Printf("ERROR: %v", session.InvalidSession)
}
}
file: errors.go
import "errors"
var (
InvalidSession = errors.New("[Your error message]"
)
Then you can use:
go run main.go