🧑‍💻

Go でWeb APIサーバを起動する

に公開

はじめに

GoでWeb APIサーバを起動させようとするといくつか選択肢がある

  • net/http(go標準搭載のwebサーバのパッケージ)
  • gin
  • echo
  • Fiber

標準でwebサーバのパッケージが搭載されているので、これを使えばいいと思ったが
よく調べるとルーティングやミドルウェアのサポートが少し足りない。

公式のチュートリアルではginを利用していたので、今回はginを利用してwebサーバを構築する
https://go.dev/doc/tutorial/web-service-gin

実行環境

Docker version 27.5.1
dockerイメージ:golang:1.24.2-bookworm

Ginの導入

もしginがプロジェクトに導入されていないなら
以下のコマンドをプロジェクトのルートで実行

go get -u github.com/gin-gonic/gin

ソースコード

cmd/main.go
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の慣例として標準パッケージと外部パッケージの間に空行を入れることが文化としてあるらしい
https://marketplace.visualstudio.com/items/?itemName=golang.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処理を受け取る関数

pkg/albums/getAlbums.go
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処理を受け取る関数

pkg/albums/postAlbums.go
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処理を受け取る関数

pkg/albums/getAlbumByID.go
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サーバを作って検証してみたい。

今回のソースコードは以下のブランチで公開している
https://github.com/sugar2456/hello_world_go/tree/web_api

Discussion