--- title: 【解答】Go言語 初心者向けハンズオン tags: Go author: yukpiz slide: false --- ※これは解答です。どうしても課題が解けない場合、ご利用ください。 # 練習問題 #1: FizzBuzz APIを作ろう ```go package main import ( "fmt" "log" "net/http" "strconv" "github.com/julienschmidt/httprouter" ) func FizzBuzz(w http.ResponseWriter, r *http.Request, p httprouter.Params) { num, err := strconv.Atoi(p.ByName("num")) if err != nil || num < 1 { http.Error(w, fmt.Sprintf("%d Bad Request", http.StatusBadRequest), http.StatusBadRequest) return } var str string for i := 1; i <= num; i++ { if i%15 == 0 { str += fmt.Sprintf("%d: %s\n", i, "FizzBuzz!") } else if i%5 == 0 { str += fmt.Sprintf("%d: %s\n", i, "Buzz") } else if i%3 == 0 { str += fmt.Sprintf("%d: %s\n", i, "Fizz") } else { str += fmt.Sprintf("%d:\n", i) } } fmt.Fprintf(w, str) } func main() { router := httprouter.New() router.GET("/FizzBuzz/:num", FizzBuzz) err := http.ListenAndServe(":8080", router) if err != nil { log.Fatal(err) } } ``` # 練習問題 #2: プロフィール取得APIを作ろう ```go package main import ( "encoding/json" "fmt" "log" "net/http" "github.com/julienschmidt/httprouter" ) type Profile struct { Name string `json:"name"` Age int `json:"age"` Gender string `json:"gender"` FavoriteFoods []string `json:"favorite_foods"` } var bob Profile = Profile{ Name: "Bob", Age: 25, Gender: "Man", FavoriteFoods: []string{"Hamburger", "Cookie", "Chocolate"}, } var alice Profile = Profile{ Name: "Alice", Age: 24, Gender: "Woman", FavoriteFoods: []string{"Apple", "Orange", "Melon"}, } func GetProfile(w http.ResponseWriter, r *http.Request, p httprouter.Params) { name := p.ByName("name") var resProfile Profile if name == "Bob" { resProfile = bob } else if name == "Alice" { resProfile = alice } else { http.Error(w, fmt.Sprintf("%d Not Found", http.StatusNotFound), http.StatusNotFound) return } bytes, err := json.Marshal(resProfile) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) } fmt.Fprintf(w, string(bytes)) } func main() { router := httprouter.New() router.GET("/Profile/:name", GetProfile) err := http.ListenAndServe(":8080", router) if err != nil { log.Fatal(err) } } ``` # 練習問題 #3: プロフィール保存APIを作ろう ```go package main import ( "encoding/json" "fmt" "io/ioutil" "log" "net/http" "github.com/julienschmidt/httprouter" ) type Profile struct { Name string `json:"name"` Age int `json:"age"` Gender string `json:"gender"` FavoriteFoods []string `json:"favorite_foods"` } var savedProfiles map[string]Profile = map[string]Profile{} func PostProfile(w http.ResponseWriter, r *http.Request, p httprouter.Params) { defer r.Body.Close() body, err := ioutil.ReadAll(r.Body) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } var reqProfile Profile err = json.Unmarshal(body, &reqProfile) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } if reqProfile.Name == "" { http.Error(w, "name is required.", http.StatusBadRequest) return } savedProfiles[reqProfile.Name] = reqProfile fmt.Fprintf(w, fmt.Sprintf("%d Created", http.StatusCreated)) } func main() { router := httprouter.New() router.POST("/Profile", PostProfile) err := http.ListenAndServe(":8080", router) if err != nil { log.Fatal(err) } } ``` # 練習問題 #4: プロフィール取得APIを拡張しよう ```go package main import ( "encoding/json" "fmt" "io/ioutil" "log" "net/http" "github.com/julienschmidt/httprouter" ) type Profile struct { Name string `json:"name"` Age int `json:"age"` Gender string `json:"gender"` FavoriteFoods []string `json:"favorite_foods"` } var savedProfiles map[string]Profile = map[string]Profile{} func PostProfile(w http.ResponseWriter, r *http.Request, p httprouter.Params) { defer r.Body.Close() body, err := ioutil.ReadAll(r.Body) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } var reqProfile Profile err = json.Unmarshal(body, &reqProfile) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } if reqProfile.Name == "" { http.Error(w, "name is required.", http.StatusBadRequest) return } savedProfiles[reqProfile.Name] = reqProfile fmt.Fprintf(w, fmt.Sprintf("%d Created", http.StatusCreated)) } func GetProfile(w http.ResponseWriter, r *http.Request, p httprouter.Params) { name := p.ByName("name") resProfile, found := savedProfiles[name] if !found { http.Error(w, fmt.Sprintf("%d Not Found", http.StatusNotFound), http.StatusNotFound) return } bytes, err := json.Marshal(resProfile) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) } fmt.Fprintf(w, string(bytes)) } func main() { router := httprouter.New() router.POST("/Profile", PostProfile) router.GET("/Profile/:name", GetProfile) err := http.ListenAndServe(":8080", router) if err != nil { log.Fatal(err) } } ``` # 練習問題 #5: APIクライアントを作ろう **get_client.go** ```go package main import ( "flag" "fmt" "io/ioutil" "log" "net/http" ) func main() { name := flag.String("name", "", "Name") flag.Parse() resp, err := http.Get(fmt.Sprintf("http://localhost:8080/Profile/%s", *name)) if err != nil { log.Fatal(err) } defer resp.Body.Close() bytes, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Println(string(bytes)) } ``` **post_client.go** ```go package main import ( "bytes" "encoding/json" "flag" "fmt" "io/ioutil" "log" "net/http" "strings" ) type Profile struct { Name string `json:"name"` Age int `json:"age"` Gender string `json:"gender"` FavoriteFoods []string `json:"favorite_foods"` } func main() { profile := parseArgs() fmt.Printf("%+v\n", profile) jsonStr, err := json.Marshal(profile) if err != nil { log.Fatal(err) } req, err := http.NewRequest("POST", "http://localhost:8080/Profile", bytes.NewBuffer([]byte(jsonStr))) if err != nil { log.Fatal(err) } client := &http.Client{} resp, err := client.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) fmt.Println(string(body)) } func parseArgs() Profile { name := flag.String("name", "", "Name") age := flag.Int("age", 0, "Age") gender := flag.String("gender", "", "Gender") foods := flag.String("foods", "", "Favorite foods") flag.Parse() return Profile{ Name: *name, Age: *age, Gender: *gender, FavoriteFoods: strings.Split(*foods, " "), } } ``` # 練習問題 #6: HTMLを返そう **index.html.tpl** ```html

Hello golang!

Alice
Bob
``` **profile.html.tpl** ```html

Hello golang!

Name: {{ .Name }}
Age: {{ .Age }}
Gender: {{ .Gender }}
Favorite Foods: {{ .FavoriteFoods }}
``` **html_server.go** ```go package main import ( "fmt" "html/template" "log" "net/http" "github.com/julienschmidt/httprouter" ) type Profile struct { Name string `json:"name"` Age int `json:"age"` Gender string `json:"gender"` FavoriteFoods []string `json:"favorite_foods"` } var bob Profile = Profile{ Name: "Bob", Age: 25, Gender: "Man", FavoriteFoods: []string{"Hamburger", "Cookie", "Chocolate"}, } var alice Profile = Profile{ Name: "Alice", Age: 24, Gender: "Woman", FavoriteFoods: []string{"Apple", "Orange", "Melon"}, } func Index(w http.ResponseWriter, r *http.Request, p httprouter.Params) { t := template.Must(template.ParseFiles("templates/index.html.tpl")) err := t.ExecuteTemplate(w, "index.html.tpl", nil) if err != nil { log.Fatal(err) } } func GetProfile(w http.ResponseWriter, r *http.Request, p httprouter.Params) { name := p.ByName("name") var resProfile Profile if name == "Bob" { resProfile = bob } else if name == "Alice" { resProfile = alice } else { http.Error(w, fmt.Sprintf("%d Not Found", http.StatusNotFound), http.StatusNotFound) return } t := template.Must(template.ParseFiles("templates/profile.html.tpl")) err := t.ExecuteTemplate(w, "profile.html.tpl", resProfile) if err != nil { log.Fatal(err) } } func main() { router := httprouter.New() router.GET("/", Index) router.GET("/profile/:name", GetProfile) err := http.ListenAndServe(":8080", router) if err != nil { log.Fatal(err) } } ```