On my Ubuntu 22.10 digitalocean server, I'm experimenting with Golang and Fiber and the html template engine. Loving it so far.
It all works, including the Mysql connection and sending email. Except for one thing.
I keep getting the error render: template index does not exist.
File system:
├── /gogo
├── main
├── main.go
├── go.mod
├── go.sum
├── /views
└── index.html
└── /public
└── plaatje.png
The code of my main.go:
package main
import (
"fmt"
"log"
fiber "github.com/gofiber/fiber/v2"
"github.com/gofiber/template/html"
)
func main() {
// Initialize standard Go html template engine
template_engine := html.New(
"./views",
".html",
)
// start fiber
app := fiber.New(fiber.Config{
Views: template_engine,
})
// add static folder
app.Static(
"/static", // mount address
"./public", // path to the file folder
)
// endpoint
app.Get("/", func(c *fiber.Ctx) error {
// Render index template
return c.Render("index", fiber.Map{
"Title": "It works",
"Plat": "almost",
})
})
log.Fatal(app.Listen(":9990"))
}
The index.html file:
<!DOCTYPE html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Unicode">
<title>{{.Title}}</title>
</head>
<body>
<h1>{{.Title}}</h1>
<p>{{.Plat}}</p>
<p><img src="./static/plaatje.png"></p>
</body>
</html>
When I run it locally on my Mac, it all works and the template is rendered as it should.
But on the Ubuntu server it all works except for the template, with the given error:
render: template index does not exist
I've tried changing ownership and permissions in Ubuntu: no results. However this is a bit of a blind spot for me, so this might still be the isue...
I've tried tinkering with the views path (./views, /views, views. etc): no results.
I've tried return c.Render("index.html", fiber.Map{: no results.
What am I missing?
The experiment with go run . gave a clue. When running it as a service, the mount point is not the dir where main is, but a path elsewhere on the server.
Changing...
template_engine := html.New(
"./views",
".html",
)
... with a relative path to an absolute path ...
template_engine := html.New(
"/home/username/go/views",
".html",
)
... solved the issue.
This issue is not mentioned in any source on this topic.
Related
Hello I am trying to setup a new serverless graphql project but the serverless.yml file doesn't find my handler, which is in src/graphql.ts
It throws an error like this:
Failure: Cannot find module '/Users/VIU/Projects/am/src/graphql'
The src is in the root directory and the path is correct, so I don't understand what is going on.
The serverless.yml looks like this:
graphql:
handler: src/graphql.graphqlHandler
events:
- http:
path: graphql
method: post
cors: true
- http:
path: graphql
method: get
cors: true
And the graphql handler file like this:
import { ApolloServer, gql } from "apollo-server-lambda"
// Construct a schema, using GraphQL schema language
const typeDefs = gql`
type Query {
hello: String
}
`;
// Provide resolver functions for your schema fields
const resolvers = {
Query: {
hello: () => 'Hello world!',
},
};
const server = new ApolloServer({ typeDefs, resolvers });
exports.graphqlHandler = server.createHandler();
I've also tried
module.exports.graphqlHandler = server.createHandler();
export const graphqlHandler = server.createHandler();
But none of that seems to work either.
Has someone any idea of what I am doing wrong? Thank You!
In order to run an AWS Lambda function with a Node.js runtime, you'll need to provide a .js file as its handler. Specifically, when using TypeScript and the Serverless framework, that means that the handler field must refer to the compiled file name, namely, ending with a .js extension.
One option for you to resolve this is to simply change the handler field to point to the compiled version of your file. For example, given the following structure:
├── am
│ ├── built
│ │ └── graphql.js
│ ├── package-lock.json
│ ├── package.json
│ └── src
│ └── graphql.ts
└── serverless.yaml
The correct handler field is:
graphql:
handler: built/graphql.graphqlHandler
However, another option which I believe is the preferred one (and possibly what you were originally aiming for) is to use the serverless-plugin-typescript plugin of the Serverless framework. That should reduce your efforts and allow you to use TypeScript almost seamlessly. There is actually an example provided by Serverless that is very similar to your need and I think you can find useful.
I wrote a structure like display in the tree below.
.
├── README.md
├── db
│ └── db.go
├── go.mod
├── go.sum
├── handler
│ ├── category.go
│ ├── handler.go
│ └── users.go
├── main.go
├── model
│ ├── category.go
│ ├── model.go
│ └── users.go
└── route
├── category.go // init() ❌ error to using package vars
├── route.go // init() writing package vars
└── users.go // init() ✅ no error to using package vars
All the files in the packages except the one with the same name (route/route.go, handler/handler.go,...) are generated automatically. For these files to extend the package variables, I use golang's func init(){} ex:
route/route.go
package route
import (
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
var (
// public routes
e *echo.Echo = echo.New()
// restricted routes
r *echo.Group = e.Group("/restricted")
)
func init() {
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
AllowOrigins: []string{"http://localhost:3000"},
AllowMethods: []string{echo.GET, echo.PUT, echo.POST, echo.DELETE, echo.OPTIONS},
AllowHeaders: []string{echo.HeaderAuthorization, echo.HeaderContentType},
}))
e.Use(middleware.Recover())
r.Use(middleware.JWT([]byte("secret")))
}
route/category.go
package route
import (
"github.com/username/project/handler"
)
func init() {
r.GET("/category", handler.ListCategory)
r.POST("/category/add", handler.CreateCategory)
r.GET("/category/:id", handler.ReadCategory)
r.PUT("/category/edit/:id", handler.UpdateCategory)
r.DELETE("/category/:id", handler.DeleteCategory)
}
route/user.go
package route
import (
"github.com/username/project/handler"
)
func init() {
r.GET("/users", handler.ListUsers)
r.POST("/users/add", handler.CreateUser)
r.PUT("/users/edit/:id", handler.UpdateUser)
r.DELETE("/users/:id", handler.DeleteUser)
e.POST("/auth", handler.Login)
e.POST("/lost", handler.Lost)
e.POST("/password", handler.Password)
}
As you already understood, the category.go init() starts before the router.go init(), which is described here: Go Package initialization.
After coding a pretty program that auto writes routes like route/category.go. I realize that to solve this problem, I will have to rename router/router.go to router/0router.go (it works) so that it is still at the top of the pillar, but it's not a good approach.
Have any suggestions for this tree and the use of golang ini() ?
Thank you
Use variable declaration expressions to avoid file name dependencies. The assignments execute before the init() functions that reference the variables.
var (
// public routes
e *echo.Echo = newPublic()
// restricted routes
r *echo.Group = newRestricted()
)
func newPublic() *echo.Echo {
e := echo.New()
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
AllowOrigins: []string{"http://localhost:3000"},
AllowMethods: []string{echo.GET, echo.PUT, echo.POST, echo.DELETE, echo.OPTIONS},
AllowHeaders: []string{echo.HeaderAuthorization, echo.HeaderContentType},
}))
e.Use(middleware.Recover())
}
func newRestricted() *echo.Group {
r := e.Group("/restricted")
r.Use(middleware.JWT([]byte("secret")))
return r
}
My problem
My apologies if the problem is trivial - I'm fairly new to golang, and want to understand the imports mechanism. I use OSX and simple go programs compile and work well.
I've generated a golang server using automatic code generator in the swagger editor. I've unzipped the code into some directory in /tmp/, and the resulting server contains the following main.go file:
package main
import (
// WARNING!
// Change this to a fully-qualified import path
// once you place this file into your project.
// For example,
//
// sw "github.com/myname/myrepo/go"
//
sw "./go"
"log"
"net/http"
)
func main() {
log.Printf("Server started")
router := sw.NewRouter()
log.Fatal(http.ListenAndServe(":8080", router))
}
As expected from the comments, go build main.go Fails with the following error:
main.go:11:2:
go/default.go:3:1: expected 'IDENT', found 'import'
Forensics
The directory tree of the project
/tmp/goserver/go-server-server
├── LICENSE
├── api
│ └── swagger.yaml
├── go
│ ├── README.md
│ ├── app.yaml
│ ├── default.go
│ ├── logger.go
│ └── routers.go
└── main.go
go/default.go
package
import (
"net/http"
)
type Default struct {
}
func QuestionimagePost(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
What have I tried
Read about go packages
Tried to understand the package / import relationship in some github projects
Moved the directory tree to $GOPATH/src, and changed the import to sw "sw/go-server-server/go", which still gives main.go:13:2:
go/default.go:3:1: expected 'IDENT', found 'import'
What should be the fully-qualified import path of the sw import, and what does it mean?
The following did the trick:
Adding a package name to all .go files in the go folder (I used blah)
eg. in go/routers.go
package blah
import (
"log"
"net/http"
"time"
)
func Logger(inner http.Handler, name string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
inner.ServeHTTP(w, r)
log.Printf(
"%s %s %s %s",
r.Method,
r.RequestURI,
name,
time.Since(start),
)
})
}
Do the same for go/logger.go and, in your case, default.go
Following an go/routers.go:7:2: cannot find package "github.com/gorilla/mux" error, go get 'github.com/gorilla/mux'
You need to export some path as the GOPATH, say $HOME/go.
export GOPATH=$HOME/go.
Then you can put your project in $GOPATH/src/go-server-server ($HOME/go/src/go-server-server) and your fully qualified path would be go-server-server/go if I am reading everything correctly.
I'm trying to use gulp-ruby-sass and/or gulp-sass but neither are working for me and think i've got it all set up correctly. I've looked at a bunch of other SO posts but nothing works for me as yet.
I've got another gulp task which is recursively copying an assets directory and index.html from src to dist and this works every time.
To test the sass setup is correct i run a vanilla sass compile and then run gulp; the sass changes work and render via the recursive copy. Here's the commands for that sass test:
$ sass ./sass/main.scss ./src/assets/css/main.css
$ gulp
Forgetting the vanilla sass test and back to the gulp sass issue here - in my gulpfile i'm running the gulp sass task before i run the recursive copy task, so if it worked then the sass changes should be applied and copied. At least that's what i thought.
Here's my dir structure showing relevant files:
├── src
│ ├── index.html
│ └── assets
│ ├── css
│ │ └── main.css
│ ├── js
│ │ └── app.js
│ └── img
│ └── etc.jpg
│
├── dist
│ └── index.html ( from ./src via recursive copy)
│ └── assets
│ └── (same as ./src/assets via recursive copy)
│
├── sass
│ ├── main.scss
│ ├── _partial1.scss
│ ├── _partial2.scss
│ └── etc ...
│
├── gulpfile.js
│
├── node_modules
│ └── etc ...
│
└── bower_components
└── etc ...
In gulpfile.js there are a couple of file mapping objects which work fine for the recursive copy of src/assets/. But for the sake of testing the gulp-ruby-sass task i'm hard-coding the sass/css paths to remove the possibility of the file mapping as an error.
For the record I'm running on OSX Maverics 10.9.5 and think i have the correct environment setup:
$ ruby -v
ruby 2.0.0p481 (2014-05-08 revision 45883) [universal.x86_64-darwin13]
$ sass -v
Sass 3.4.9 (Selective Steve)
Here's my gulpfile.js showing approaches that i've tried so far, with gulp-sass related task commented-out:
var gulp = require('gulp');
var watch = require('gulp-watch');
var gsass = require('gulp-ruby-sass');
// var gsass = require('gulp-sass');
var gutil = require('gulp-util');
// Base paths:
var basePaths = {
srcRoot: './src/',
distRoot: './dist/',
bowerRoot: './bower_components/'
};
// File paths:
var filePaths = {
sassRoot: basePaths.srcRoot + 'sass/',
assetsBuildRoot: basePaths.srcRoot + 'assets/',
jqMin: basePaths.bowerRoot + 'jquery/dist/jquery.min.js',
html: basePaths.srcRoot + 'index.html'
};
// With gulp-ruby-sass
gulp.task('compile-sass', function() {
gulp.src('./sass/main.scss')
.pipe(gsass({sourcemap: true, sourcemapPath: './sass/'}))
.on('error', function (err) { console.log(err.message); })
.pipe(gulp.dest('./src/assets/css'));
});
// With gulp-sass
// gulp.task('gsass', function () {
// gulp.src('./sass/*.scss')
// .pipe(gsass())
// .pipe(gulp.dest('./src/assets/css'));
// });
// Assets directory copied recursively from /src to /dist:
gulp.src(filePaths.assetsBuildRoot + '**/*.*', {base : basePaths.srcRoot})
.pipe(gulp.dest(basePaths.distRoot));
// Copy index.html from /src to /dist:
gulp.src(filePaths.html)
.pipe(gulp.dest(basePaths.distRoot));
gulp.task('default', function() {
// With gulp-ruby-sass
// return gulp.src('./sass/main.scss')
// .pipe(gsass({sourcemap: true, sourcemapPath: './sass/'}))
// .on('error', function (err) { console.log(err.message); })
// .pipe(gulp.dest('./src/assets/css'));
// gulp.watch('compile-sass');
console.log('You reached the finishing line');
});
I have tried allsorts to bugfix, e.g.:
Removing all of the vanilla sass compiled .css files and running the gulp compile, but no .css is produced.
Also tried removing all of the *.map files generated by the vanilla sass compile then running gulp but no dice.
Can anyone see anything glaringly and obviously wrong?
Thanks in advance.
If you are using Sass >= 3.4, you will need to install gulp-ruby-sass version 1.0.0-alpha:
npm install --save-dev gulp-ruby-sass#1.0.0-alpha
In this new version, gulp-ruby-sass is a gulp source adapter and the syntax has changed slightly. Instead of:
gulp.task('compile-sass', function() {
gulp.src('./sass/main.scss')
task code here
});
The new syntax is:
gulp.task('compile-sass', function() {
return sass('./sass/main.scss')
task code here
});
You can find more info in the new version documentation including the new syntax for sourcemaps. https://github.com/sindresorhus/gulp-ruby-sass/tree/rw/1.0
I'm writing a small web app with gorilla/mux. My folder structure inside my GOPATH is like this.
app/
- app.go
- views/
- layout.html
- login/
- login.go
- login_test.go
- login.html
I'd like to keep login as a completely separate package. Within login.go I initiate the template and render it on request. All file paths are relative to app.go as I run go run app.go in my main app/ folder.
package login
var view = template.Must(template.ParseFiles(
"login/login.html",
"views/layout.html",
))
func GetLogin(w http.ResponseWriter, r *http.Request) {
err := view.ExecuteTemplate(w, "layout", nil)
check(err)
}
That works fine and I can call the route in my app.go file.
import (
"github.com/zemirco/app/login"
)
func main() {
router := mux.NewRouter()
router.HandleFunc("/login", login.GetLogin).Methods("GET")
http.Handle("/", router)
http.ListenAndServe(":"+os.Getenv("PORT"), nil)
}
My problem is testing this route. Within login_test.go I have something like this.
package login
import (
"net/http"
"net/http/httptest"
"testing"
"."
)
func TestHandleGetLogin(t *testing.T) {
request, _ := http.NewRequest("GET", "/", nil)
response := httptest.NewRecorder()
login.GetLogin(response, request)
t.Log(response)
}
Whenever I run go test login/login_test.go I get the error message
open login/login.html: no such file or directory
As far as I know go test executes from within the login/ directory and therefore cannot find the html files. The relative file paths are wrong.
How can I solve this problem or what would be a better directory structure?