A projecthez tartozó GitHub Repository itt található
Go Service
Az előző lépésben megírtunk egy Go Application-t, és egy go module-t, ami alkalmas arra, hogy kiírjon valamit a standard outputra.
Most szeretnénk, ha egy egyszerű Go alkalmazás helyett, lenne egy microservice, aminek az API-ját meghívhatnánk. Ez úgy nézne ki, hogy vagy a böngészőn keresztül, vagy egy egyszerű curl
parannccsal küldenénk egy requestet a szerverünkhöz, amire várnánk egy választ.
Pl.: http://localhost:8081/test –> visszaadna egy választ nekünk.
Írjuk át az alkalmazásunkat, hogy egyszerű szerverként funkcionáljon.
Amikor szervert futtatunk, akkor érdemes:
- Bekérni, hogy milyen címen és porton fusson a szerver (ehhez mi flageket fogunk használni)
- Rendelkezni alapértelmezett (default) értékekkel, hogy ha valaki úgy dönt, hogy nem ad át egy címet és egy portot
- Elindítani a szervert a rendelkezésünkre álló adatokkal
A main.go
fájlunk az alábbi módon fog kinézni ezek után:
package main # Továbbra is a main package-ben maradunk
import (
"flag" # beimportáljuk a flag packaget, hogy bekérhessünk adatokat a szerver indulásakor
"fmt" # ezt használjuk arra, hogy kiírassunk üzeneteket a standard outputra
"net/http" # ennek a segítségével indítunk el egy web szervert
"github.com/SanFranciscobolJottem/penguin-api/pkg/handlers" # rövidesen írunk egy handler-t amit itt beimportálunk
)
# Ha a program indításakor nem definiálnak címet és portot, ezeket az alapértelmezett értékeket fogjuk használni
const (
defaultAddress string = "0.0.0.0"
defaultPort int = 80
)
# Ezekben a változókban fogjuk tárolni a szerver címét és a portot.
var (
address string
port int
)
# A fő függvényünk, ami legelőször meghívásra kerül program indításnál
func main() {
# Az `address` változóban fogjuk tárolni a szerver címét. Ha megadnak egy "address" paramétert program indításkor,
# akkor annak az értéke kerül bele. Ha nem adnak meg, akkor a `defaultAddress` értéke kerül bele.
# Az utolsó paraméter egy leírás a definiálható flag-ről.
flag.StringVar(&address, "address", defaultAddress, "Server's Address")
# Ugyanezt megcsináljuk a port bekérésekor, de itt az eredményt egy intben tároljuk
flag.IntVar(&port, "port", defaultPort, "Server's Port")
# Itt történik az értékek evaluálása
flag.Parse()
# Meghívjuk a segéd függvényünket
runAPI()
}
# Ez a segédfüggvény felelős azért, hogy elindítsunk egy webszervert.
func runAPI() {
# Létrehozunk egy stringet, ami tárolja a címet, egy kettőspontot és utána a portot. Pl. 127.0.0.1:8081
fullAddress := fmt.Sprintf("%s:%d", address, port)
# Kiiratunk egy üzenetet a standard outputra
fmt.Printf("\n Server is running on %s", fullAddress)
# A /test endpoint kezelését rábízzuk egy handler függvényre, amit egy másik fájlban fogunk mindjárt definiálni
http.HandleFunc("/test", handlers.TestHandler)
# Elindítjuk a szerverünket a megadott címen + porton
http.ListenAndServe(fullAddress, nil)
}
Handler készítése
Ezek után létrehozunk egy két új alkönyvtárat a project gyökérkönyvtárában.
mkdir -p pkg/handlers
és létrehozunk egy új fájlt ebben a könyvtárban, handlers.go
néven.
code pkg/handlers/handlers.go
A fájl tartalma pedig ez lesz:
package handlers # a handlers packageben fog élni, erre hivatkozik a main.go fájlunk
# beimportálunk pár segéd libraryt
import (
"fmt"
"net/http"
"strconv"
)
# Ez a handler lett a main.go-ban hozzárendelve a /test endpointhoz.
# Minden handlernek kötelező fogadnia egy writer-t, amibe a válaszunkat írjuk,
# és egy Requestet, ami a bejövő requestet képviseli.
func TestHandler(w http.ResponseWriter, r *http.Request) {
result := getSum(r) # átadjuk a requestet egy segéd függvénynek, és eltároljuk a visszatérési értéket egy változóban
fmt.Fprintf(w, "Hello Gyula, az eredmenyed: %v", result) # A response writerbe beleírjuk a válaszunkat, így a requester meg fogja kapni
}
# Ez a függvény bekér a requestből két változót, és az összegüket visszaküldi int típusú változóként
# a func jelzi, hogy ez egy függvény. A `getSum` a neve. `r`-nek hívjuk a beérkező Request paramétert. `int` típusú visszatérő értéket küldünk vissza.
func getSum(r *http.Request) int {
# Kiszedjük az a és b változó eredményét a requestből.
# Például valaki ezt írta a böngészőjébe: http://localhost:8081/test?a=1&b=2
params := r.URL.Query()
# Sajnos az értékeket string-két kapjuk vissza, ezért majd át kell őket alakítanunk int típusúvá.
a := params.Get("a")
b := params.Get("b")
# Ha nem adtak meg a URL-ben `a` változót, akkor `a` értéke nulla lesz.
if a == "" {
a = "0"
}
# Ha nem adtak meg a URL-ben `b` változót, akkor `b` értéke nulla lesz.
if b == "" {
b = "0"
}
# A string értékekből int-et csinálunk. Ha hibát kapunk (error), azt kiíratjuk a standard outputra
aNumber, err := strconv.Atoi(a)
if err != nil {
fmt.Println(err)
}
bNumber, _ := strconv.Atoi(b)
if err != nil {
fmt.Println(err)
}
# A két szám összeadott értékét visszaküldjük
return aNumber + bNumber
}
Makefile módosítása
Mivel most már képes a Go alkalmazásunk fogadni két paramétert, ezért módosíthatjuk a Makefile-unkat az alábbi módon:
run: build
$(BIN_LINUX) --address 127.0.0.1 --port 8081
Ezen a ponton érdemes tesztelni, hogy a szerverünk működik, a terminálban a gyökérkönyvtárból ismét használhatjuk a Makefile-t.
make run
Egy böngészben, vagy egy új terminal tab-en (ctrl + shift + o
) küldhetünk egy teszt requestet a szerverünknek:
curl localhost:8081/test?a=a&b=2
A visszaérkező eredményünk pedig megjelenik a válaszban. A szervert a ctrl + c
-vel tudjuk leállítani.
Visszaküldés a repositoryba
Végül pedig állítsd össze a módosításaidat és commitold őket GitHubra.
git status # Információt ad vissza a git repo aktuális állapotáról
git add . # a stage-re helyezi a módosított/hozzáadott fájlokat
git commit -m "Converting the Go App into a microservice" # A stage tartalmát commitolja a lokális repositoryba
git push origin main # Felpusholja a commitodat a GitHub repositoryba, aminek a UI-on is megnézheted a tartalmát