こんにちは。よっしーです(^^)
今日は、Golangで RESTful API を開発する方法についてご紹介します。
概要
本記事では、GoとGin Web Framework(Gin)を使ってRESTfulなWebサービスAPIを書く基本をご紹介します。
Ginは、Webサービスを含むWebアプリケーションの構築に関連する多くのコーディング作業を簡素化します。このチュートリアルでは、リクエストをルーティングし、リクエストの詳細を取得し、レスポンス用のJSONをマーシャルするためにGinを使用します。
この記事では、2つのエンドポイントを持つRESTful APIサーバーを構築します。サンプルプロジェクトは、ビンテージジャズのレコードに関するデータのリポジトリです。
以下のセクションで構成されています。
- API エンドポイントを設計する。
- コード用のフォルダを作成する。
- データを作成する。
- すべての項目を返すハンドラを記述する。
- 新しいアイテムを追加するハンドラを書く。
- 特定の項目を返すハンドラを記述する。
この記事では、セクション4までを解説しています。セクション5以降は、次回の記事でご説明いたします。
APIエンドポイントの設計
この記事で作成するAPIは下記になります。
ビンテージ盤を販売する店舗へのアクセスを提供するAPIを構築する。そのため、クライアントがユーザーのためにアルバムを取得したり追加したりできるエンドポイントを提供する。
APIを開発する場合、通常はエンドポイントを設計することから始めます。エンドポイントが理解しやすいものであれば、APIのユーザーはより使いやすいものになります。
下記がこの記事で作成するエンドポイントです。
/albums
- GET – すべてのアルバムのリストを取得し、JSONとして返します。
- POST – JSONとして送信されたリクエストデータから、新しいアルバムを追加します。
/albums/:id
- GET – IDでアルバムを取得し、アルバムデータをJSONとして返す。
コード用のディレクトリを作成
最初に作業ディレクトリを作成します。手順は下記のコマンドになります。
mkdir 14_learn-golang-develop--rest-api
cd 14_learn-golang-develop--rest-api
asdfコマンドで使用するGolangのバージョンを指定します。すでにGolangが実行できる状態にある方は、このコマンドをスキップしても問題ありませんが、Go 1.16以降である必要があります。
asdf local golang 1.20.5
モジュールの初期化を初期化します。この例では、data-accessモジュールを作成します。
mkdir data-access
cd data-access
go mod init example/data-access
作業ディレクトリを作成します。
mkdir 14_learn-golang-develop--rest-api
pushd 14_learn-golang-develop--rest-api
依存関係を管理できるモジュールを作成する。
go mod initコマンドを実行し、あなたのコードが入るモジュールのパスを与える。
go mod init example/web-service-gin
このコマンドはgo.modファイルを作成し、そこにあなたが追加した依存関係がトラッキングのためにリストアップされます。モジュールパスを使ったモジュール名の付け方については、依存関係の管理を参照してください。
データの作成
本記事では物事をシンプルにするために、データをメモリーに保存する。一般的なAPIはデータベースとやりとりをしますが、ここではメモリ上に保存します。
データをメモリーに保存するということは、サーバーを停止するたびにアルバムのセットが失われ、サーバーを起動すると再作成されるということです。
main.goの中に、以下のコードを貼り付けて、保存します。
package main
// album represents data about a record album.
type album struct {
ID string `json:"id"`
Title string `json:"title"`
Artist string `json:"artist"`
Price float64 `json:"price"`
}
// albums slice to seed record album data.
var albums = []album{
{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},
}
すべての項目を返すハンドラを書く
クライアントがGET /albumsでリクエストを行ったとき、すべてのアルバムをJSONとして返したい。
そのためには、以下のように記述する。
- レスポンスを準備するロジック
- リクエストパスをロジックにマップするコード
これは実行時に実行される方法の逆であることに注意してください。
前のセクションで追加した構造体コードの下に、以下のコードを貼り付けてアルバム・リストを取得します。
このgetAlbums関数は、アルバム構造体のスライスからJSONを作成し、そのJSONをレスポンスに書き込みます。
// getAlbums responds with the list of all albums as JSON.
func getAlbums(c *gin.Context) {
c.IndentedJSON(http.StatusOK, albums)
}
main.goの一番上、アルバム・スライス宣言のすぐ下に、以下のコードを貼り付けて、ハンドラー関数をエンドポイント・パスに割り当てる。
これにより、getAlbumsが/albumsエンドポイントパスへのリクエストを処理する関連付けが設定されます。
main.goの一番上、パッケージ宣言のすぐ下に、今書いたコードをサポートするために必要なパッケージをインポートする。
コードの最初の行は次のようにします。
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
コードの実行
依存関係としてGinモジュールのトラッキングを開始する。
コマンドラインでgo getを使って、github.com/gin-gonic/ginモジュールをあなたのモジュールの依存関係として追加します。ドット引数は、”カレントディレクトリのコードの依存関係を取得する “という意味で使います
go get .
main.goのあるディレクトリのコマンドラインから、コードを実行する。ドット引数は、”カレント・ディレクトリでコードを実行する “という意味で使う。
go run .
コードが実行されると、リクエストを送ることができるHTTPサーバーが完成します。
新しいコマンドラインウィンドウから、curlを使って実行中のウェブサービスにリクエストを出します。
curl http://localhost:8080/albums
下記のようなデータが表示されていれば成功です。
% 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
}
]
解説
main.go
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
// album represents data about a record album.
type album struct {
ID string `json:"id"`
Title string `json:"title"`
Artist string `json:"artist"`
Price float64 `json:"price"`
}
// albums slice to seed record album data.
var albums = []album{
{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},
}
func main() {
router := gin.Default()
router.GET("/albums", getAlbums)
router.Run("localhost:8080")
}
// getAlbums responds with the list of all albums as JSON.
func getAlbums(c *gin.Context) {
c.IndentedJSON(http.StatusOK, albums)
}
このコードは、Go言語でWebアプリケーションを作成するためのサンプルコードです。
main
パッケージをインポートします。net/http
パッケージとgithub.com/gin-gonic/gin
パッケージを使用します。album
という構造体が定義されています。この構造体は、レコードアルバムに関するデータを表します。ID
、Title
、Artist
、Price
というフィールドを持ち、それぞれがJSONキーとして表現されます。albums
という変数が定義されています。これは、レコードアルバムデータを初期化するためのスライスです。サンプルデータとして、3つのアルバムが含まれています。main
関数が定義されています。ここでは、Ginフレームワークを使用してWebサーバーを起動します。gin.Default()
を使用して、デフォルトのGinルーターを作成します。GET
メソッドのハンドラ関数としてgetAlbums
が定義されています。この関数は、すべてのアルバムのリストをJSON形式で応答します。router.GET("/albums", getAlbums)
によって、/albums
エンドポイントにGETリクエストがあった場合にgetAlbums
関数が呼び出されるように設定されます。router.Run("localhost:8080")
によって、Webサーバーが指定されたアドレス(ローカルホストのポート8080)で起動されます。
このコードは、Ginフレームワークを使用してシンプルなWebサーバーを構築し、/albums
エンドポイントにGETリクエストがあった場合にアルバムのリストをJSON形式で返すサンプルです。
Gin
Ginは、Go言語で使用できる軽量なWebフレームワークです。以下に、Ginの特徴と使用方法の概要を説明します。
特徴:
- 高速: Ginは高速なルーティングエンジンを備えており、パフォーマンスの向上を重視しています。
- ミドルウェアサポート: Ginはミドルウェアを使用して、アプリケーションのロギング、認証、エラーハンドリングなどの機能を追加することができます。
- ルーティング: Ginは柔軟なルーティング機能を提供しており、URLパラメータ、クエリパラメータ、RESTfulなルーティングなどをサポートしています。
- バリデーション: Ginはリクエストデータのバリデーションを簡単に行うための機能を提供しています。
- テンプレートエンジン: GinはHTMLテンプレートエンジンを組み込んでおり、HTMLページの生成やレンダリングに使用することができます。
使用方法:
- インストール:
go get -u github.com/gin-gonic/gin
を使用してGinをインストールします。 - インポート:
github.com/gin-gonic/gin
をインポートして、Ginを使用するファイルで利用可能にします。 - ルーティングの設定:
gin.Default()
を呼び出してデフォルトのGinルーターを作成し、GET
、POST
、PUT
などのHTTPメソッドに対してエンドポイントとハンドラ関数を設定します。 - リクエストデータの取得:
c.Param()
やc.Query()
などのメソッドを使用して、リクエストからパラメータやクエリパラメータを取得します。 - ミドルウェアの設定:
gin.Use()
を使用してミドルウェアを設定し、リクエストの前後に特定の処理を実行します。 - レスポンスの送信:
c.JSON()
やc.HTML()
などのメソッドを使用して、JSONデータやHTMLページをレスポンスとして送信します。 - サーバーの起動:
router.Run()
を呼び出して、指定したアドレスとポートでWebサーバーを起動します。
これらはGinの基本的な使い方です。Ginにはさらに多くの機能があり、ドキュメントやチュートリアルで詳細な情報を確認できます。
おわりに
今日は、Golangで RESTful API を開発する方法についてご紹介しました。次回の記事では、アイテムを追加するためのPOSTリクエストを処理するコードで別のエンドポイントを作成します。
本記事で使用したコードは下記のリポジトリにあります。
何か質問や相談があれば、遠慮なくコメントしてください。また、エンジニア案件についても、いつでも相談にのっていますので、お気軽にお問い合わせください。
それでは、また明日お会いしましょう(^^)
コメント