Create a Golang Web App without using any Framework
Use the net/http library to create a web application without using any framework
When it comes to making a web app in Golang, I have often seen tutorials that were taught in Gin, Beego, Fiber, etc. Beginners have no clue to make a simple Golang web app without using any framework.
When I was first learning Golang, I made a few simple projects but when it came to making a web app, I didn't find many resources online.
Most of the resources were focused on the frameworks. For me, it was really difficult to learn them. Finally, after reading some books and the code line by line, I understood the concept of making a web application in Golang. Unfortunately, the books are paid and there are limited resources online.
Here is a blog that will help you create a Golang web app without using any framework.
Note: I am going to briefly explain each and every step in this blog. But I won't attach the browser screenshots as a result. It's your homework to do it.
Prerequisites
- Install Golang.
- Install Visual Studio Code.
Implementation
After installing the Golang, open the Visual Studio Code and create a main.go file. Inside the main.go file, write the following code.
main.go
package main
import (
"fmt"
"log"
"net/http"
)
func HomePage(w http.ResponseWriter) {
fmt.Fprintln(w, "<h1> Home page </h1>")
}
func AboutPage(w http.ResponseWriter) {
fmt.Fprintln(w, "<h1> About page </h1>")
}
func ContactPage(w http.ResponseWriter) {
fmt.Fprintln(w, "<h1> Contact page </h1>")
}
func main() {
http.HandleFunc("/", HomePage)
http.HandleFunc("/about", AboutPage)
http.HandleFunc("/contact", ContactPage)
fmt.Println("Starting the server at port: 8080")
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal(err)
}
}
This file has four functions. Three of them are the functions of different pages and the last one is the
main()
function that will run all the above three functions.The
HomePage
,AboutPage
andContactPage
functions contain the write parameter(w http.ResponseWriter)
that is used to print the data on the browser.fmt.Fprintln()
will write the data on the browser.Every function is called in the main function using the
http.HandleFunc()
with a link and a function name.fmt.Println()
will print the message when the code will run.At the end,
http.ListenAndServe
is used that will contain the port number. You can give any port number you want. I gave the port number8080
.After writing this code, run it in the terminal by typing
go run main.go
and it will give you a message Starting the server at port: 8080. Once this message is given, typelocalhost:8080
in the browser and you will see the home page.You can move to other pages also by typing
localhost:8080/about
orlocalhost:8080/contact
.
Adding if-statement and read parameter
main.go
func HomePage(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
fmt.Fprintln(w, "<h1> Page not found </h1>")
return
}
fmt.Fprintln(w, "<h1> Home page </h1>")
}
r *http.Request
is added to read the data.if r.URL.Path != "/"
is used to stop running other links. If the given links like/
,/about
,/contact
are not visited or if other links are visited likelocalhost:8080/hello
orlocalhost:8080/try
etc, it will give an error message that the page is not found.
Using HTML templates in Golang
views/templates/home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title> Home </title>
</head>
<body>
<h1>Home Page</h1>
<h1>This is the home page</h1>
</body>
</html>
main.go
package main
import (
"fmt"
"net/http"
"html/template"
)
var homeTmpl = template.Must(template.ParseFiles("views/templates/home.html"))
var aboutTmpl = template.Must(template.ParseFiles("views/templates/about.html"))
var contactTmpl = template.Must(template.ParseFiles("views/templates/contact.html"))
func HomePage(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
fmt.Fprintln(w, "<h1> Page not found </h1>")
return
}
homeTmpl.Execute(w, nil)
}
func AboutPage(w http.ResponseWriter) {
aboutTmpl.Execute(w, nil)
}
func ContactPage(w http.ResponseWriter) {
contactTmpl.Execute(w, nil)
}
...
Make a views directory. Inside the views, create a subdirectory called templates. Inside the templates, create three HTML files by the name of home.html, about.html, and contact.html.
Write the same HTML code in all the files that I have written above in the home.html but just change the title and the body text in each file.
After that, move to the main.go file and change the code a little bit. Write the file paths inside the
template.Must(template.ParseFiles()
to fetch the data from those files and make them equal to different variable names likehomeTmpl
,aboutTmpl
, andcontactTmpl
.Once these variables are created, remove the
fmt.Fprintln()
from each function and instead take the variable names that are just created and writeExecute(w, nil)
with it. It will execute those files.Run the code to start the server again and type
localhost:8080
in the browser. You will see that the HTML file text is executed in the browser. Move to other pages. You will also see the other files' execution.
Problem No. 1
main.go
...
func MakeTemplate(path string) template.Template {
return *template.Must(template.ParseFiles(path))
}
var homeTmpl = MakeTemplate("views/templates/home.html")
var aboutTmpl = MakeTemplate("views/templates/about.html")
var contactTmpl = MakeTemplate("views/templates/contact.html")
...
If there are multiple pages then
template.Must(template.ParseFiles()
is going to be used multiple times. To avoid this problem, I created a function by the name ofMakeTemplate()
and inside it, I just returned this common code*template.Must(template.ParseFiles(path))
so that it is not used multiple times.Just give a path as an argument in the
MakeTemplate()
function and you're good to go.
Problem No. 2
views/templates/base.html
{{define "base"}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title> {{template "title" .}} </title>
</head>
<body>
<section>
{{template "body" .}}
</section>
</body>
</html>
{{end}}
views/templates/home.html
{{template "base" .}}
{{define "title"}} Home {{end}}
{{define "body"}}
<h1> Home Page </h1>
<p> This is the home page </p>
{{end}}
views/templates/about.html
{{template "base" .}}
{{define "title"}} About {{end}}
{{define "body"}}
<h1> About Page </h1>
<p> This is an about page </p>
{{end}}
views/templates/contact.html
{{template "base" .}}
{{define "title"}} Contact {{end}}
{{define "body"}}
<h1> Contact Page </h1>
<p> This is the contact page </p>
{{end}}
main.go
...
func MakeTemplate(path string) template.Template {
files := []string{path, "views/templates/base.html"}
return *template.Must(template.ParseFiles(files...))
}
...
Most of the HTML code is common in all the templates. To solve this problem, there is a need to create a base.html file that will contain that common code and we just need to call that template to use it.
In the base.html file, I used
{{define "base"}} ... {{end}}
. It means that the code/template inside the{{define "base"}} ... {{end}}
is able to be used in all the HTML files.define "base"
is like a variable that is equal to the whole template. Now I just need to call this variable in other HTML files to use it.In the base.html file, I also used
{{template "title" .}}
and{{template "body" .}}
to call the title and body that are defined in other template files(home.html, about.html, and contact.html).Now come to the home.html, about.html, and contact.html files. Inside each of them, you can see that I called
{{template "base" .}}
that I defined in the base.html file. It will use the HTML template of the base.html inside all the other HTML files.I defined the title and body in each file separately. That data is already called in the base.html file by using the
{{template "title" .}}
and{{template "body" .}}
.In the main.go file, I wrote
files := []string{path, "views/templates/base.html"}
inside theMakeTemplate()
function. You can see that every path variable is linked to the base.html file path. It means that if any path is running, then the base.html file will also run with it. I make this line of code equal to thefiles
variable.Use this
files
variable while returning the code and the three dots...
mean to find all the files recursively.
I hope you like this blog. If you like it then make sure to share it with other people to help them. You can also connect with me on Twitter.
Thank you!