Go HTTP Webserver
Go ofron suport për protokolin HTTP, me ç’rast nuk nevojitet kurrfarë serveri i jashtëm, për shembull siç është rasti me PHP.
1 package main
2
3 import (
4 "fmt"
5 "net/http"
6 )
7
8 func main() {
9 fmt.Println("Duke e startuar serverin")
10 http.HandleFunc("/", homeHandler)
11 err := http.ListenAndServe(":8080", nil)
12 if err != nil {
13 panic(err)
14 }
15 }
16 func homeHandler(w http.ResponseWriter, r *http.Request) {
17 fmt.Println("Pergjigja nga Web aplikacioni")
18 }
https://play.golang.org/p/n8CKMxzIp9z
<I Ky program nuk ekzekutohet në Go Playground, duhet të kompajlohet.
Rezultati:
Programi i mësipërm kthen përgjigje në konzolë, por në fakt ne do ta modifikojmë asisoj që përgjigjen ta kthejë si HTPP Response, pra t’ia dërgojë tekstin browserit në vend të konzolës.
Ashtu si është tani, programi startohet, shfaq tekstin “Duke e startuar serverin” në konzolë.
E hapim browserin dhe atje shënojmë si adresë:
Sa herë bëjmë refresh në browser, në konzolë do të shfaqet teksti “Pergjigja nga Web aplikacioni”.
<I Në vend të 8080 mund të shënojë një numër arbitrar të lirë. Në produksion do të përdorim portin 80, për çka në fund të domainit nuk do të kemi nevojë ta shënojmë numrin e portit. Pra, nëse porti është 80, ky aplikacion do të thirrej me http://localhost, respektivisht me domain kur ta kemi bërë upload aplikacionin në Web server.
Funksioni HandleFunc nga pakoja http, shërben si një ruter bazik.
Si parametër të parë e shënojmë rutën e që në rastin konkret është “/” që d.m.th. home page, respektivisht faqja kryesore që hapet kur e shënojmë vetëm domainin, në rastin konkret http://localhost:8080.
Si parametër të dytë e shënojmë emrin e funksionit i cili thirret, dhe i cili do ta bëjë kthimin e përgjigjes (Response), në rastin konkret homeHandler.
Funksioni homeHandler (sikurse edhe funksionet tjera që do t’i definojmë te rutat tjera), i ka dy parametra; w të tipit http.ResponseWriter dhe r të tipit pointer i http.Request :
- w http.ResponseWriter
- r *http.Request
Nëse ruta ka parametra, ato lexohen nga http.Request, ndërsa në http.ResponseWriter dërgohet përmbajtja e dëshiruar në browser, zakonisht të dhëna në formatin HTML ose JSON.
Nga http.Request lexohen edhe të dhënat e fushave të formularit, nëse ajo rutë është thirrur si “action” i një formulari.
<I Natyrisht, emrat e variablave nuk kanë rëndësi, me rëndësi janë tipet të cilat duhet të jenë http.ResponseWriter dhe *http.Request.
Funksioni ListenAndServe() e starton serverin në portin e cekur. Prej momentit kur fillon ekzekutimi i këtij funksioni, ne mund t’i qasemi serverit nëpërmes browserit. Vetë programi do të ngelet duke u ekzekutuar deri sa ta ndërprejmë me Ctrl-C. Asgjë nuk do të ekzekutohet pas këtij rreshti (rreshti 11), përveç nëse paraqitet ndonjë gabim, me ç’rast ai gabim raportohet në konzolë (rreshtat 12-14).
Për këtë shkak, të gjitha definicionet e rutave duhet të bëhet para thirrjes së ListenAndServe().
Meqë në këtë program konkret ende nuk kemi shënuar funksione që dërgojnë përgjigje në http.Response(), kur e hapim adresën në browser, browseri do të shfaqë faqe të zbrazët.
%{
Let us now extend the above example to add more functionality. The
functionality that we want to add is:
- Register a user
- Unregister a user
- Get List of Registered users
In other words, we are building out a full API Server out there. Read on.
To keep the example simple we will not use a database to hold the list of
registered users, but instead will use a map to track registered users.
The first thing that we need to do is define a structfor a user as given below:
type user struct {
Name string
Age string
} F
or example purpose, we have used only 2 fields for user: name and age . Both
of these fields are of string type.
As discussed above we will use map to hold registered user.
var usersMap map [ string ]user
func init() {
usersMap = make ( map [ string ]user)
}
W
e will use name of the user as the key, hence we defined the map with key as
string and value as user (struct) and initialized this map in init() func which will
be called before main func is called.
Now we need to define handlersfor handling functionality like register user,
un-register user and get list of registered users. We will define 3 different
handlersfor these 3 functionalities.
Register User
func registerUserHandler(w http.ResponseWriter, r *http.Request){
userName := r.URL.Query().Get( “uname” )
if ( len (userName) == 0 ){
w.Write([] byte ( “User Name is mandatory. Pass value for uname” ))
return
} ag
e := r.URL.Query().Get( “age” )
if ( len (age) == 0 ){
w.Write([] byte ( “User Name is mandatory. Pass value for age” ))
return
} us
ersMap[userName] = user
w.Write([] byte ( “Successfully registered User Name: “ + userName))
} If
you are familiar with HTTP protocol, you will notice that we are using the GET
method for all the URL endpoints that we have defined so far. As a result, we are
going to query the HTTP request string for parameters that are passed as part of
the URL. For example : username and age of the user to be registered.
We first fetch “ uname ” from the query to check if it is not empty. If empty we
write back to user saying “User Name is mandatory…..” . Similarly “ age” is
mandatory too and we check for “age” parameter in query too. If both these
parameters are available and not empty, we create new instance of struct user
and add it to the mapwith username as the key. We then write back success
message to indicate that user was successfully registered.
Now let us quickly define other two handler for getting the list of registered
users and unregister user.
Get list Of Registered Users:
func getRegisteredUsersHandler(w http.ResponseWriter, r *http.Request){
regUser := ““ ;
for _, user := range usersMap {
if ( len (user.Name) > 0 ){
regUser = regUser + “\n” + user.Name
}
} w.
Write([] byte ( “Registered Users are : “ + regUser))
} U
nregister User:
func unRegisteredUsersHandler(w http.ResponseWriter, r *http.Request){
userName := r.URL.Query().Get( “uname” )
if ( len (userName) == 0 ){
w.Write([] byte ( “User Name is mandatory. Pass value for uname” ))
return
} de
lete (usersMap, userName)
w.Write([] byte ( “Successfully un-registered User : “ + userName))
} A
fter defining the handlers we need to configure them or rather map themto the URL
patternsagainst which they will be executed.
http.HandleFunc( “/regUser” , registerUserHandler)
http.HandleFunc( “/getRegUser” , getRegisteredUsersHandler)
http.HandleFunc(“ /unRegUser “, unRegisteredUsersHandler)
Here is the full code:
package main
import (
“fmt”
“net/http”
) c
onst PORT = “8080”
type user struct {
Name string
Age string
} v
ar usersMap map[string]user
func init() {
usersMap = make(map[string]user)
}
func checkErrorAndPanic(err error) {
if err != nil {
panic(err)
}
} f
unc main() {
fmt.Println(“Attempt to start server at port ….” + PORT)
http.HandleFunc(“/regUser”, registerUserHandler)
http.HandleFunc(“/getRegUser”, getRegisteredUsersHandler)
http.HandleFunc(“/unRegUser”, unRegisteredUsersHandler)
err := http.ListenAndServe(“:”+PORT, nil)
checkErrorAndPanic(err)
} f
unc registerUserHandler(w http.ResponseWriter, r *http.Request) {
userName := r.URL.Query().Get(“uname”)
if len(userName) == 0 {
w.Write([]byte(“User Name is mandatory. Pass value for
uname”))
return
} a
ge := r.URL.Query().Get(“age”)
if len(age) == 0 {
w.Write([]byte(“User Name is mandatory. Pass value for
age”))
return
} u
sersMap[userName] = user
w.Write([]byte(“Successfully registered User Name: “ +
userName))
} f
unc getRegisteredUsersHandler(w http.ResponseWriter, r
*http.Request) {
regUser := “”
for _, user := range usersMap {
if len(user.Name) > 0 {
regUser = regUser + “\n” + user.Name
}
} w
.Write([]byte(“Registered Users are : “ + regUser))
} f
unc unRegisteredUsersHandler(w http.ResponseWriter, r
*http.Request) {
userName := r.URL.Query().Get(“uname”)
if len(userName) == 0 {
w.Write([]byte(“User Name is mandatory. Pass value for
uname”))
return
} d
elete(usersMap, userName)
w.Write([]byte(“Successfully un-registered User : “ +
userName))
}
%}