Trong bài viết trước, chúng ta đã xây dựng một command line application dùng để hiển thị horoscope. Hôm nay chúng ta cũng làm tương tự, thậm chí là cải tiến lại application trước để xây dựng một webservice cung cấp thông tin horoscope daily.
Nhưng chúng ta không muốn phải viết lại code, chúng ta muốn reuse lại một phần code trong cli application. Vậy nên plan như sau. Trước tiên sẽ cần phải tách cli application ra thành hai phần, một module xử lý nội dung horoscope và main module dùng để giao tiếp với người dùng.
Tách module horoscope
Tạo một project mới với file horoscope có nội dung như sau :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
package gohoro
import (
"strings"
"fmt"
"net/http"
"io/ioutil"
"regexp"
)
var endpoint string = "http://www.horoscope.com/us/horoscopes/general/horoscope-general-daily-today.aspx";
var SignMap = map[string]int{
"ARIES":1,
"TAURUS":2,
"GEMINI":3,
"CANCER":4,
"LEO":5,
"VIRGO":6,
"LIBRA":7,
"SCORPIO":8,
"SAGITTARIUS":9,
"CAPRICORN":10,
"AQUARIUS":11,
"PISCES":12,
}
func GetSignNameById(signId int) string{
for name,id := range SignMap{
if(id == signId){
return name
}
}
return ""
}
func GetHoroscope(signName string) (string, error) {
signName = strings.ToUpper(signName)
signId, ok := SignMap[signName];
if !ok {
return "", fmt.Errorf("I don't know anything about this sign.")
}
url := fmt.Sprintf("%s?sign=%d", endpoint, signId)
resp, err := http.Get(url);
if err != nil {
return "", fmt.Errorf("Can not get data");
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("Can not read body")
}
content := string(body)
r := regexp.MustCompile("(?s)<div class=\"block-horoscope-text[^>]*\">([^/]*)</div>")
loginResultSubmatch := r.FindStringSubmatch(content)
if loginResultSubmatch == nil {
return "", fmt.Errorf("Can not read data.")
}
return strings.TrimSpace(loginResultSubmatch[1]), nil
}
|
Giờ tạo project horoscopecli với file main.go có nội dung như sau :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
package main
import (
"flag"
"fmt"
"github.com/nguyenvanduocit/gohoro"
)
func main() {
var signName string
flag.StringVar(&signName, "sign", "", "Sign name")
flag.Parse()
if signName == "" {
var signId int = -1
for k, v := range gohoro.SignMap {
fmt.Println(k, "--", v)
}
isFirst:=true
for signName == ""{
if !isFirst{
fmt.Print("This sign is not exist, please type a number from the list below :")
}else{
isFirst = false;
fmt.Print("Please choose a horoscope (number):")
}
fmt.Scanf("%d", &signId)
if signId==0{
return
}
signName = gohoro.GetSignNameById(signId)
}
}
fmt.Println("Please wait ...")
content, err := gohoro.GetHoroscope(signName)
if err != nil {
fmt.Println(err)
}
fmt.Println(content)
}
|
Vậy là thành công, khá đơn giản, và giờ bạn có thể share package của bạn cho bạn bè sử dụng. Nhưng nhớ dụ họ thật kỹ, vì thường thì cái này chẳng có giá trị gì nhiều.
Tạo Webservice
Cũng giống như bên cli, nhưng khác ở chỗ interface, giờ chúng ta sẽ sử dụng http server để giao tiếp với người dùng, nhưng phần xử lý thì vẫn là package lúc nảy chúng ta vừa tách
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
package main
import (
"github.com/nguyenvanduocit/gohoro"
"net/http"
"github.com/gorilla/mux"
"log"
"encoding/json"
"flag"
"fmt"
)
type Response struct {
Success bool `json:"success"`
Content string `json:"content"`
}
func DailyHoro(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
sign := vars["sign"]
result, err := gohoro.GetHoroscope(sign)
if err != nil {
json.NewEncoder(w).Encode(Response{Success:false, Content:"Can not get data."})
}else if(result == ""){
errorMessage := Response{Success:false, Content:"Sign not found"}
json.NewEncoder(w).Encode(errorMessage)
}else{
json.NewEncoder(w).Encode(Response{Success:true, Content:result})
}
}
func main() {
var ip, port string
flag.StringVar(&ip, "ip", "", "ip")
flag.StringVar(&port, "port", "8080", "Port")
flag.Parse()
address := fmt.Sprintf("%s:%s", ip, port)
router := mux.NewRouter().StrictSlash(true)
router.HandleFunc("/{sign}/daily", DailyHoro)
log.Fatal(http.ListenAndServe(address, router))
}
|
Ở đây mình sử dụng mux package để làm server. và cấu thúc route của daily horoscope là
1
|
/{sign}/daily
|
Mình làm vậy vì mình muốn phát triển thêm một vài tính năng khác chứ không phải chỉ có mỗi daily horoscope. Mặc dù mình không phải là thích horoscope, nhưng mình muốn lấy nó làm demo.
Giờ để run nó, bạn chạy:
1
2
|
cd gowebservice
go run main.go -ip=117.0.0.1 -port=8080
|
Để build thì dùng lệnh:
1
|
go build
|
Giờ bạn có thể thử get, post vào url :
1
|
http://localhost:8080/leo/daily
|
Bạn sẽ thấy thông tin về cung hoàn đạo đó.
Lời kết
Suy cho cùng, thì đây cũng chỉ là một bài tập nhỏ mà chúng ta có thể làm để cải thiện dần dần kiến thức về go mà thôi, thực tế thì nó không có giá trị nhiều. Nhưng khác mình, trong lúc làm ví dụ này, các bạn có thể tìm hiểu kỹ hơn về mux, tại sao dùng mux mà không dùng http mặc định. Đó hẳn là còn nhiều thứ để các bạn tìm hiểu.
0 comments:
Post a Comment