Go でWeb APIサーバを起動する
はじめに
GoでWeb APIサーバを起動させようとするといくつか選択肢がある
- net/http(go標準搭載のwebサーバのパッケージ)
- gin
- echo
- Fiber
標準でwebサーバのパッケージが搭載されているので、これを使えばいいと思ったが
よく調べるとルーティングやミドルウェアのサポートが少し足りない。
公式のチュートリアルではginを利用していたので、今回はginを利用してwebサーバを構築する
実行環境
Docker version 27.5.1
dockerイメージ:golang:1.24.2-bookworm
Ginの導入
もしginがプロジェクトに導入されていないなら
以下のコマンドをプロジェクトのルートで実行
go get -u github.com/gin-gonic/gin
ソースコード
package main
import (
"hello_world_go/pkg/albums"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
router.GET("/albums", albums.GetAlbums)
router.POST("/albums", albums.PostAlbums)
router.GET("/albums/:id", albums.GetAlbumById)
router.Run("localhost:8080")
}
routerのインスタンスを作成する。
このデフォルトにはロガーやリカバリーミドルウェアが呼び出されているらしい
/albumsというエンドポイントにGetAlbumsという関数を呼び出している
ちなみにvscodeでgoの公式拡張機能を導入するとプロジェクトパッケージと外部パッケージの
間に勝手に改行が入るが、これはgoの慣例として標準パッケージと外部パッケージの間に空行を入れることが文化としてあるらしい
以下は起動した際のコンソールに表示されているログ
ロガーミドルウェアで表示しているらしい
[GIN-debug] Listening and serving HTTP on localhost:8080
[GIN] 2025/04/29 - 04:36:23 | 404 | 1.141µs | 127.0.0.1 | GET "/"
[GIN] 2025/04/29 - 04:36:23 | 404 | 1.156µs | 127.0.0.1 | GET "/favicon.ico"
[GIN] 2025/04/29 - 04:41:40 | 200 | 110.511µs | 127.0.0.1 | GET "/albums"
エンドポイントに紐付けている関数
goでは関数名の大文字はパッケージを超えて参照するという意味がある
逆に小文字はパッケージを超えて参照することができない関数になる
get処理を受け取る関数
package albums
import (
"hello_world_go/pkg/types"
"net/http"
"github.com/gin-gonic/gin"
)
// パッケージレベルの定義なので、同パッケージ内の関数からアクセスすることができる
var albums = []types.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 GetAlbums(c *gin.Context) {
c.IndentedJSON(http.StatusOK, albums)
}
post処理を受け取る関数
package albums
import (
"hello_world_go/pkg/types"
"net/http"
"github.com/gin-gonic/gin"
)
func PostAlbums(c *gin.Context) {
var newAlbum types.Album
if err := c.BindJSON(&newAlbum); err != nil {
return
}
albums = append(albums, newAlbum)
c.IndentedJSON(http.StatusCreated, newAlbum)
}
パスパラメータによるget処理を受け取る関数
package albums
import (
"net/http"
"github.com/gin-gonic/gin"
)
func GetAlbumById(c *gin.Context) {
id := c.Param("id")
for _, album := range albums {
if album.ID == id {
c.IndentedJSON(http.StatusOK, album)
return
}
}
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "album not found"})
}
動作確認
以下のコマンドでapiサーバを起動
go run cmd/main.go
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
}
]
アルバム情報を登録
$ curl http://localhost:8080/albums \
--include > \
--header "Content-Type: application/json" \
> > --request "POST" \
--data '{"id": "4","tit> le": "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: Tue, 29 Apr 2025 06:55:53 GMT
Content-Length: 116
{
"id": "4",
"title": "The Modern Sound of Betty Carter",
"artist": "Betty Carter",
"price": 49.99
}
追加したアルバムをパスパラメータで取得
$ curl http://localhost:8080/albums/4
{
"id": "4",
"title": "The Modern Sound of Betty Carter",
"artist": "Betty Carter",
"price": 49.99
}
終わりに
今回はginでweb apiサーバを構築してみた。
簡単にルーティングやリクエスト、レスポンスの操作ができ、
実装コストが簡単だった。
時間があったらechoやFiberでもapiサーバを作って検証してみたい。
今回のソースコードは以下のブランチで公開している
Discussion