βοΈ Hope you find something useful. If you like it please give it a π.
- Installation
- Concepts to learn before diving into Web
- Basic Hello World
- Adding static assets
- Creating Routes
- Adding Forms
- Adding MiddleWare
- Sessions Management
- Adding Database
- Writing Unit Test
- Parsing XML Data
- File Uploading
Follow the official doc and setup Go depending on your OS (ie. Windows , Linux, OS X)
- Basic Understanding of
- Variables
- Constants
- Packages and import/export
- Functions
- Pointers
- Mutability
- Types
- Type Conversion
- Type assertion**
- Structs
- Composition
- Collection Types
- Arrays
- Slicing
- Range & Maps
- Control Flow
- If, For, Switch statement
- Methods
- Interfaces
- Concurrency
- Goroutines
- Channels
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World !")
})
http.ListenAndServe(":8000", nil)
}
When we want to serve static files like CSS, JavaScript or images to Web.
func main() {
http.HandleFunc("/", func (w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World!")
})
fs := http.FileServer(http.Dir("./static"))
http.Handle("/static/", http.StripPrefix("/static/", fs))
http.ListenAndServe(":8000", nil)
}
package main
import (
"fmt"
"encoding/json"
"net/http"
"github.com/gorilla/mux"
)
type Tasks struct {
ID string `json:"id,omitempty"`
TASKNAME string `json:"task,omitempty"`
}
var task []Tasks
func getAllTask(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(task)
}
func getTask(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
for _,item := range task {
if item.ID == params["id"] {
json.NewEncoder(w).Encode(item)
return
}
}
json.NewEncoder(w).Encode(&Tasks{})
}
func main() {
router := mux.NewRouter()
router.HandleFunc("/task", getAllTask).Methods("GET")
router.HandleFunc("/task/{id}", getTask).Methods("GET")
http.ListenAndServe(":8000", router)
}
Considering the form has 2 fields Email
and Message
.
package main
import (
"log"
"fmt"
"net/http"
)
type Details struct {
Email string
Message string
}
func messageHandle(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
fmt.Fprintf(w, "ParseForm() err: %v", err)
return
}
data := Details{
Email: r.FormValue("email"),
Message: r.FormValue("message"),
}
// do something with the data
}
func main() {
http.HandleFunc("/", messageHandle)
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal(err)
}
}
Here, the Middleware
function allows adding more than one layer of middleware and handle them appropriately.
SomeMiddleware
is the middleware function which gets called before the route handler function getAllTask
package main
import (
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
)
func getAllTask(w http.ResponseWriter, r *http.Request) {
// ... do something inside this route
}
// Function allows adding more than one layer of middleware and handle them appropriately
func Middleware(h http.Handler, middleware ...func(http.Handler) http.Handler) http.Handler {
for _, mw := range middleware {
h = mw(h)
}
return h
}
// Middlware function
func SomeMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// ... do middleware things
next.ServeHTTP(w, r)
})
}
func main() {
router := mux.NewRouter()
router.Handle("/task", Middleware(
http.HandlerFunc(getAllTask),
SomeMiddleware,
))
log.Fatal(http.ListenAndServe(":8000", router))
}
import (
"os"
"log"
"net/http"
"github.com/gorilla/sessions"
)
var store = sessions.NewCookieStore([]byte(os.Getenv("SESSION_KEY")))
func Handlerfunction(w http.ResponseWriter, r *http.Request) {
session, err := store.Get(r, "session-name")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Set some session values.
session.Values["hello"] = "world"
// Save it
session.Save(r, w)
}
func main() {
http.HandleFunc("/", Handlerfunction)
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal(err)
}
}
Here in this example we have connected MongoDB with our application and saved sample data into the collection
package main
import (
"context"
"fmt"
"os"
"time"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type Data struct {
ID int `json:"Field Int"`
Task string `json:"Field Str"`
}
func main() {
clientOptions := options.Client().ApplyURI("<MONGO_URI>")
// Connect to the MongoDB
client, err := mongo.Connect(context.TODO(), clientOptions)
if err != nil {
fmt.Println("mongo.Connect() ERROR:", err)
os.Exit(1)
}
// To manage multiple API requests
ctx, _ := context.WithTimeout(context.Background(), 15*time.Second)
// Access a MongoDB collection through a database
col := client.Database("DATABASE_NAME").Collection("COLLECTION_NAME")
// Declare a MongoDB struct instance for the document's fields and data
newData := Data{
ID: 12,
Task: "Learn Go",
}
result, err := col.InsertOne(ctx, newData)
if err != nil {
fmt.Println("ERROR:", err)
os.Exit(1)
} else {
fmt.Println("Result:", result)
}
}
Consider the Adding Routes section for testing. The below test case is for the /task
route which returns an array of tasks created by users.
package main
import (
"net/http"
"testing"
"net/http/httptest"
"strings"
)
func TestGetAllTask(t *testing.T) {
req, err := http.NewRequest("GET", "http://localhost:8000/task", nil)
if err != nil {
t.Fatal(err)
}
res := httptest.NewRecorder()
handler := http.HandlerFunc(getAllTask)
handler.ServeHTTP(res, req)
if status := res.Code; status != http.StatusOK {
t.Errorf("Wrong Status Code: got %v want %v",
status, http.StatusOK)
}
// Check the response body is what we expect.
expected := `[{"id":"1","task":"Hello"},{"id":"2","task":"World"},{"id":"3","task":"yeah"}]`
if strings.TrimRight(res.Body.String(),"\n") != expected {
t.Errorf("ERROR: got %v want %v",
res.Body.String(), expected)
}
}
Remember Test file should be name of original file + test like: base.go
- base_test.go
.(good practice)
After running the above test case by go test -v
command, the following output will appear
F:\Go\src\Rest_API>go test -v
=== RUN TestGetAllTask
--- PASS: TestGetAllTask (0.00s)
PASS
ok Rest_API 0.454s
For example we have taken this XML file for parsing.
package main
import (
"encoding/xml"
"fmt"
"io/ioutil"
"os"
)
// struct which contains the array of all Foods in the file.
type Foods struct {
Foods []Food `xml:"food"`
}
// struct which contains the details of one food.
type Food struct {
Name string `xml:"name"`
Price string `xml:"price"`
Calories string `xml:"calories"`
}
func main() {
// Open xml file
xmlFile, err := os.Open("foods.xml")
if err != nil {
fmt.Println(err)
}
// defer the closing of our xmlfile so that we can parse later
defer xmlFile.Close()
// read the xml file as a byte array.
byteValue, _ := ioutil.ReadAll(xmlFile)
var f Foods
xml.Unmarshal(byteValue, &f)
// Do something with the info.....
// Here, we print out the Foods as just an example
fmt.Println("______MENU______")
for i := 0; i < len(f.Foods); i++ {
fmt.Println(f.Foods[i].Name + " " + f.Foods[i].Price + " " + f.Foods[i].Calories)
}
}
After running the above program, the following output will appear
F:\Go\src\Code>go run parsexml.go
______MENU______
Belgian Waffles $5.95 650
French Toast $4.50 600
Todo
Contributions are always welcome! Please open an issue if you think something should be added to the list.
MIT Β© Debasish Sahoo