Go like any other language has different ways data can be expressed Numerical: int, float, double bool : true, false text : Strings Container types : Arrays and Slices Custom Types : structs
// ways to declare variables
var num = 5
//or the more compact form
num := 5
// you can also declare multiple variables in go
num1, num2 := 5, 6
//strings for text
name := "John"
// arrays and slices
//arrays have static size i.e the size cannot be changed after declaration
arr := [3]int{1,2,3}
// slices are dynamic and are resizable
slice := []int{1,2,3}there are ywo main conditional structures in go
//if-else statement
age := 18
if age < 18{
fmt.Print("you cant drive")
}else{
fmt.Print("you can drive")
}
//switch statement
switch day{
case 1:
fmt.Print("Monday")
case 2:
fmt.Print("Tuesday")
case 3:
fmt.Print("Wednesday")
case 4:
fmt.Print("Thursday")
case 5:
fmt.Print("Friday")
case 6:
fmt.Print("Saturday")
case 7:
fmt.Print("Sunday")
default:
fmt.Print("Invalid day")
}like any other language go has repetitive structures known as loops, but unlike others go only has one loop structure which is for
// standard for loop
// prints numbers from 0 to 9
for i:=0; i<10; i++{
fmt.Print(i)
}
// while loop
i:=0
for i<10{
fmt.Print(i)
i++
}
// range based loop
//usually to access indices and values of container structures
// prints the indices of the array with their corresponding values
arr := [3]int{1,2,3}
for index, value := range arr{
fmt.Print("index: %d, value: %d\n", index, value)
}functions are blocks of code that accomplish specific tasks and have at least one return value. Note that variables used un functions are copies and are only native to the function.
// return one value
func add (a int, b int) int{
return a+b
}
// function with 2 return values
func isEven(num int) bool, error{
if num%2 == 0{
return true, nil
}
return false, nil
}these are the features in Go that enables its OOP qualities
type User struct{
name string
age int
}
// above we can see that a user is a type with a name and an age field
// and fields can be referenced using the dot operator
var user User
user.name = "John"
user.age = 20
// so this is a user who's name is John and is 20 years old
Meanwhile an interface is used for types that satisfy a certain condition, it is like go's nifty way of expressing polymorphism
type Animal interface{
Speak() string
}
type Dog struct{
name string
}
type Cat struct{
name string
}
func (d Dog) Speak() string{
return "Woof!"
}
func (c Cat) Speak() string{
return "Meow!"
}
func main(){
dog := Dog{"Fido"}
cat := Cat{"Whiskers"}
animals := []Animal{dog, cat}
for _, animal := range animals{
fmt.Println(animal.Speak())
}
}
// dogs and cats can use the animal interface because they meet the "speak" requirement
// dog goes woof and cat goes meowpointers are addresses that store the memory address of a variable
x := 5
var p *int
p = &x
//prints the address of x
fmt.print("value stored in the address of p : %p\n", p )
// we can get the value at x by dereferencing p
fmt.print("value of x : %d\n", *p)
//pointers can also be passed as variables of functions
// when pointers are used any operations that changes the value of the variables in the function will reflect outside the function
func main(){
x := 5
y := 10
swap(&x, &y)
fmt.Print("x: %d, y: %d\n", x, y)
// prints x: 10, y: 5
}
func swap(a *int, b *int){
temp := *a
*a = *b
*b = temp
}is a type Native to Go which checks if there is an error, possible values are nil or an errorif
func divide(a int, b int) (int, error){
if b == 0{
return 0, errors.New("cannot divide by zero")
}
return a/b, nil
}
// return error message if b is 0, since divison by 0 is not possible
func sqrt(x float64) (float64, error){
if x < 0{
return 0, errors.New("cannot take square root of negative number")
}
return math.Sqrt(x), nil
}
// negative numbers have no real square rootspackages are files that provide some level of abstraction for certain operations net/http : web programming golang-jwt : JWT Authentication godotenv : read content from .env files gorm : Go Object Relational Model e.t.c.
these are packages made specifically for the rich features that provide good web abstractions during development Go has a multitude of such frameworks but we'll be focusing on fiber
you nee to get the following package
go get github.com/gofiber/fiber/v2//basic fiber app
package main
import (
"github.com/gofiber/fiber/v2"
)
func main() {
app := fiber.New()
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Hello, World!")
})
app.Listen(":3000")
}Fiber supports all standard HTTP methods:
package main
import "github.com/gofiber/fiber/v2"
func main() {
app := fiber.New()
// GET method
app.Get("/api/data", func(c *fiber.Ctx) error {
return c.SendString("GET request received")
})
// POST method
app.Post("/api/data", func(c *fiber.Ctx) error {
return c.SendString("POST request received")
})
// PUT method
app.Put("/api/data/:id", func(c *fiber.Ctx) error {
return c.SendString("PUT request for ID: " + c.Params("id"))
})
// DELETE method
app.Delete("/api/data/:id", func(c *fiber.Ctx) error {
return c.SendString("DELETE request for ID: " + c.Params("id"))
})
// PATCH method
app.Patch("/api/data/:id", func(c *fiber.Ctx) error {
return c.SendString("PATCH request for ID: " + c.Params("id"))
})
// All method (matches any HTTP method)
app.All("/api/all", func(c *fiber.Ctx) error {
return c.SendString("This matches any HTTP method")
})
app.Listen(":3000")
}Handlers in Fiber are functions that process HTTP requests. Here's a more structured approach:
package main
import (
"github.com/gofiber/fiber/v2"
)
// User struct for JSON parsing
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
// Handler functions
func homeHandler(c *fiber.Ctx) error {
return c.SendString("Welcome to the homepage!")
}
func getUserHandler(c *fiber.Ctx) error {
id := c.Params("id")
return c.JSON(fiber.Map{"id": id, "name": "John Doe"})
}
func createUserHandler(c *fiber.Ctx) error {
user := new(User)
if err := c.BodyParser(user); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(user)
}
func main() {
app := fiber.New()
// Route grouping
api := app.Group("/api")
// Basic route
app.Get("/", homeHandler)
// API routes
api.Get("/users/:id", getUserHandler)
api.Post("/users", createUserHandler)
app.Listen(":3000")
}Middleware functions execute between the request and response:
package main
import (
"fmt"
"github.com/gofiber/fiber/v2"
)
// Logger middleware
func logger(c *fiber.Ctx) error {
fmt.Printf("%s - %s\n", c.Method(), c.Path())
return c.Next()
}
// Auth middleware
func authRequired(c *fiber.Ctx) error {
token := c.Get("Authorization")
if token != "secret-token" {
return c.Status(fiber.StatusUnauthorized).SendString("Unauthorized")
}
return c.Next()
}
func main() {
app := fiber.New()
// Global middleware
app.Use(logger)
// Public route
app.Get("/public", func(c *fiber.Ctx) error {
return c.SendString("Public content")
})
// Protected route with auth middleware
app.Get("/private", authRequired, func(c *fiber.Ctx) error {
return c.SendString("Private content")
})
app.Listen(":3000")
}package main
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/session"
"github.com/gofiber/storage/redis"
)
func main() {
// Session storage using Redis
store := session.New(session.Config{
Storage: redis.New(redis.Config{
Host: "localhost",
Port: 6379,
Username: "",
Password: "",
Database: 1,
}),
})
app := fiber.New()
app.Get("/set-cookie", func(c *fiber.Ctx) error {
c.Cookie(&fiber.Cookie{
Name: "token",
Value: "random-value",
Expires: time.Now().Add(24 * time.Hour),
HTTPOnly: true,
Secure: true,
})
return c.SendString("Cookie set")
})
app.Get("/get-cookie", func(c *fiber.Ctx) error {
return c.SendString("Cookie value: " + c.Cookies("token"))
})
app.Get("/set-session", func(c *fiber.Ctx) error {
sess, err := store.Get(c)
if err != nil {
return err
}
sess.Set("username", "john_doe")
if err := sess.Save(); err != nil {
return err
}
return c.SendString("Session set")
})
app.Get("/get-session", func(c *fiber.Ctx) error {
sess, err := store.Get(c)
if err != nil {
return err
}
username := sess.Get("username")
return c.SendString("Session username: " + username.(string))
})
app.Listen(":3000")
}package main
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/session"
)
var store = session.New()
type User struct {
Username string `json:"username"`
Password string `json:"password"`
}
func login(c *fiber.Ctx) error {
var user User
if err := c.BodyParser(&user); err != nil {
return err
}
// In a real app, verify credentials against database
if user.Username != "admin" || user.Password != "password123" {
return c.Status(fiber.StatusUnauthorized).SendString("Invalid credentials")
}
sess, err := store.Get(c)
if err != nil {
return err
}
sess.Set("authenticated", true)
sess.Set("username", user.Username)
if err := sess.Save(); err != nil {
return err
}
return c.SendString("Logged in successfully")
}
func authMiddleware(c *fiber.Ctx) error {
sess, err := store.Get(c)
if err != nil {
return err
}
if auth, ok := sess.Get("authenticated").(bool); !ok || !auth {
return c.Status(fiber.StatusUnauthorized).SendString("Unauthorized")
}
return c.Next()
}
func profile(c *fiber.Ctx) error {
sess, err := store.Get(c)
if err != nil {
return err
}
username := sess.Get("username")
return c.JSON(fiber.Map{"username": username})
}
func logout(c *fiber.Ctx) error {
sess, err := store.Get(c)
if err != nil {
return err
}
if err := sess.Destroy(); err != nil {
return err
}
return c.SendString("Logged out successfully")
}
func main() {
app := fiber.New()
app.Post("/login", login)
app.Get("/profile", authMiddleware, profile)
app.Get("/logout", authMiddleware, logout)
app.Listen(":3000")
}package main
import (
"gorm.io/driver/postgres"
"gorm.io/gorm"
"github.com/gofiber/fiber/v2"
)
type User struct {
gorm.Model
Username string `gorm:"unique;not null"`
Email string `gorm:"unique;not null"`
Password string `gorm:"not null"`
}
var DB *gorm.DB
func initDB() {
dsn := "host=localhost user=postgres password=postgres dbname=golang port=5432 sslmode=disable TimeZone=UTC"
var err error
DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
DB.AutoMigrate(&User{})
}
func createUser(c *fiber.Ctx) error {
user := new(User)
if err := c.BodyParser(user); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()})
}
result := DB.Create(&user)
if result.Error != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": result.Error.Error()})
}
return c.JSON(user)
}
func getUser(c *fiber.Ctx) error {
id := c.Params("id")
var user User
result := DB.First(&user, id)
if result.Error != nil {
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "User not found"})
}
return c.JSON(user)
}
func updateUser(c *fiber.Ctx) error {
id := c.Params("id")
var user User
result := DB.First(&user, id)
if result.Error != nil {
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "User not found"})
}
updates := new(User)
if err := c.BodyParser(updates); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()})
}
DB.Model(&user).Updates(updates)
return c.JSON(user)
}
func deleteUser(c *fiber.Ctx) error {
id := c.Params("id")
result := DB.Delete(&User{}, id)
if result.Error != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": result.Error.Error()})
}
return c.SendString("User deleted successfully")
}
func main() {
initDB()
app := fiber.New()
app.Post("/users", createUser)
app.Get("/users/:id", getUser)
app.Put("/users/:id", updateUser)
app.Delete("/users/:id", deleteUser)
app.Listen(":3000")
}