【Go言語】簡単なウェブアプリケーションの作成

Goで作成されたアプリケーションは配布が容易で、特にコマンドラインツールの実装に優れているが、ウェブアプリケーションの作成にも適している。

## 基礎的なウェブサービス

`http://localhost:8080/hello`にアクセスすると`Hello, World`を返すウェブアプリを作成する

### サンプル
```go
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"

	"github.com/rs/zerolog/log"
)

func main() {
	// URLごとの処理を登録
	http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello, World")
		log.Info().Msg("receive hello world request")
	})

	// サーバーの起動を画面に表示
	fmt.Println("Start listening at :8080")

	// サーバーの起動
	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		// エラー処理
		fmt.Fprintf(os.Stderr, "")
		io.WriteString(os.Stderr, err.Error())
		os.Exit(1)
	}
}

```

### コードの解説
1. **URLごとの処理の登録** (`http.HandleFunc`)
    `/hello` というパスにアクセスがあった際に、`Hello, World` という文字列を返す処理を登録している。
1. **サーバーの起動** (`http.ListenAndServe`)
    実際にサーバーを起動するために http.ListenAndServe 関数を使用する。この例ではポート 8080 を使用している。
1. **エラーハンドリング**
    サーバーの起動に失敗した場合（例えば、ポートが既に使用されているなど）には、エラーメッセージを表示してプログラムを終了する。

### 実行と動作確認
以下のコマンドで起動する
```bash
$ go run main.go
```

ブラウザや`curl`で`http://localhost:8080/hello`にアクセスすると`Hello, World`が返される
```bash
curl -X GET http://localhost:8080/hello
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1719666/9f6ef2cd-14b9-a9c9-8865-f65d24e2c835.png)


## CRUD操作を行うウェブサービス

機能を拡張して、**CRUD操作**（作成(Create)、読み取り(Read)、更新(Update)、削除(Delete)）が行えるようにする。
簡単なユーザ管理を行うウェブサービスを実装する。

### サンプル

```go
package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "strconv"
    "strings"
)

type User struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}

var users = []User{
    {ID: 1, Name: "山田太郎"},
    {ID: 2, Name: "鈴木一郎"},
}

func main() {
    http.HandleFunc("/users", usersHandler)
    http.HandleFunc("/user/", userHandler)

    fmt.Println("Server is running at :8080")
    http.ListenAndServe(":8080", nil)
}

func usersHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case "GET":
        json.NewEncoder(w).Encode(users)
    case "POST":
        var user User
        json.NewDecoder(r.Body).Decode(&user)
        users = append(users, user)
        json.NewEncoder(w).Encode(user)
    }
}

func userHandler(w http.ResponseWriter, r *http.Request) {
    parts := strings.Split(r.URL.Path, "/")
    if len(parts) < 3 {
        http.NotFound(w, r)
        return
    }

    userID, err := strconv.Atoi(parts[2])
    if err != nil {
        http.Error(w, "Invalid user ID", http.StatusBadRequest)
        return
    }

    switch r.Method {
    case "GET":
        for _, user := range users {
            if user.ID == userID {
                json.NewEncoder(w).Encode(user)
                return
            }
        }
        http.NotFound(w, r)
    case "PUT":
        var updatedUser User
        json.NewDecoder(r.Body).Decode(&updatedUser)
        for i, user := range users {
            if user.ID == userID {
                users[i] = updatedUser
                json.NewEncoder(w).Encode(updatedUser)
                return
            }
        }
        http.NotFound(w, r)
    case "DELETE":
        for i, user := range users {
            if user.ID == userID {
                users = append(users[:i], users[i+1:]...)
                fmt.Fprintf(w, "Deleted")
                return
            }
        }
        http.NotFound(w, r)
    }
}

```
### コードの解説

* **ユーザーの作成 (Create)**
    POST リクエストを `/users` に送ると、新しいユーザーが追加される。
* **ユーザー情報の読み取り (Read)**
    GET リクエストを `/users` または `/user/{id}` に送ると、全ユーザーまたは特定のユーザーの情報が取得できる。
* **ユーザー情報の更新 (Update)**
    PUT リクエストを `/user/{id}` に送ると、指定されたIDのユーザー情報を更新できる。
* **ユーザーの削除 (Delete)**
    DELETE リクエストを `/user/{id}` に送ると、指定されたIDのユーザーを削除できる

### 実行方法

### 実行と動作確認
以下のコマンドで起動する
```bash
$ go run main.go
```

ブラウザや`curl`でリクエストすると操作できる。

#### 全ユーザを取得するリクエスト
```bash
curl -X GET http://localhost:8080/users
```
#### レスポンス
```bash
[{"id":1,"name":"山田太郎"},{"id":2,"name":"鈴木一郎"}]
```

## 参考

https://www.oreilly.co.jp/books/9784873119694/