Go言語とPostgreSQLでハンバーガー予約のAPIを作ってみる：まずGET

作成：2023年8月8日
[前回行ったPostgreSQLの練習の結果](https://qiita.com/RYO_/items/265f6cb3e0834a116118)を使ってAPIを作ってみます。まずはGETから作ってみます。
[今回のコードのGithub置き場](https://github.com/ryoyuki6/api_sql20230730/tree/add_get20230808)です。

# PostgrSQL で DB を準備

## docker-compose.yaml を作成

```:docker-compose.yaml
# docker-composeで使用するバージョンを定義しています。
version: '3.9'
# サービス (コンテナ) を定義します。
services:
  # 今回は postgres をサービスとして定義しました。
  postgres:
    # Docker Image は postgres:12-alpine を使います。postgres:12-alpine は postgres:12 と比較して、イメージサイズが小さくなっています。
    image: postgres:12-alpine
    # コンテナの名前を指定します。
    container_name: postgres20230730
    # 環境変数を設定します。
    environment:
      - POSTGRES_USER=root
      - POSTGRES_PASSWORD=root
      - POSTGRES_DB=testdb
    # データの永続化
    volumes:
      # postgresボリュームを/var/lib/postgresql/dataにマウントします
      - postgres20230730:/var/lib/postgresql/data
    # ポートの指定（HOST:CONTAINER）
    ports:
      - 5432:5432
# データの永続化：ボリュームを作成します。
volumes:
  postgres20230730:
```

## コンテナ立ち上げ

コンテナを立ち上げて、PostgrSQL を確認します。

```:MacBook Terminal
% docker-compose up -d

% docker ps
CONTAINER ID   IMAGE                        COMMAND                   CREATED          STATUS         PORTS                                       NAMES
af3bcf786dde   postgres:12-alpine           "docker-entrypoint.s…"   10 seconds ago   Up 9 seconds   0.0.0.0:5432->5432/tcp, :::5432->5432/tcp   postgres20230730

 % docker exec -it postgres20230730 bash
af3bcf786dde:/# psql -l
                             List of databases
   Name    | Owner | Encoding |  Collate   |   Ctype    | Access privileges 
-----------+-------+----------+------------+------------+-------------------
 postgres  | root  | UTF8     | en_US.utf8 | en_US.utf8 | 
 template0 | root  | UTF8     | en_US.utf8 | en_US.utf8 | =c/root          +
           |       |          |            |            | root=CTc/root
 template1 | root  | UTF8     | en_US.utf8 | en_US.utf8 | =c/root          +
           |       |          |            |            | root=CTc/root
 testdb    | root  | UTF8     | en_US.utf8 | en_US.utf8 | 
(4 rows)
```

## PostgreSQL に接続してテーブル作成

PostgreSQL に接続します。

```:MacBook Terminal
af3bcf786dde:/# psql -h localhost -p 5432 -U root -d testdb
psql (12.15)
Type "help" for help.

testdb=# 
```

テーブルを作成します。

```:MacBook Terminal
testdb=# create table order_list (id serial primary key, order_name varchar(255), number_of_orders integer);
CREATE TABLE

testdb=# INSERT INTO order_list VALUES (1, 'hamburger', 11);
INSERT 0 1
testdb=# INSERT INTO order_list VALUES (2, 'cheeseburger', 22);
INSERT 0 1
testdb=# INSERT INTO order_list VALUES (3, 'big_mac', 33);
INSERT 0 1

testdb=# SELECT * FROM order_list;
 id |  order_name  | number_of_orders 
----+--------------+------------------
  1 | hamburger    |               11
  2 | cheeseburger |               22
  3 | big_mac      |               33
(3 rows)
```

# Go のコード準備

```:main.go
package main

import (
	"database/sql"
	"fmt"
	_ "github.com/lib/pq"

	"bytes"
	"encoding/json"
	"log"
	"net/http"
)

var DB *sql.DB

func init() {
	var err error
	DB, err = sql.Open("postgres", "user=root dbname=testdb password=root sslmode=disable")
	if err != nil {
		panic(err)
	}
}

type Order struct {
	Id				int		`json:"id"`
	OrderName		string	`json:"order_name"`
	NumberOfOrders	int		`json:"number_of_orders"`
}

func main() {
	handler1 := func (w http.ResponseWriter, r *http.Request)  {
		var  buf bytes.Buffer
		enc := json.NewEncoder(&buf)

		orders := []Order{}

		rows, err := DB.Query("SELECT * FROM order_list ORDER BY id")
		if err != nil {
			return
		}
		for rows.Next() {
			m := Order{}
			rows.Scan(&m.Id, &m.OrderName, &m.NumberOfOrders)
			fmt.Println(m)
			orders = append(orders, m)
		}

		if err2 := enc.Encode(&orders); err2 != nil {
			log.Fatal(err)
		}

		w.Header().Set("Access-Control-Allow-Origin","http://localhost:3000")

		_, err3 := fmt.Fprint(w, buf.String())
		if err3 != nil {
			return
		}
	}

	http.HandleFunc("/order", handler1)
	log.Fatal(http.ListenAndServe(":8000", nil))
}
```

# goモジュールのインストール

```:MacBook Terminal
% go mod init example.com/api_sql
go: creating new go.mod: module example.com/api_sql
go: to add module requirements and sums:
	go mod tidy

% go mod tidy
go: finding module for package github.com/lib/pq
go: found github.com/lib/pq in github.com/lib/pq v1.10.9
```

# 実行

main.go を実行します。
```:MacBook Terminal
ryo@Ryo-MacBook-Pro api_sql20230730 % go run main.go 
{1 hamburger 11}
{2 cheeseburger 22}
{3 big_mac 33}
```

別のターミナルから curl します。
```:MacBook Terminal
% curl http://localhost:8000/order
[{"id":1,"order_name":"hamburger","number_of_orders":11},{"id":2,"order_name":"cheeseburger","number_of_orders":22},{"id":3,"order_name":"big_mac","number_of_orders":33}]
```
API から GET できました。


# 後片付け： PostgreSQL のコンテナを落とします

```:MacBook Terminal
 % docker-compose down
[+] Running 2/2
 ✔ Container postgres20230730       Removed                                                                                                                          0.2s 
 ✔ Network api_sql20230730_default  Removed    
```

次は、他の CRUD処理を追加していきたいと思います。

# 参考
[Go言語の基本文法3(配列, スライス, マップ, 構造体)](https://osamu-tech-blog.com/go-basic-grammar3/)
[【Go言語】構造体を要素に持つスライスの作成・要素追加・初期化方法まとめ](https://nishinatoshiharu.com/initialize-structure-slice/)
[しまぶーのIT大学](https://www.youtube.com/@shimabu_it)