What is this article about?
Import
Debug
Variables and Declarations
Function Declarations
Data Type
Structure, enum, class
Maps, Arrays and Slices
Interfaces
Concurrency
Pointer
How to create a routes ( Storing routes, static routes, dynamic routes, Forwarding routes… )
Working with web handlers, requests, and ResponseWriter instances: parse request data, response JSON
Making a middleware in Golang
Handling errors and the Error interface in Golang
Concurrency in Golang
Microservice and Monolithic with Golang, java, nodejs
Using structures and closures for stateful handlers
Validating input for Go structures and user inputs
Rendering and content negotiation
Implementing and using middleware
Building a reverse proxy application
About GRPC clients
Variables and Declarations
It is quite simple to define a variables, look the example code below
Example Code
package main
import "fmt"
func main() {
// `var` declares 1 or more variables.
var a = "initial"
fmt.Println(a)
// You can declare multiple variables at once.
var b, c int = 1, 2
fmt.Println(b, c)
// Go will infer the type of initialized variables.
var d = true
fmt.Println(d)
// Variables declared without a corresponding
// initialization are _zero-valued_. For example, the
// zero value for an `int` is `0`.
var e int
fmt.Println(e)
// The `:=` syntax is shorthand for declaring and
// initializing a variable, e.g. for
// `var f string = "apple"` in this case.
f := "apple"
fmt.Println(f)
}
Declaring and Calling Functions in Golang
In Golang, we declare a function using the func keyword. A function has a name, a list of comma-separated input parameters along with their types, the result type(s), and a body.
Following is an example of a simple function called avg that takes two input parameters of type float64 and returns the average of the inputs. The result is also of type float64:
func avg(x float64, y float64) float64 {
return (x + y) / 2
}
Now, calling a function is very simple. You just need to pass the required number of parameters to the function like this:
avg(6.56, 13.44)
Here is an example to call func sum and average:
package main
import "fmt"
func avg(x float64, y float64) float64 {
return (x + y) / 2
}
func sum(x float64, y float64) float64 {
return x + y
}
func main() {
x := 5.75
y := 6.25
result := avg(x, y)
fmt.Printf("Average of %.2f and %.2f = %.2f\n", x, y, result)
sum := sum(x,y)
fmt.Printf("Sum of %.2f and %.2f = %.2f\n", x, y, sum )
}
//go run func.go
What is an interface in Golang ?
Interfaces
An interface type is defined as a set of method signatures.
A value of interface type can hold any value that implements those methods.
It is a kind of protocol
Example
type Abser interface { Abs() float64 }
How to create a web server
Here, we use the “net/http” package
The default port is 8080
Look the example code below
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
// http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request){
// fmt.Fprintf(w, "Hello!")
// })
http.HandleFunc("/hello", helloHandler) // Update this line of code
fmt.Printf("Starting server at port 8080\n")
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal(err)
}
}
func helloHandler(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/hello" {
http.Error(w, "404 not found.", http.StatusNotFound)
return
}
if r.Method != "GET" {
http.Error(w, "Method is not supported.", http.StatusNotFound)
return
}
fmt.Fprintf(w, "Hello! My name is Huy ")
}
Run the code and do a request on localhost:8080/hello, you will see this
How to create a routes
How to create a Storing routes
How to create a static routes
How to create a dynamic routes
How to create a Forwarding routes
How to get data from API request
// File: main.go package main import ( "encoding/json" "fmt" "log" "net/http" ) type Person struct { Name string Age int } func personCreate(w http.ResponseWriter, r *http.Request) { // Declare a new Person struct. var p Person // Try to decode the request body into the struct. If there is an error, // respond to the client with the error message and a 400 status code. err := json.NewDecoder(r.Body).Decode(&p) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } // Do something with the Person struct... fmt.Fprintf(w, "Person: %+v", p) } func main() { mux := http.NewServeMux() mux.HandleFunc("/person/create", personCreate) err := http.ListenAndServe(":4000", mux) log.Fatal(err) }
Run the go file above
go run main.go
Then, try to test it with a curl
/* test curl curl --location --request POST 'localhost:4000/person/create' \ --header 'X-Access-Token: xxxx' \ --header 'Content-Type: application/json' \ --data-raw '{"Name":"Tôi là ABC", "Age": 40}' */
The rusult is like below
How to response a JSON
Use “encoding/json”
and write to http response
For example
package main import ( "encoding/json" "net/http" "log" ) type Profile struct { Name string Hobbies []string } func main() { http.HandleFunc("/", foo) log.Println("Starting server on port 4000...") http.ListenAndServe(":4000", nil) } func foo(w http.ResponseWriter, r *http.Request) { profile := Profile{"Alex", []string{"snowboarding", "programming"}} js, err := json.Marshal(profile) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.Write(js) } /* test curl curl --location --request POST 'localhost:4000' \ --header 'X-Access-Token: xxxx' \ --header 'Content-Type: application/json' \ --data-raw '{"Name":"Tôi là ABC", "Age": 40}' */
Concurrency in Golang
Handling errors and the Error interface in Golang
Working with web handlers, requests, and ResponseWriter instances
Making a middleware in Golang
A middleware handler is simply an http.Handler that wraps another http.Handler to do some pre- and/or post-processing of the request. It’s called “middleware” because it sits in the middle between the Go web server and the actual handler.
//File: main.go package main import ( "log" "net/http" ) func middlewareOne(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { log.Println("Executing middlewareOne") next.ServeHTTP(w, r) log.Println("Executing middlewareOne again") }) } func middlewareTwo(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { log.Println("Executing middlewareTwo") if r.URL.Path == "/foo" { return } next.ServeHTTP(w, r) log.Println("Executing middlewareTwo again") }) } func final(w http.ResponseWriter, r *http.Request) { log.Println("Executing finalHandler") w.Write([]byte("OK")) } func main() { mux := http.NewServeMux() finalHandler := http.HandlerFunc(final) mux.Handle("/", middlewareOne(middlewareTwo(finalHandler))) log.Println("Listening on :3000...") err := http.ListenAndServe(":3000", mux) log.Fatal(err) }
Microservice and Monolithic with Golang, java, nodejs
Here we can have a look of the big picture
(Example of Microservice Architecture of Uber – Microservice Architecture.)
Building a reverse proxy application
Create a file name process.go
package proxy import ( "bytes" "net/http" "net/url" ) // ProcessRequest modifies the request in accordnance // with Proxy settings func (p *Proxy) ProcessRequest(r *http.Request) error { proxyURLRaw := p.BaseURL + r.URL.String() proxyURL, err := url.Parse(proxyURLRaw) if err != nil { return err } r.URL = proxyURL r.Host = proxyURL.Host r.RequestURI = "" return nil } // CopyResponse takes the client response and writes everything // to the ResponseWriter in the original handler func CopyResponse(w http.ResponseWriter, resp *http.Response) { var out bytes.Buffer out.ReadFrom(resp.Body) for key, values := range resp.Header { for _, value := range values { w.Header().Add(key, value) } } w.WriteHeader(resp.StatusCode) w.Write(out.Bytes()) }
Create another file name proxy.go
package proxy import ( "log" "net/http" ) // Proxy holds our configured client // and BaseURL to proxy to” type Proxy struct { Client *http.Client BaseURL string } // ServeHTTP means that proxy implements the Handler interface // It manipulates the request, forwards it to BaseURL, then // returns the response func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { if err := p.ProcessRequest(r); err != nil { log.Printf("error occurred during process request: %s", err.Error()) w.WriteHeader(http.StatusBadRequest) return } resp, err := p.Client.Do(r) if err != nil { log.Printf("error occurred during client operation: %s", err.Error()) w.WriteHeader(http.StatusInternalServerError) return } defer resp.Body.Close() CopyResponse(w, resp) }
Finally, a main.go
package main import ( "fmt" "net/http" "proxy" ) func main() { p := &proxy.Proxy{ Client: http.DefaultClient, BaseURL: "https://www.golang.org", } http.Handle("/", p) fmt.Println("Listening on port :3333") err := http.ListenAndServe(":3333", nil) panic(err) }
About GRPC clients
GRPC is a high-performance RPC framework that is built using protocol buffers (https://developers.google.com/protocol-buffers) and HTTP/2 (https://http2.github.io). Creating a GRPC client in Go involves many of the same intricacies as working with Go HTTP clients
# Keyword
OAuth2
NoSQL with MongoDB
WEB Clients and APIs
REST
gRPC
parallel and async request
interface
connect database
database handler
validate user input: don’t ever trust user input
Test tool
Working with web handlers, requests, and ResponseWriter instances
Using structures and closures for stateful handlers
Validating input for Go structures and user inputs
Rendering and content negotiation
Implementing and using middleware
Building a reverse proxy application
Exporting GRPC as a JSON API
Using Kafka with Sarama
GoFlow
Consumer and producer
Serverless
Apex, Lambda, AWS Lambda
Memory allocation and heap management
Reference:
https://openmymind.net/The-Little-Go-Book/
Download ebook Go here