web dev

JavaScript Expanding Cards

This is only for documentation purposes while going through the course “50 Projects In 50 Days - HTML, CSS & JavaScript” by Brad Traversy and Florin Pop. The course is on Udemy. The source code.

More About SQL With Go

package main import ( "database/sql" "fmt" _ "github.com/jackc/pgx/v4/stdlib" // stdlib is the package that provides the standard library driver. To be able to use database sql package ) type PostgresConfig struct { Host string Port string User string Password string Database string SSLMode string } func (cfg PostgresConfig) String() string { return fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=%s", cfg.Host, cfg.Port, cfg.User, cfg.Password, cfg.Database, cfg.SSLMode) } func main() { cfg := PostgresConfig{ Host: "localhost", Port: "5432", User: "baloo", Password: "junglebook", Database: "lenslocked", SSLMode: "disable", } // pgx = Driver name defined by github.

Executing SQL With Go

The first difference in this piece of code is that the “PostgresConfig type” is replacing the long string in the sql.Open() section, as it was in the previous version of the code. The second and most important difference is that we are using db.Exec(). As far as I understand, it seems that db.Exec is used when the SQL query does not return rows, for example when doing “delete”, “update”, “insert”. On the other hand, when requiring a “select”, then db.

Postgres With Go

Two things are required to interact with the database: A library A driver Our library to interact with the database is ““database/sql” which is from the standard library. While the driver is “github.com/jackc/pgx/v4” which provides also a toolkit or library to interact with the database, but in this case we will it only for getting the driver. The below code is just one example: package main import ( "database/sql" "fmt" _ "github.

Interacting With the Database

Today it was a bit of lazy day so here it is… docker compose start [+] Running 2/2 ⠿ Container section-9-adminer-1 Started 0.4s ⠿ Container section-9-db-1 Started docker compose exec -it db psql -U baloo -d lenslocked psql (15.2 (Debian 15.2-1.pgdg110+1)) Type "help" for help. lenslocked=# lenslocked=# Deleting (dropping) a table lenslocked=# DROP TABLE IF EXISTS users; DROP TABLE lenslocked=# Adding comments lenslocked'# lenslocked'# -- Creating the "users" table lenslocked'# Creating a table lenslocked=# CREATE TABLE users ( lenslocked(# id SERIAL PRIMARY KEY, lenslocked(# age INT, lenslocked(# first_name TEXT, lenslocked(# last_name TEXT, lenslocked(# email TEXT UNIQUE NOT NULL lenslocked(# ); CREATE TABLE lenslocked=# lenslocked=# SELECT * FROM users; id | age | first_name | last_name | email ----+-----+------------+-----------+------- (0 rows) lenslocked=# lenslocked=# INSERT INTO users VALUES (1, 22, 'Alex', 'Rabocse', 'alex@email.

Connecting to Postgres

First, I am running postgres in a container. More specifically, I am using docker compose, so here is the yaml file: version: "3.9" services: # Our Postgres database db: # The service will be named db. image: postgres # The postgres image will be used restart: always # Always try to restart if this stops running environment: # Provide environment variables POSTGRES_USER: baloo # POSTGRES_USER env var w/ value baloo POSTGRES_PASSWORD: junglebook POSTGRES_DB: lenslocked # Database name ports: # Expose ports so that apps not running via docker-compose can connect to them.

Decouple With Interfaces Go

if we check the users.go controller: type Users struct { Templates struct { New views.Template } } We can see that the views.Template is used. Which mean that we are locked in (forced) to use that package views. If we replace views.Template with an interface, we could pass anything as long as it satisfies the interface. In other words, as long as it passes the methods the interface needs, then it will work.

Intro Example With Tailwind

This is how my main.go looks like: package main import ( "fmt" "net/http" "github.com/go-chi/chi/v5" "github.com/rabocse/lenslocked/controllers" "github.com/rabocse/lenslocked/templates" "github.com/rabocse/lenslocked/views" ) func main() { r := chi.NewRouter() r.Get("/", controllers.StaticHandler(views.Must(views.ParseFS(templates.FS, "home.gohtml", "tailwind.gohtml")))) r.Get("/contact", controllers.StaticHandler(views.Must(views.ParseFS(templates.FS, "contact.gohtml", "tailwind.gohtml")))) r.Get("/faq", controllers.FAQ(views.Must(views.ParseFS(templates.FS, "faq.gohtml", "tailwind.gohtml")))) r.NotFound(func(w http.ResponseWriter, r *http.Request) { http.Error(w, "Page Not Found", http.StatusNotFound) }) fmt.Println("Starting the server on :3000...") http.ListenAndServe(":3000", r) } Compared to the previous versions, now I am using a tailwind.gohtml instead of the layout-xxxx.gohtml files.

Reusable Layouts - Go

There are two possible approaches: With “Dangling” HTML tags. Layout Page 1. With “Dangling” HTML tags First, the layout-parts.gohtml is created: ├── templates │ ├── contact.gohtml │ ├── faq.gohtml │ ├── fs.go │ ├── home.gohtml │ └── layout-parts.gohtml This is how the home.gohtml looks: {{template "header"}} <h1>Welcome to my awesome site!</h1> {{template "footer"}} This is how the layout-parts.gohtml looks: {{{define "header"}}} <html> <body> {{end}} {{define "footer"}} <p>Copyright Alex Escobar 2023</p> </body> </html> {{end}} And, the only change that main.

Embedding Go

So far, the templates that I have been using reside in the templates directory from my localhost, which means of course, that if I shipped my binary and try to execute it in a different PC (or even the same PC but different directory), it will fail because it will not find the contact, faq and home.gohtml files. For reference: └── section-6 ├── controllers │ └── static.go ├── go.mod ├── go.

Adding Must Function Go

Within template.go, we can add the following “Must” fuction: func Must(t Template, err error) Template { if err != nil { panic(err) } return t } That will allow us to call it in main.go, like this: package main import ( "fmt" "net/http" "path/filepath" "github.com/go-chi/chi/v5" "github.com/rabocse/lenslocked/controllers" "github.com/rabocse/lenslocked/views" ) func main() { r := chi.NewRouter() r.Get("/", controllers.StaticHandler(views.Must(views.Parse(filepath.Join("templates", "home.gohtml"))))) r.Get("/contact", controllers.StaticHandler(views.Must(views.Parse(filepath.Join("templates", "contact.gohtml"))))) r.Get("/faq", controllers.StaticHandler(views.Must(views.Parse(filepath.Join("templates", "faq.gohtml"))))) r.NotFound(func(w http.ResponseWriter, r *http.Request) { http.Error(w, "Page Not Found", http.

Validate Template at Startup Go

Validate Template at Startup - Go We are starting to follow the MVC pattern therefore the following structure: └── section-6 ├── controllers │ └── static.go ├── go.mod ├── go.sum ├── main.go ├── templates │ ├── contact.gohtml │ ├── faq.gohtml │ └── home.gohtml └── views └── template.go Notice the following: The templates are within the template directory. views directory contains template.go which have the following: package views import ( "fmt" "html/template" "log" "net/http" ) func Parse(filepath string) (Template, error) { tpl, err := template.

Working With Go Templates

Below is an example of using Go templates for a web server: package main import ( "fmt" "log" "net/http" "path/filepath" "text/template" "github.com/go-chi/chi/v5" ) func homeHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") tplPath := filepath.Join("templates", "home.gohtml") tpl, err := template.ParseFiles(tplPath) if err != nil { log.Printf("parsing template: %v", err) http.Error(w, "There was an error parsing the template", http.StatusInternalServerError) return } err = tpl.Execute(w, nil) if err != nil { log.Printf("executing template: %v", err) http.

How Go Templates Can Help With Cross Site Scripting(XSS)

Given the following code: package main import ( "fmt" "net/http" "github.com/go-chi/chi/v5" ) func homeHandler(w http.ResponseWriter, r *http.Request) { bio := `<script>alert("You have been hacked!! XD") </script>` w.Header().Set("Content-Type", "text/html; charset=utf-8") fmt.Fprint(w, "<h1>Welcome to my site!!!! </h1> <p>Bio:"+bio+"</p>") } func contactHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") fmt.Fprint(w, "<h1> Contact Page </h1><p> To get in touch, email me at <a href=\"mailto:example@example.test\"> exampke@example.test </a>.") } func faqHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") fmt.

A bit of Go templates

A bit of Go Templates This is a file called hello.gohtml: <h1> Hello, {{.Name}} </h1> While this is the go code: package main import ( "html/template" "os" ) type User struct { Name string } func main() { t, err := template.ParseFiles("hello.gohtml") if err != nil { panic(err) } user := User{ Name: "Alex Rabocse", } t.Execute(os.Stdout, user) if err != nil { panic(err) } } Notes If we “go run” the previous file, this is what we will get: go run main.

Web Dev With Go 2

Web Dev With Go - Section 3 package main import ( "fmt" "net/http" "github.com/go-chi/chi/v5" ) func homeHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") fmt.Fprint(w, "<h1>Welcome to my site!!!! </h1>") } func contactHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") fmt.Fprint(w, "<h1> Contact Page </h1><p> To get in touch, email me at <a href=\"mailto:example@example.test\"> exampke@example.test </a>.") } func faqHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") fmt.Fprint(w, `<h1> FAG Page </h1><p> Why blah bla bla blah?

Web Dev With Go

Web Dev With Go - Section 1 Basic Handler package main import ( "fmt" "net/http" ) func home(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "<h1>Welcome to my site! </h1>") } func main() { http.HandleFunc("/", home) fmt.Println("Starting the server on :3000...") http.ListenAndServe(":3000", nil) } Notes func home receives two arguments: http.ResponseWriter *http.Request The first parameter is an interface while the second one is a pointer. It seems that the first one (http.ResponseWriter) is an interface since it is the response that the server will provide, so it could potentially be “whatever”, therefore an interface.

Not Found Page - Go

Page Not Found - Go In my previous TIL post about custom routing, I did not specify any page or message once a request is asking for a resource that is not found in the server. Below is the way how it could be added: package main import ( "fmt" "net/http" ) func homeHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Add("Fake", "my fake header") fmt.Fprint(w, "<h1> Welcome to my site </h1>") } func contactHandler(w http.

Basic Custom Routing - Go

Custom Routing (With If statements and Switch) - Go Here is a basic example about how to do custom routing with if statements: package main import ( "fmt" "net/http" ) func homeHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Add("Fake", "my fake header") fmt.Fprint(w, "<h1> Welcome to my site </h1>") } func contactHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") fmt.Fprint(w, "<h1> Contact Page </h1><p> To get in touch, email me at <a href=\"mailto:rabocse@alexrabocse.

Http.Request Type - Go

http.Request Type - Go This is just some additional notes while going through the Go Web Dev course: “r” is http.Request type, then we accessed its field called “URL”, which happens to have also a field called “Path”. package main import ( "fmt" "net/http" ) func pathHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, r.URL.Path) } func main() { http.HandleFunc("/", pathHandler) fmt.Println("Starting the server on :3000...") http.ListenAndServe(":3000", nil) } So, what this program will do is just to print the URL path that is being accessed.

Adding Contact Page With Go Handler

Adding Another Page With Go Handlers To add another page, we added another “handler”. Notice how each path is associated with a “handler”: / = homeHandler /contact = contactHandler Here is the source code: package main import ( "fmt" "net/http" ) func homeHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Add("Fake", "my fake header") fmt.Fprint(w, "<h1> Welcome to my site </h1>") } func contactHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") fmt.

HTTP Headers With Go

HTTP Headers With Go I was looking how to add HTTP headers to the HTTP responses and here it is how: package main import ( "fmt" "net/http" ) func handlerFunc(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Add("Fake", "my fake header") w.Header().Set("Content-Type", "text/plain") // w.WriteHeader(20000) fmt.Fprint(w, "<h1> Welcome to my site </h1>") } func main() { http.HandleFunc("/", handlerFunc) fmt.Println("Starting the server on :3000...") http.ListenAndServe(":3000", nil) } The one doing the magic is the Header() method.

Basic Web Server With Go

Web Dev With Go My notes from Jon Calhoun’s course. I will work with Jon’s course since I believe it will help to complete some potential projects I have in mind. Basic Web Server Here is the source code for the server: package main import ( "fmt" "net/http" ) func handlerFunc(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "<h1> Welcome to my site </h1>") } func main() { http.HandleFunc("/", handlerFunc) fmt.Println("Starting the server on :3000.

Http.Get vs Http.NewRequest

Go - http.Get vs http.NewRequest The difference between “http.Get” and http.NewRequest is that the second one allows us to get control over the HTTP heades. Turned out that I had no idea about http.Get, I guess it has to do with the fact that everything I have worked with requires authentication, therefore additional headers in the HTTP requests are needed. Official Go Documentation: https://pkg.go.dev/net/http