{
  "$type": "site.standard.document",
  "canonicalUrl": "https://blog.nove-b.dev//posts/create-signup-unsubscribe-webapi-golang",
  "path": "/posts/create-signup-unsubscribe-webapi-golang",
  "publishedAt": "2023-12-14T00:00:00.000Z",
  "site": "at://did:plc:2atly2y5kfyjcj5zap6pv4wd/site.standard.publication/3mmxeqr2tcb2k",
  "tags": [
    "api",
    "go"
  ],
  "textContent": "いたるまで\n\n1. Go Lang で WebAPI を作成するために、まずは Docker で MySQL を構築する\n2. Go Lang で WebAPI を作成するために、Golang で MySQL に接続する\n3. Go Lang で WebAPI を作成するために、Golang でサーバーを立ち上げる\n4. Go Lang で WebAPI を作成するために、Golang でエンドポイントにアクセスし DB からデータを取得する\n5. Go Lang で WebAPI を作成するために、Golang で DB のデータを取得する main ファイルをそれぞれの責務に分割する\n\nディレクトリ構成\n\n上記のように作成した。\n\n簡単に説明すると、\n\ndb/db.go\n\nデータベースとの接続が行われる。\n\nhandlers/handlers.go\n\nHTTP リクエストに対する処理を管理している。\n\nhandlers/auth/handlers.go\n\nユーザー作成・削除に対する処理を作成している。\n\nhandlers/models/user_model.go\n\nユーザーに関する構造体を定義している。 データーベースモデル。\n\n処理を追いかける\n\nデーターベースと接続する\n\nプログラム初期化時に init 関数が実行\n\nまずプログラム初期化時にinit関数が実行される。\n\nこれはGolangの特殊仕様。\n\ngodotenv.Load()でgodotenvライブラリを使用し、.envを読み込む。\n\nエラーが出た際はerrにエラーオブジェクトをセットする。\n\nif err != nilは Go 言語においてエラー処理を行う際の一般的な書き方。\n\nenvが読み込めなかった場合、log.Fatal(\"Error loading .env file\")が実行される。\n\n実行されることで、メッセージをログに記録し、それからプログラムを即座に終了する。\n\nlog.Fatal()は致命的なエラーが発生した場合に使われるログ出力関数らしい。\n\ndb.InitDB()が実行される\n\n問題がなければdb.InitDB()が実行される。\n\nこちらはインポートされた\"GiveAndTakeCollection-Backend/src/db\"のInitDB関数が呼ばれる。\n\n先頭でpackage dbと定義しているため、db.InitDB()で呼び出すことができる。\n\nこのファイルではまず、gorm.DB型のポインタ変数DBを宣言している。これはGormのデータベース接続を表す変数。\n\nちなみに、ポインタ変数というのは「変数のメモリアドレスを格納するための特別な型の変数」ということらしい。\n\n> 変数にはデータそのものが格納されますが、ポインタ変数にはメモリアドレスが格納されます。\n\nとのこと。\n\nちなみにGoでは下記のように宣言する。\n\n詳細な使い方は調べる必要がある。\n\nあとvar DB gorm.DBパッケージレベルで行う方がいいらしい。\n\n> var DB\n> \\gorm.DB の宣言が initDB 関数の中で行われる場合、その変数はローカル変数として initDB 関数のスコープ内にのみ存在します。この場合、他の関数やファイルから DB 変数にアクセスすることができなくなります。\n>\n> 一般的に、データベース接続などのリソースはアプリケーション全体で共有されることが多いため、var\n> DB\n> \\gorm.DB の宣言は関数の外、パッケージレベルで行われることがあります。これにより、他の関数やファイルから DB 変数にアクセスでき、アプリケーション内で一貫性のあるデータベース接続が確保されます。\n\n話を戻して次に、db.InitDB()の処理を追いかける。\n\ndsnという変数に、os.Getenv(\"DB_CONNECTION_STRING\")で取得した環境変数を格納する。\n\nos.Getenvの戻り値の型はstringなので、もし環境変数が空文字であれば、エラーメッセージを標準出力し、プログラムを終了する。\n\nちなみに引数は下記の通り。\n\n> os.Exit(0): プログラムの正常な終了を示します。<br>\n> os.Exit(1): プログラムがエラーで終了したことを示します。\n>\n> 一般的には非ゼロの終了コードはエラーを示す慣習とされています。\n\n環境変数が適切に設定されていた場合は下記コードが実行される。\n\nここでは、まずエラー変数を定義し、Gormを使用してMySQLデータベースに接続する。\n\n成功するとDBに接続が設定され、失敗するとエラーがエラー変数に格納される。\n\nif err != nil { ... }でエラーチェックが実行され、エラーの場合はエラーメッセージを標準出力し、プログラムを終了する。\n\n問題がなければ、データベースに接続しましたが標準出力に表示される。\n\nここまでで、データベースの接続が完了し、次にmain関数が呼ばれる。\n\nHTTP リクエストを処理するためのルーティングとサーバーの起動\n\nmain 関数が実行される\n\nmain関数では上記の通り、handlers パッケージが呼ばれている。\n\nHandleRequests関数は、HTTP リクエストを処理するためのルーティングとサーバーの起動を行っている。\n\nこれにより、/auth/newへのリクエストはauth.CreateUser関数で処理され、/auth/deleteへのリクエストはauth.DeleteUser関数で処理されるようになる。\n\nauth.CreateUser が呼ばれた時\n\nauth.CreateUserは下記のようなコード構成になっている。\n\nCreateUser関数を追いかけると、まずdb := db.DBで db パッケージで定義したデータベース接続を取得する(var DB gorm.DBパッケージレベルで行っていたのはこのような場合のため)。\n\n次にtx := db.Begin()でトランザクションを開始する。\n\nトランザクションというのは、一貫性のないデータを作らないための処理のこと。\n\n次のブロックはまず、userDataという変数を作成する。 models.Userは型指定。\n\nerr := json.NewDecoder(r.Body).Decode(&userData)では、json.NewDecoder(r.Body)で HTTP リクエストのボディを読み込むためのデコーダー(変換機)を作成し、.Decode(&userData)でデコーダーを使ってボディの内容をuserDataという変数に変換(デコード)する。この操作は、JSON 形式のデータを Go の構造体(models.User)に変換する役割を果たしている。\n\nもしエラーが出た際はエラーメッセージを標準出力し、HTTP レスポンスを生成してクライアントにエラーメッセージを返し、処理を終了させている。\n\nエラーがない場合は、この時点でユーザーの登録したいデータ(HTTP リクエストのボディ)がuserDataに格納されている。\n\nその次にuserDataのパスワード(ユーザーの入力したパスワード)をハッシュ化する処理が行われる。\n\nこれはbcryptのGoパッケージを使用している。\n\n問題なく、ハッシュ化が行われれば、データベースにユーザーを作成する。\n\nerr = db.Create(&userData).Errorでデータベースに新規データを作成する。\n\nその際エラーが出たらerrオブジェクトに代入する。\n\nエラーがなければトランザクションをコミットし確定。\n\n成功のレスポンスを返し、ユーザー作成が完了した。\n\nユーザー作成が出来たので、退会処理も同様に作成する。\n\nauth.DeleteUser が呼ばれた時\n\nこれで退会処理もできた。",
  "title": "Go Langで新規登録と退会のWebAPIを作成したので、やったことをまとめてみる。"
}