GOでAPI作成．PostgreSQL+GIN

# go初期設定
go言語のインストールは<a href=https://go.dev/dl/>こちら</a>から

インストール出来たら．
```
mkdir myproject
```
```
cd myproject
```
```
go mod init example.com/myproject
```
```
go get -u github.com/gin-gonic/gin
```
```
go get -u github.com/joho/godotenv
```
```
go get -u github.com/jackc/pgx/v4 
```
# ファイル構造
```
C:.
│  .env
│  go.mod
│  go.sum
│  main.go
│
├─config
│      config.go
│
├─controllers
│      user_controller.go
│
├─database
│      database.go
│
├─models
│      user.go
│
├─repositories
│      user_repository.go
│
├─routers
│      routre.go
│
└─services
        user_service.go
```
# 実際のコード

### main.go

main.goは今回のAPIのエントリーポイントの役割をしている．

```main.go
package main

import (
	"log"

	"example.com/myproject/config"
	"example.com/myproject/database"
	"example.com/myproject/routers"
	"github.com/gin-gonic/gin"
)

func main() {
	// 環境変数の読み込み
	config.LoadConfig()

	// データベースの初期化
	database.InitDB()

	// Ginのデフォルトのルーターを作成
	r := gin.Default()

	// ルーティングの設定
	routers.SetupRouter(r)

	// サーバーをポート8000で起動
	r.Run(":8000")

	// サーバーの起動をログに記録
	log.Println("Server started on :8000")
}
```
### config.go

config.goは、アプリケーションの設定を管理するためのものであり，今回は.envファイルから環境変数を読み込み、アプリケーションで使用できるようにしている．

```config.go
package config

import (
	"log"
	"os"

	"github.com/joho/godotenv"
)

// LoadConfig は.envファイルから設定をロードする
func LoadConfig() {
	err := godotenv.Load()
	if err != nil {
		log.Fatal("Error loading .env file")
	}
}

// GetEnv は環境変数を取得する
func GetEnv(key string) string {
	return os.Getenv(key)
}
```

### user_controller.go

user_controller.goは，ユーザーからのHttpリクエストを処理するものである．

```user_controller.go
package controllers

import (
	"net/http"

	"example.com/myproject/models"
	"example.com/myproject/services"
	"github.com/gin-gonic/gin"
)

// 全てのユーザーデータの取得
func GetUsers(c *gin.Context) {
	users, err := services.GetUsers()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, users)
}

// 指定されたIDのユーザーデータの取得
func GetUser(c *gin.Context) {
	id := c.Param("id")
	user, err := services.GetUser(id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, user)
}

// 新しいユーザーデータの作成
func CreateUser(c *gin.Context) {
	var user models.User
	if err := c.BindJSON(&user); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if err := services.CreateUser(user); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusCreated, gin.H{})
}

// 指定されたIDのユーザーデータの更新
func UpdateUser(c *gin.Context) {
	id := c.Param("id")
	var user models.User
	if err := c.BindJSON(&user); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if err := services.UpdateUser(id, user); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{})
}

// 指定されたIDのユーザーデータの削除
func DeleteUser(c *gin.Context) {
	id := c.Param("id")
	if err := services.DeleteUser(id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{})
}

```

### database.go

database.goは，データベースとの接続と必要な場合はテーブルの作成をするものである．

```database.go
package database

import (
	"context"
	"log"

	"example.com/myproject/config"
	"github.com/jackc/pgx/v4"
)

// DB はデータベースへの接続を保持します。
var DB *pgx.Conn

// InitDB はデータベースを初期化し、接続を確立します。
func InitDB() {
	var err error
 
    // DATABASE_URL環境変数からdatabaseのURIを取得
	dsn := config.GetEnv("DATABASE_URL")

    // pgxライブラリを使用して、DSNを使用してデータベースに接続
	DB, err = pgx.Connect(context.Background(), dsn)
 
	if err != nil {
		log.Fatalf("Unable to parse DSN: %v\n", err)
	}

    // ユーザーのテーブルが存在しない場合は作成
	createTableSQL := `
    CREATE TABLE IF NOT EXISTS users (
        id SERIAL PRIMARY KEY,
        name TEXT,
        email TEXT
    );`
	_, err = DB.Exec(context.Background(), createTableSQL)
	if err != nil {
		log.Fatalf("Failed to create table: %v\n", err)
	}
}

```

### user.go

user.goは，User構造体を定義し，JSON形式での表現とデータベース内のカラムとのマッピングを行うためのタグも含めている．

```user.go
package models

// User はユーザーを表すデータ構造体
type User struct {
    ID    int    `json:"id" db:"id"`       // ユーザーのID
    Name  string `json:"name" db:"name"`   // ユーザーの名前
    Email string `json:"email" db:"email"` // ユーザーのメールアドレス
}
```

### user_repositories.go

user_repositories.goは，ユーザーに関するデータベース操作を行うためのリポジトリを定義したもので，データベースの操作を行うもの．

```user_repositories.go
package repositories

import (
	"context"

	"example.com/myproject/database"
	"example.com/myproject/models"
)

// すべてのユーザーをデータベースから取得
func GetAllUsers() ([]models.User, error) {
	var users []models.User
	query := "SELECT id, name, email FROM users"
	rows, err := database.DB.Query(context.Background(), query)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	for rows.Next() {
		var user models.User
		if err := rows.Scan(&user.ID, &user.Name, &user.Email); err != nil {
			return nil, err
		}
		users = append(users, user)
	}

	return users, nil
}

// 指定されたIDのユーザーをデータベースから取得
func GetUser(id string) (models.User, error) {
	var user models.User
	query := "SELECT id, name, email FROM users WHERE id = $1"
	err := database.DB.QueryRow(context.Background(), query, id).Scan(&user.ID, &user.Name, &user.Email)
	if err != nil {
		return models.User{}, err
	}

	return user, nil
}

// 新しいユーザーをデータベースに作成
func CreateUser(user models.User) error {
	query := "INSERT INTO users (name, email) VALUES ($1, $2)"
	_, err := database.DB.Exec(context.Background(), query, user.Name, user.Email)
	if err != nil {
		return err
	}

	return nil
}

// 指定されたIDのユーザーをデータベースで更新
func UpdateUser(id string, user models.User) error {
	query := "UPDATE users SET name = $1, email = $2 WHERE id = $3"
	_, err := database.DB.Exec(context.Background(), query, user.Name, user.Email, id)
	if err != nil {
		return err
	}

	return nil
}

// 指定されたIDのユーザーをデータベースから削除
func DeleteUser(id string) error {
	query := "DELETE FROM users WHERE id = $1"
	_, err := database.DB.Exec(context.Background(), query, id)
	if err != nil {
		return err
	}

	return nil
}
```

### router.go

router.goは，SetupRouter関数がGinエンジンを受け取り、HTTPリクエストとそれに対応するコントローラーの関連付けを行うものである．

```router.go
package routers

import (
	"example.com/myproject/controllers"
	"github.com/gin-gonic/gin"
)

// ルーティングを設定
func SetupRouter(r *gin.Engine) {

    // GETリクエストでのユーザー取得エンドポイントを設定し、controllers.GetUsers関数を実行する
	r.GET("/users", controllers.GetUsers)

    // GETリクエストでの特定のユーザー取得エンドポイントを設定し、controllers.GetUser関数を実行する
	r.GET("/users/:id", controllers.GetUser)

    // POSTリクエストでのユーザー作成エンドポイントを設定し、controllers.CreateUser関数を実行する
	r.POST("/users", controllers.CreateUser)

    // PUTリクエストでのユーザー更新エンドポイントを設定し、controllers.UpdateUser関数を実行する
	r.PUT("/users/:id", controllers.UpdateUser)

    // DELETEリクエストでのユーザー削除エンドポイントを設定し、controllers.DeleteUser関数を実行する
	r.DELETE("/users/:id", controllers.DeleteUser)
}
```

### user_service.go

user_service.goはuser_controllerから呼び出されるのに対して、データベース操作を抽象化し、ビジネスロジックとデータアクセスを分離するものである．

```user_service.go
package services

import (
	"example.com/myproject/models"
	"example.com/myproject/repositories"
)

// すべてのユーザーを取得
func GetUsers() ([]models.User, error) {
	return repositories.GetAllUsers()
}

// 指定されたIDのユーザーを取得
func GetUser(id string) (models.User, error) {
	return repositories.GetUser(id)
}

// 新しいユーザーを作成
func CreateUser(user models.User) error {
	return repositories.CreateUser(user)
}

// 指定されたIDのユーザーを更新
func UpdateUser(id string, user models.User) error {
	return repositories.UpdateUser(id, user)
}

// 指定されたIDのユーザーを削除
func DeleteUser(id string) error {
	return repositories.DeleteUser(id)
}
```

### .env
```.env
DATABASE_URL=uri
```

# 実行

### 実行コマンド
```
go run main.go
```

### 動作確認
**1.PostmanでかきのURLにPOSTしてみよう**
```
http://localhost:8000/users
```

**2.jsonのテンプレート**
```json
{
    "name": "test_name",
    "email": "test_mail"
}
```


完成!!!