Sorted out how to do views with Go html/template, how to put code in subdirectories for a namespace, and documented why Go's modules are so weird.
This commit is contained in:
parent
144a76a67a
commit
55f59d88b6
11 changed files with 155 additions and 53 deletions
|
@ -4,7 +4,7 @@ tmp_dir = "tmp"
|
|||
|
||||
[build]
|
||||
args_bin = []
|
||||
bin = "fibertest.exe"
|
||||
bin = "webapp"
|
||||
cmd = "make build"
|
||||
delay = 1000
|
||||
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
|
||||
|
|
3
Makefile
3
Makefile
|
@ -1,6 +1,9 @@
|
|||
build:
|
||||
go build .
|
||||
|
||||
html:
|
||||
go tool qtc -dir templates
|
||||
|
||||
docs:
|
||||
go tool godoc -http=localhost:6060 -index -index_files godoc.idx
|
||||
|
||||
|
|
40
README.md
40
README.md
|
@ -22,3 +22,43 @@ go tool godoc -http=localhost:6060 -index
|
|||
> ___NOTE:___ Google doesn't know how the internet works so you have to use `localhost:PORT` and not `127.0.0.1:PORT` when you run this.
|
||||
|
||||
After that it'll take some time to index everything but you can already start browsing the APIs you need, and your project's stuff is in the _Third Party_ section.
|
||||
|
||||
## Dealing With Module Bullshit
|
||||
|
||||
The way to think about Go's modules is that they don't have modules, they have "projects." Every
|
||||
directory's .go files export all of their functions without any namespacing based on the file's
|
||||
name. So if you put `FooBar` into `tools.go` and `Dipshit` in `fuckyou.go` then your namespace for
|
||||
_all_ files has raw dogged `FooBar` and `Dipshit` without any reference to `tools` or `fuckyou`.
|
||||
|
||||
That's because your root directory is a whole __project__, not a module. To then create a namespace
|
||||
you have to make a directory, place the files in that directory, and add `package mymod` at the top
|
||||
of those files. You then have to import this as if it's an __entire fucking project__ everywhere
|
||||
you want to use it:
|
||||
|
||||
```go
|
||||
import 'mywholewebsite.com/rootproject/subproject'
|
||||
```
|
||||
|
||||
In this case you have a directory `subproject` and in there are a bunch of .go files with `package subproject` at the top to indicate they are in that subproject. Thinking about Go's modules as separate projects helps to sort out this `import` statement.
|
||||
|
||||
1. mkdir tools
|
||||
2. Create files in tools/ with `package tools`
|
||||
3. `import "zedshaw.games/webapp/tools"` to get the subdirectory
|
||||
|
||||
## Why Did Go Do This?
|
||||
|
||||
That's because it comes from Google, and Google is famous for two things:
|
||||
|
||||
1. Using a monorepo.
|
||||
2. Assuming everyone else uses a monorepo.
|
||||
|
||||
Don't believe me? Go look at the official first document [covering modules](https://go.dev/doc/tutorial/create-module) and you'll see they create two _totally separate projects at the root which then link to each other_. That's not how anyone else thinks when they make a single project to work on, but if you're suffering in monorepo hell you'll do it this way.
|
||||
|
||||
I'll also posit that Google has some weird incentive that measures numbers of projects in the
|
||||
monorepo as some kind of metric for employee productivity, so everyone working there is motivated
|
||||
to get as many little projects into the monorepo as possible, thus a great way to get them to adopt
|
||||
Go is to make Go support pulling tons of random projects from the root of a monorepo.
|
||||
|
||||
So that's why you have to put your whole entire domain name into the import, and why you have all
|
||||
the functions just raw dogged into your face when you make multiple files, and why subdirectories
|
||||
are treated like whole little projects.
|
||||
|
|
9
go.mod
9
go.mod
|
@ -1,12 +1,15 @@
|
|||
module zedshaw-games/fibertest
|
||||
module zedshaw.games/webapp
|
||||
|
||||
go 1.24.2
|
||||
|
||||
require (
|
||||
github.com/Masterminds/squirrel v1.5.4
|
||||
github.com/go-playground/validator/v10 v10.26.0
|
||||
github.com/gofiber/fiber/v2 v2.52.8
|
||||
github.com/gofiber/template/html/v2 v2.1.3
|
||||
github.com/jmoiron/sqlx v1.4.0
|
||||
github.com/mattn/go-sqlite3 v1.14.28
|
||||
github.com/valyala/quicktemplate v1.8.0
|
||||
)
|
||||
|
||||
require (
|
||||
|
@ -35,9 +38,10 @@ require (
|
|||
github.com/go-faster/errors v0.7.1 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.26.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.9.2 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/gofiber/template v1.8.3 // indirect
|
||||
github.com/gofiber/utils v1.1.0 // indirect
|
||||
github.com/gohugoio/hugo v0.147.6 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||
|
@ -78,7 +82,6 @@ require (
|
|||
github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.58.0 // indirect
|
||||
github.com/valyala/quicktemplate v1.8.0 // indirect
|
||||
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||
github.com/vertica/vertica-sql-go v1.3.3 // indirect
|
||||
github.com/ydb-platform/ydb-go-genproto v0.0.0-20241112172322-ea1f63298f77 // indirect
|
||||
|
|
8
go.sum
8
go.sum
|
@ -135,6 +135,8 @@ github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1
|
|||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
|
@ -150,6 +152,12 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
|||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/gofiber/fiber/v2 v2.52.8 h1:xl4jJQ0BV5EJTA2aWiKw/VddRpHrKeZLF0QPUxqn0x4=
|
||||
github.com/gofiber/fiber/v2 v2.52.8/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
|
||||
github.com/gofiber/template v1.8.3 h1:hzHdvMwMo/T2kouz2pPCA0zGiLCeMnoGsQZBTSYgZxc=
|
||||
github.com/gofiber/template v1.8.3/go.mod h1:bs/2n0pSNPOkRa5VJ8zTIvedcI/lEYxzV3+YPXdBvq8=
|
||||
github.com/gofiber/template/html/v2 v2.1.3 h1:n1LYBtmr9C0V/k/3qBblXyMxV5B0o/gpb6dFLp8ea+o=
|
||||
github.com/gofiber/template/html/v2 v2.1.3/go.mod h1:U5Fxgc5KpyujU9OqKzy6Kn6Qup6Tm7zdsISR+VpnHRE=
|
||||
github.com/gofiber/utils v1.1.0 h1:vdEBpn7AzIUJRhe+CiTOJdUcTg4Q9RK+pEa0KPbLdrM=
|
||||
github.com/gofiber/utils v1.1.0/go.mod h1:poZpsnhBykfnY1Mc0KeEa6mSHrS3dV0+oBWyeQmb2e0=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/gohugoio/go-i18n/v2 v2.1.3-0.20230805085216-e63c13218d0e h1:QArsSubW7eDh8APMXkByjQWvuljwPGAGQpJEFn0F0wY=
|
||||
github.com/gohugoio/go-i18n/v2 v2.1.3-0.20230805085216-e63c13218d0e/go.mod h1:3Ltoo9Banwq0gOtcOwxuHG6omk+AwsQPADyw2vQYOJQ=
|
||||
|
|
68
main.go
68
main.go
|
@ -1,15 +1,15 @@
|
|||
package main
|
||||
package webapp
|
||||
|
||||
import (
|
||||
"log"
|
||||
"zedshaw.games/webapp/tools"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/logger"
|
||||
"github.com/gofiber/template/html/v2"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/jmoiron/sqlx"
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
type Link struct {
|
||||
|
@ -26,34 +26,6 @@ type Stream struct {
|
|||
}
|
||||
|
||||
|
||||
func SelectJson[T any](db *sqlx.DB, c *fiber.Ctx, err error, sql string, args ...interface{}) error {
|
||||
if(err != nil) {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
var result []T
|
||||
|
||||
err = db.Select(&result, sql, args...)
|
||||
if(err != nil) {
|
||||
log.Fatalln(err);
|
||||
}
|
||||
|
||||
return c.JSON(&result);
|
||||
}
|
||||
|
||||
func GetJson[T any](db *sqlx.DB, c *fiber.Ctx, err error, sql string, args ...interface{}) error {
|
||||
if(err != nil) {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
var result T
|
||||
|
||||
err = db.Get(&result, sql, args...)
|
||||
if(err != nil) {
|
||||
log.Fatalln(err);
|
||||
}
|
||||
|
||||
return c.JSON(&result);
|
||||
}
|
||||
|
||||
func main() {
|
||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||
|
||||
|
@ -62,41 +34,35 @@ func main() {
|
|||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
app := fiber.New()
|
||||
engine := html.New("./views", ".html")
|
||||
app := fiber.New(fiber.Config{
|
||||
Views: engine,
|
||||
})
|
||||
app.Use(logger.New())
|
||||
|
||||
// handler that returns one json from a sql database
|
||||
app.Get("/api/stream/", func (c *fiber.Ctx) error {
|
||||
sql, args, err := sq.Select("*").From("stream").ToSql()
|
||||
return SelectJson[Stream](db, c, err, sql, args...)
|
||||
return tools.SelectJson[Stream](db, c, err, sql, args...)
|
||||
})
|
||||
|
||||
app.Get("/api/stream/:id", func (c *fiber.Ctx) error {
|
||||
sql, args, err := sq.Select("*").From("stream").Where("id", c.Params("id")).ToSql()
|
||||
return GetJson[Stream](db, c, err, sql, args...)
|
||||
return tools.GetJson[Stream](db, c, err, sql, args...)
|
||||
})
|
||||
|
||||
app.Get("/api/stream/:id/links", func (c *fiber.Ctx) error {
|
||||
sql, args, err := sq.Select("*").From("stream_link").Where("stream_id", c.Params("id")).ToSql()
|
||||
|
||||
return SelectJson[Link](db, c, err, sql, args...)
|
||||
return tools.SelectJson[Link](db, c, err, sql, args...)
|
||||
})
|
||||
|
||||
app.Post("/api/link", func (c *fiber.Ctx) error {
|
||||
link := new(Link)
|
||||
link, err := tools.GetThing[Link](c)
|
||||
|
||||
if err := c.BodyParser(link); err != nil {
|
||||
log.Println(err);
|
||||
return c.Redirect("/live/")
|
||||
}
|
||||
|
||||
var validate *validator.Validate
|
||||
validate = validator.New(validator.WithRequiredStructEnabled())
|
||||
|
||||
if err := validate.Struct(link); err != nil {
|
||||
validationErrors := err.(validator.ValidationErrors)
|
||||
log.Println(validationErrors)
|
||||
return c.Redirect("/live/")
|
||||
if(err != nil) {
|
||||
log.Println(err)
|
||||
c.Redirect("/live/")
|
||||
}
|
||||
|
||||
sql, args, err := sq.Insert("stream_link").Columns("stream_id", "url", "description").Values(link.StreamId, link.Url, link.Description).ToSql()
|
||||
|
@ -113,5 +79,11 @@ func main() {
|
|||
|
||||
app.Static("/", "./public")
|
||||
|
||||
app.Get("/test/", func (c *fiber.Ctx) error {
|
||||
return c.Render("index", fiber.Map{
|
||||
"Title": "Hello, World!",
|
||||
})
|
||||
})
|
||||
|
||||
log.Fatal(app.Listen(":5001"))
|
||||
}
|
||||
|
|
59
tools/tools.go
Normal file
59
tools/tools.go
Normal file
|
@ -0,0 +1,59 @@
|
|||
package tools
|
||||
|
||||
import (
|
||||
"log"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
func SelectJson[T any](db *sqlx.DB, c *fiber.Ctx, err error, sql string, args ...interface{}) error {
|
||||
if(err != nil) {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
var result []T
|
||||
|
||||
err = db.Select(&result, sql, args...)
|
||||
if(err != nil) {
|
||||
log.Fatalln(err);
|
||||
}
|
||||
|
||||
return c.JSON(&result);
|
||||
}
|
||||
|
||||
func GetJson[T any](db *sqlx.DB, c *fiber.Ctx, err error, sql string, args ...interface{}) error {
|
||||
if(err != nil) {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
var result T
|
||||
|
||||
err = db.Get(&result, sql, args...)
|
||||
if(err != nil) {
|
||||
log.Fatalln(err);
|
||||
}
|
||||
|
||||
return c.JSON(&result);
|
||||
}
|
||||
|
||||
func GetThing[T any](c *fiber.Ctx) (*T, error) {
|
||||
var result *T
|
||||
result = new(T)
|
||||
|
||||
if err := c.BodyParser(result); err != nil {
|
||||
log.Println(err);
|
||||
return result, err
|
||||
}
|
||||
|
||||
var validate *validator.Validate
|
||||
validate = validator.New(validator.WithRequiredStructEnabled())
|
||||
|
||||
if err := validate.Struct(result); err != nil {
|
||||
validationErrors := err.(validator.ValidationErrors)
|
||||
log.Println(validationErrors)
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
5
views/index.html
Normal file
5
views/index.html
Normal file
|
@ -0,0 +1,5 @@
|
|||
{{template "partials/header" .}}
|
||||
|
||||
<h1>{{.Title}}</h1>
|
||||
|
||||
{{template "partials/footer" .}}
|
10
views/layouts/main.html
Normal file
10
views/layouts/main.html
Normal file
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Main</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{{embed}}
|
||||
</body>
|
||||
</html>
|
1
views/partials/footer.html
Normal file
1
views/partials/footer.html
Normal file
|
@ -0,0 +1 @@
|
|||
</h2>Footer</h2>
|
1
views/partials/header.html
Normal file
1
views/partials/header.html
Normal file
|
@ -0,0 +1 @@
|
|||
<h1>Header</h1>
|
Loading…
Add table
Add a link
Reference in a new issue