[Golang/Go言語]GinフレームワークでAPI開発2~CRUDの実装~

こんにちは。KOUKIです。

とあるWeb系企業で、Goエンジニアをやっています。

前回は、Go言語のフレームワークである「Gin」を使って簡単なAPI開発手法を紹介しました。

今回はより実践的な内容として、CRUD機能を取り込んだ「レシピを取り扱うAPI(recipe-api)」を実装していきたいと思います。

参考

以下のリポジトリを参考にしています。

https://github.com/PacktPublishing/Building-Distributed-Applications-in-Gin

環境

Mac + Chromeで開発します。

前回

前回は、Hello アプリを開発しました。

プロジェクトの作成

プロジェクトを作成しましょう。

main.goに最低限のコードを書きます。

Recipeモデルの定義

Recipeモデルを定義しましょう。

まずは、必要なディレクトリとファイルを用意します。

次に、GoのStructでモデルを実装します。

このModelにAPIのリクエスト/レスポンスデータを格納します。

jsonタグはレスポンスを返すときに、Keyをいい感じに整形してくれます。

HTTPエンドポイントの実装

下記に示すHTTPエンドポイントを実装しましょう。

HTTP Method リソース Description
GET /recipes レシピの一覧を返す
POST /recipes 新しいレシピを作る
PUT /recipes/{id} レシピをアップデートする
DELETE /recipes レシピを削除する
GET /recipes/search?tag=X Tagに指定されたレシピを返却する

HTTPルートを実装

HTTPエンドポイントを参考に、ルートを実装していきましょう。

以下のディレクトリとファイルを用意しておきます。

レシピの作成(recipes): POST

まず、handlerを実装しましょう。ここにはレシピを作成するための処理を実装します。

中身は後で実装するので、とりあえず先に進みましょう。

次は、ルートを実装します。

ここには、GETやDELETEなど他のHTTPエンドポイントを追加していく予定です。

次に、routeをmain関数から呼び出しましょう。

いい感じですね。NewRecipeHandlerの中身を実装しましょう。

recipes変数は一時的なデータ格納場所です。将来はDatabaseにデータを保存したいですね。

またGinに限らず大抵のフレームワークには、データバインディング機能(c.ShouldBindJSON(&recipe))がついてます。

これは、Goの構造体とリクエストの構造体(ここではJSON)の間で一致したパラメーターをrecipe変数にコピーしてくれます。大変便利です。

テストをしてみましょう。Terminal上で以下のコマンドを実行ください。

私はテストAPIツールとして、ChromeのTalend APIを利用します。

これを使って、以下のパラメーターでAPIへリクエストを送ってみましょう。

  • URL: http://localhost:8080/recipes
  • 形式: POST
  • Body: ↓

200 OKかつ投入データが確認できたのでOKですね。

レシピ一覧の取得(recipes): GET

続いて、レシピ一覧を取得しましょう。

Handlerを作成します。

これは単純に、先ほど作成したrecipes(一時的なデータベース)を呼び出し元に返しているだけです。

ListRecipesHandlerをルートに加えます。

テストをしてみましょう。

Ctrl + cで先ほど立ち上げたWebサーバーを切ってから「go run main.go」で立ち上げ直してください。

Webサーバーを立ち上げ直すと先ほど追加したレシピは消えてしまうので(一時的なものなので)、レシピを入れ直してから以下のパラメータでデータの取得を試してみましょう。

  • URL: http://localhost:8080/recipes
  • 形式: GET

OKですね。

初期データの投入

Webサーバーを起動しなす度に投入したデータが消えるのはめんどくさいですね。

Webサーバー起動時に、初期データを投入できるようにしましょう。

まず、JSONでデータを作成します。

このファイルに以下のデータを追加します。

newrecipehandler.goファイルのinitに「ioutil.ReadFile」メソッドを使って先ほど作成したJSONファイルを読み込む処理を追加します。

これで、初期データの投入は完了です。Webサーバーを起動し直してGETリクエストでデータを取得してみてください。データが取得できるはずです。

CURLでも試せます。※ jqを使っています

レシピ一覧の更新(recipes/id): PUT

続いて、レシピを更新する処理を実装します。

例によって、ハンドラーを作成します。

ginのParamメソッドはURLに記述された「:id」からIDを取得します。この「: + id」を所定のフォーマットになります。

例えば「:name」の場合は、c.Param(“name”)でデータを取り出すイメージです。

idを取得し、リクエストデータをrecipe変数にバインドしたら既存のデータ検索の実装に移ります。

既存のデータから今回リクエストしたidで検索をかけ、該当するデータをそっくりそのまま上書きする処理を実装しています。

Databaseを導入すればもっといい感じの処理がかけますが、今回はこれでよしとしましょう。

続いて、ルートにUpdateRecipeHandlerを追加しましょう。

動作確認をします。Webサーバーを起動し直します。

現在の状態を確認するために、以下のコマンドを実行しましょう。

このデータの中で、nameを変更してみましょう。

以下のパラメーターで、データを送信します。

  • URL: http://localhost:8080/recipes/dfjpaidhjfpiajdpif
  • 形式: PUT

dfjpaidhjfpiajdpifがIDです

Updateされましたね。CURLでも確認します。

レシピ一覧の削除(recipes/id): DELETE

次は、レシピを削除する処理を実装しましょう。

例によって、Handlerを実装します。

更新処理とロジックはほぼ同じです。

ルートも追加しましょう。

Webサーバーを起動し直してください。

まず、recipesを取得してみましょう。

レシピは存在しています。

続いて、下記のコマンドでレシピを削除します。

OKですね。

念の為、Recipeを取得してみましょう。

レシピ一覧の検索(recipes/search): GET

最後に、レシピを検索する処理を実装しましょう。

テストデータ(recipies.json)を増やしておきます。

さて、例によってHandlerを追加しましょう。

GinのQueryメソッドは大変便利です。

例えば、「http://localhost:8080/recipes/search?tag=”orange”」とリクエストした場合、orangeを取得できます。

「?query名」のフォーマットですね。

実装したHandlerをルートに追加しましょう。

Webサーバーを起動し直して、テストしましょう。

  • URL: http://localhost:8080/recipes/search?tag=dinner
  • 形式: GET

dinnerタグは、Homemade Pizzaにしかないのでそれしか取得できてません。

一応、共通するタグでリクエストを送ってみましょう。

  • URL: http://localhost:8080/recipes/search?tag=italian

ちょっと見にくいですが、今回はどちらも取得できたことがわかります。

次回

次回は、OpenAPI(Swagger)を学習しましょう。

Go記事まとめ

Go記事をまとめます。

コメントを残す