こんにちは。よっしーです(^^)
今日は、先日の記事に引き続き、GolangでRESTful APIを開発する方法についてご紹介します。
概要
本記事は前回の記事からの続きになります。前回の記事は下記になりますので、未参照の方は一読することをおすすめします。
GolangでRESTful APIを開発する方法については、以下のセクションで構成されています。
- API エンドポイントを設計する。
- コード用のフォルダを作成する。
- データを作成する。
- すべての項目を返すハンドラを記述する。
- 新しいアイテムを追加するハンドラを書く。
- 特定の項目を返すハンドラを記述する。
前回の記事では、セクション4までをご紹介しました。本記事では、セクション5以降についてご紹介しています。
新しい項目の追加処理
クライアントが/albumsにPOSTリクエストをしたとき、リクエストボディに記述されたアルバムを既存のアルバムデータに追加します。
そのためには、下記の手順を実施します。
- 新しいアルバムを既存のリストに追加するロジック。
- POSTリクエストをロジックにルーティングする。
アルバムリストにアルバムデータを追加するコードを追加する。
import文の後のどこかに、以下のコードを貼り付ける。(このコードはファイルの最後が良いのですが、Goは関数を宣言する順番を強制しません)
// postAlbums adds an album from JSON received in the request body.
func postAlbums(c *gin.Context) {
var newAlbum album
// Call BindJSON to bind the received JSON to
// newAlbum.
if err := c.BindJSON(&newAlbum); err != nil {
return
}
// Add the new album to the slice.
albums = append(albums, newAlbum)
c.IndentedJSON(http.StatusCreated, newAlbum)
}
次のように、main関数にrouter.POST関数を含めるように変更します。
func main() {
router := gin.Default()
router.GET("/albums", getAlbums)
router.POST("/albums", postAlbums)
router.Run("localhost:8080")
}
コードを実行する
最後のセクションでサーバーがまだ動いている場合は、サーバーを停止する。
main.goのあるディレクトリのコマンドラインから、コードを実行する。
go run .
別のコマンドラインウィンドウから、curlを使って実行中のウェブサービスにリクエストを出す。
curl http://localhost:8080/albums \
--include \
--header "Content-Type: application/json" \
--request "POST" \
--data '{"id": "4","title": "The Modern Sound of Betty Carter","artist": "Betty Carter","price": 49.99}'
下記のような出力になっていれば成功です。
% curl http://localhost:8080/albums \
--include \
--header "Content-Type: application/json" \
--request "POST" \
--data '{"id": "4","title": "The Modern Sound of Betty Carter","artist": "Betty Carter","price": 49.99}'
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
Date: Thu, 22 Jun 2023 12:18:27 GMT
Content-Length: 116
{
"id": "4",
"title": "The Modern Sound of Betty Carter",
"artist": "Betty Carter",
"price": 49.99
}
前のセクションと同様に、curlを使ってアルバムの全リストを取得し、それを使って新しいアルバムが追加されたことを確認する。
% curl http://localhost:8080/albums
[
{
"id": "1",
"title": "Blue Train",
"artist": "John Coltrane",
"price": 56.99
},
{
"id": "2",
"title": "Jeru",
"artist": "Gerry Mulligan",
"price": 17.99
},
{
"id": "3",
"title": "Sarah Vaughan and Clifford Brown",
"artist": "Sarah Vaughan",
"price": 39.99
},
{
"id": "4",
"title": "The Modern Sound of Betty Carter",
"artist": "Betty Carter",
"price": 49.99
}
]
特定の項目を返す処理
クライアントがGET /albums/[id]というリクエストをしたとき、IDがidパス・パラメータと一致するアルバムを返すAPIを追加します。
そのために、下記のことをします。
- リクエストされたアルバムを取得するロジックを追加する。
- パスをロジックにマップします。
前のセクションで追加したpostAlbums関数の下に、特定のアルバムを取得するために以下のコードを貼り付けます。
このgetAlbumByID関数は、リクエストパスのIDを抽出し、一致するアルバムを探します。
// getAlbumByID locates the album whose ID value matches the id
// parameter sent by the client, then returns that album as a response.
func getAlbumByID(c *gin.Context) {
id := c.Param("id")
// Loop over the list of albums, looking for
// an album whose ID value matches the parameter.
for _, a := range albums {
if a.ID == id {
c.IndentedJSON(http.StatusOK, a)
return
}
}
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "album not found"})
}
最後に、次の例に示すように、mainを変更して、router.GETの新しい呼び出しを含むようにします。ここで、パスは/albums/:idになります。
func main() {
router := gin.Default()
router.GET("/albums", getAlbums)
router.GET("/albums/:id", getAlbumByID)
router.POST("/albums", postAlbums)
router.Run("localhost:8080")
}
最後のセクションでサーバーがまだ動いている場合は、サーバーを停止する。
main.goのあるディレクトリのコマンドラインから、サーバーを起動するコードを実行してください。
go run .
別のコマンドラインウィンドウから、curlを使って実行中のウェブサービスにリクエストを出す。
curl http://localhost:8080/albums/2
コマンドは、使用したIDのアルバムのJSONを表示するはずです。
% curl http://localhost:8080/albums/2
{
"id": "2",
"title": "Jeru",
"artist": "Gerry Mulligan",
"price": 17.99
}
アルバムが見つからなかった場合は、エラーメッセージとともにJSONが表示されます。
% curl http://localhost:8080/albums/22
{
"message": "album not found"
}
解説
postAlbums メソッド
このコードは、Ginフレームワークを使用してHTTP POSTリクエストを処理するハンドラ関数です。リクエストボディで受け取ったJSON形式のアルバムデータを解析し、アルバムを追加します。
以下がコードの解説です:
postAlbums
関数は、gin.Context
オブジェクトを引数として受け取ります。これは、HTTPリクエストとレスポンスのコンテキストを表します。newAlbum
という名前のalbum
型の変数を宣言します。この変数は、リクエストボディから受け取ったJSONデータを格納するために使用されます。album
型は、おそらくこのコードの別の場所で定義されていると思われます。c.BindJSON(&newAlbum)
を呼び出して、受け取ったJSONデータをnewAlbum
にバインドします。これにより、JSONデータがnewAlbum
のフィールドにマッピングされます。エラーが発生した場合は、処理を終了して関数から戻ります。- 新しいアルバムをスライス
albums
に追加します。append
関数を使用して、albums
スライスにnewAlbum
を追加します。 c.IndentedJSON(http.StatusCreated, newAlbum)
を呼び出して、レスポンスをJSON形式で返します。http.StatusCreated
は、HTTPステータスコード201(Created)を表します。newAlbum
は、追加されたアルバムのデータです。
このコードは、HTTP POSTリクエストを受け取り、リクエストボディで受け取ったJSONデータを解析し、アルバムを追加してレスポンスとして返す役割を持っています。
getAlbumByID メソッド
このコードは、Ginフレームワークを使用してHTTP GETリクエストを処理するハンドラ関数です。クライアントから送信されたIDパラメータと一致するID値を持つアルバムを探し、そのアルバムをレスポンスとして返します。
以下がコードの解説です:
getAlbumByID
関数は、gin.Context
オブジェクトを引数として受け取ります。これは、HTTPリクエストとレスポンスのコンテキストを表します。id := c.Param("id")
を使用して、クライアントから送信されたIDパラメータを取得します。Param
メソッドを使用することで、URLのパスに含まれるパラメータを取得できます。ここでは、パスの一部としてid
パラメータが指定されていることが想定されています。- スライス
albums
の各アルバムに対してループを実行し、パラメータと一致するID値を持つアルバムを探します。 - ループ内で、現在のアルバムを表す変数
a
のID値がパラメータのIDと一致するかをチェックします。一致する場合、c.IndentedJSON(http.StatusOK, a)
を呼び出して、そのアルバムをJSON形式でレスポンスとして返します。http.StatusOK
は、HTTPステータスコード200(OK)を表します。 - アルバムが見つからない場合、
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "album not found"})
を呼び出して、エラーメッセージを含むJSON形式のレスポンスを返します。http.StatusNotFound
は、HTTPステータスコード404(Not Found)を表します。
このコードは、HTTP GETリクエストを受け取り、指定されたIDパラメータと一致するアルバムを探し、そのアルバムをレスポンスとして返す役割を持っています。また、アルバムが見つからない場合はエラーメッセージを含むレスポンスを返します。
おわりに
前回と今回の記事では、GoとGinを使ってシンプルなRESTfulウェブサービスを書きました。
本記事で使用したコードは下記のリポジトリにあります。
Ginの詳細については、Gin Web FrameworkパッケージのドキュメントまたはGin Web Frameworkのドキュメントを参照してください。
Golangが初めての方は、Effective Go と How to write Go codeに役立つベストプラクティスが記載されています。
また、Go ツアーというGolang の基礎をステップバイステップで学べる入門サイトもあります。
何か質問や相談があれば、遠慮なくコメントしてください。また、エンジニア案件についても、いつでも相談にのっていますので、お気軽にお問い合わせください。
それでは、また明日お会いしましょう(^^)
コメント