Go言語でWeb APIサーバーを作る完全ガイド|設計・開発フロー・テスト・CI/CDまで徹底解説

  • golang
    golang
  • echo
    echo
  • gin
    gin
2023/11/21に公開

GoでWeb APIサーバーを作りたいけど、どうやって進めたらいいか迷うこともありますよね。
今回は、初心者の方でも取り組みやすいように、設計の考え方から導入手順までを順を追って解説します。

まず押さえておきたいポイント

GoでWeb APIサーバーを作るときは、以下の2つを意識すると開発がグッとやりやすくなります。

✅ 疎結合 & 保守性を重視する
✅ ビジネスロジック(ドメイン)とインフラ周りを分ける

これを意識しておくと、後から機能を拡張するのも楽になります。

疎結合 & 保守性を重視するとは?

疎結合とは、アプリの各部分が「なるべく依存しすぎない」ように作ることです。

例えば、APIのルーティング部分(Ginなど)と、データベース操作(GORMなど)を直接つなぎすぎると、修正や拡張が大変になりがちです。

代わりに、API層(ハンドラ)・ビジネスロジック層(Usecase)・データアクセス層(Repository)といった役割ごとの分離をすると、以下のようなメリットがあります。

  • どこか1箇所を修正しても、他の部分への影響が少ない
  • テストも役割ごとに作りやすい(例:DBをモック化してビジネスロジックだけテストする、など)

ビジネスロジック(ドメイン)とインフラ周りを分ける

  • ビジネスロジックとは、そのアプリ特有の「こう動くべき」という処理部分です。
    例:アルバム作成時にタイトルは必須、カテゴリーが正しいかチェック…など。

  • インフラ周りとは、外部とやり取りする部分です。
    例:DBにデータを保存する処理、APIのルーティング、ファイル操作など。

これを分けるとどうなるかというと…
例えば「DBをMySQLからPostgreSQLに変えたい!」となったときでも、インフラ部分(Repository)だけ修正すれば済むことが多くなります。

要件・仕様を整理する

まずは、どんなAPIを作りたいのか、どんなデータを扱うのかをまとめます。
ER図やデータフローを簡単にでも書いておくと、開発がスムーズです。

どんなAPIを作りたいのか考える

APIを作る目的や機能をざっくりと洗い出します。
例えば、ブログサイトなら、以下のような操作が考えられます。

  • 新しいブログ記事を投稿するAPI
  • 投稿された記事を取得するAPI
  • 記事を編集するAPI
  • 記事を削除するAPI
  • カテゴリーやタグを管理するAPI

「どんな操作が必要?」と考えて、APIのエンドポイント(URL)をリストアップしておくとスムーズです。

どんなデータを扱うのか決める

次に、ブログの記事データをどう扱うかを整理します。
ブログサイトなら、記事データの基本的な要素はこんなイメージです。

  • 記事タイトル(Title)
  • 記事本文(Content)
  • 公開日(PublishedAt)
  • カテゴリー(Category)
  • タグ(Tags)
  • 著者情報(Author)

「このAPIでどんなデータを返すか・受け取るか」を意識しておくと、レスポンスやリクエストの形が決めやすいです。

ER図やデータフローを描いてみる

ここで「頭の中のイメージ」を図にしておくと、全体像がスッキリ見えます。

  • ER図(Entity-Relationship 図)
    例えば、記事とカテゴリーの関係はこう描けます。
Post (ID, Title, Content, PublishedAt, AuthorID, CategoryID)
Category (ID, Name)
Author (ID, Name)
  • データフロー図
    APIがどんな流れでデータを処理するかを絵にしておくと便利です。
Client → APIサーバー(エンドポイント) → ビジネスロジック → DB

なぜここをしっかりやるのか?

  • 途中で「この記事APIって何を返すんだっけ?」と迷わない
  • フロントエンドや他のチームメンバーと認識を共有しやすい
  • 設計書として残せるので、将来のメンテナンスが楽になる

最小限の動作確認(Hello World)

いきなり複雑なAPIを作ろうとすると、どこかで詰まりやすくなります。
まずは「サーバーが起動してリクエストを受け付ける」という最小限の動作を確認しましょう。

フレームワークとしては、GoではGinやEchoが人気です。
どちらも簡単なコードでAPIを試せます。

Ginのサンプル

package main

import (
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default() // Ginのデフォルト設定(ロギングやリカバリ機能もON)

	// /health エンドポイントを作成
	r.GET("/health", func(c *gin.Context) {
		c.JSON(200, gin.H{"status": "ok"})
	})

	// サーバー起動(ポート8080)
	r.Run(":8080")
}

✅ ポイント

  • r.GETで「GETリクエストに応答するルート」を定義します。
  • /healthにアクセスすると、{"status": "ok"}というJSONが返ります。

より詳しくGinの基礎を知りたい方は、こちらの記事をご覧ください。

https://shinagawa-web.com/blogs/go-gin-basic-guide

Echoのサンプル

package main

import (
	"net/http"
	"github.com/labstack/echo/v4"
)

func main() {
	e := echo.New() // Echoのインスタンスを作成

	// /health エンドポイントを作成
	e.GET("/health", func(c echo.Context) error {
		return c.JSON(http.StatusOK, map[string]string{"status": "ok"})
	})

	// サーバー起動(ポート8080)
	e.Start(":8080")
}

✅ ポイント

  • Ginと似た形で「GETエンドポイント」を定義しています。
  • c.JSONでJSONレスポンスを返せます。
  • Echoはmap[string]stringで簡単にJSONを作れるので、こちらも使いやすいです。

まずは「Hello, World!」の代わりに /health が返るだけでもOKです。
ここまでできたら「サーバーは起動できる」と自信が持てます


まずは「サーバーが立ち上がる」ことを確認するだけでOK。
ルーティングがちゃんと機能するか?レスポンスはちゃんと返せるか?を試すことで、環境構築やコードの基本が整います。

設計方針を決める

APIサーバーを作るとき、最初に「どんな設計方針で進めるか」を考えておくと、後で修正が入っても大丈夫なしなやかで強いアプリになります。

なぜ設計方針が大事?

小さいアプリなら「全部1つのファイルに書く」でも動きますが、機能が増えると必ず困ります。

  • どこに何が書いてあるかわからない…
  • ちょっと修正したら別の機能が壊れた…
  • テストもしづらい…

こんなトラブルを避けるために、設計方針=プロジェクトの骨組みをしっかり決めておく必要があります。

代表的な設計スタイル

クリーンアーキテクチャ(レイヤードアーキテクチャ)

役割ごとに層を分けることで、依存関係がはっきりして保守性が高まります。

├── handler       (APIの入口)
├── usecase       (ビジネスロジック)
├── entity        (ドメインモデル)
├── gateway       (DBや外部APIのやりとり)
├── pkg           (共通ライブラリ・ツール群)

✅ ポイント

  • 例えば「DBをMySQL→PostgreSQLに変えたい」となっても、gatewayだけ直せばOK
  • usecaseやentityが「アプリの本質的なロジック」を守るので、インフラの変更に強くなる

MVC(シンプルな構成)

「モデル・ビュー・コントローラ」の役割で分ける構成。小規模アプリならこれでもOK。

├── controllers   (リクエストを受け取る部分)
├── models        (DBやデータ構造)
├── views         (HTMLテンプレートなど)

✅ ポイント

  • 1ファイルが巨大にならず、見通しが良い
  • クリーンアーキテクチャほど厳密じゃなくてもOK

Go × Gin を使って、ブログ記事投稿APIをMVC構成で組み立てる基礎的な流れをご紹介している記事。

https://shinagawa-web.com/blogs/go-gin-mvc-basics

設計方針を決めるときのヒント

  • 自分が「どこで何をするか」イメージできるか?
    「この処理はusecaseでやる」「DB操作はgateway」みたいにイメージできると、迷いにくくなります。

  • 最初から完璧を目指さなくてOK
    とりあえず分けて、後で「ここはまとめよう」「ここは層を増やそう」と見直せばいいです。もちろん途中でMVCからクリーンアーキテクチャに移行することも可能です。

APIスキーマを決める(できればOpenAPIを活用)

Web APIを作るときに、「APIの仕様書をどうするか?」 はとても重要なポイントです。
特にチーム開発やフロントエンド・モバイルとの連携があるなら、OpenAPI(旧Swagger) の活用を強くおすすめします。

APIスキーマとは?

APIスキーマは、以下のような「APIの設計図」です。

  • どんなエンドポイントがある?
  • どんなリクエストボディ・レスポンスがある?
  • どんなデータ型・バリデーションが必要?

これを文章で書くのではなく、マシン可読な形式(YAMLやJSON)でまとめるのがOpenAPI仕様です。

OpenAPI(Swagger)のメリット

  • ドキュメントとして誰でも見れる
    swagger-uiを使えばブラウザ上でわかりやすく表示されるので、フロントエンドやデザイナー、テスターも迷わない。

  • ツールで一括管理できる
    例えば oapi-codegen などを使うと、OpenAPIからGoの型(構造体やクライアントコード)を自動生成できます。

  • テストやモックサーバーも作りやすい
    OpenAPIを使うと、自動でモックサーバーを立てるツール(Prismなど)も使えます。
    これで「バックエンドができる前にフロント開発を進める」なんてことも可能です。

例)OpenAPIファイル(例: openapi.yaml)の内容

openapi: 3.0.0
info:
  title: My Blog API
  version: 1.0.0
paths:
  /posts:
    get:
      summary: 記事の一覧を取得
      responses:
        '200':
          description: 一覧取得成功
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Post'
components:
  schemas:
    Post:
      type: object
      properties:
        id:
          type: integer
        title:
          type: string
        content:
          type: string
        publishedAt:
          type: string
          format: date-time

Go用のコード自動生成(oapi-codegenなど)

OpenAPIからGoコードを自動生成するツールとして、oapi-codegenがよく使われます。

  • openapi.yamlから、Goの型(リクエスト・レスポンス用の構造体)を生成
  • APIクライアントやサーバースタブも生成可能

✅ メリット

  • 型が自動で生成されるので、API仕様の変更があっても即対応できる
  • 手書きのミスがなくなり、バグを減らせる

エンドポイントごとに実装する

まずは小さく始める

例えばブログAPIを作るとき、全部一気に作ろうとすると大変です。
まずは「新規作成APIだけ動かす」のように、一つずつ実装していきましょう。

実装するエンドポイントの例

✅ POST /blogs(新規作成)

  • 新しいブログ記事を登録するAPI
  • 受け取るデータ: タイトル・本文・カテゴリーなど
  • 成功時のレスポンス: 作成された記事のIDや詳細情報

✅ GET /blogs/:id(取得)

  • 記事の詳細を取得するAPI
  • :idは記事のID(URLパラメータ)
  • データベースからそのIDの記事を取得して返す

✅ PATCH /blogs/:id(更新)

  • 記事を編集するAPI
  • 更新したい項目だけをリクエストボディに含めて送信
  • DBでその記事を更新して返す

✅ DELETE /blogs/:id(削除)

  • 記事を削除するAPI
  • :idの指定で記事をDBから削除
  • 削除後は204 No Contentなどを返す

実装の基本フロー

どのエンドポイントでも、基本はこの流れです。

  1. ルーティング設定(GinやEchoでエンドポイントを登録)
  2. リクエストを受け取る(JSONやURLパラメータを取り出す)
  3. ビジネスロジックを実行(Usecase層)
  4. DBにデータを保存・取得・削除(Repository層)
  5. レスポンスをJSONで返す

ミドルウェアとエラーハンドリング

APIサーバーを実際に運用するなら、必須の機能がいくつかあります。
それを一括で担ってくれるのが ミドルウェア です。

ミドルウェアとは

ミドルウェアは、リクエストがハンドラに届く前や、レスポンスを返す直前に動く機能です。
サーバー全体に共通でかかる「中間処理」なので、複数のエンドポイントで同じ処理を何度も書く必要がなくなります。

必須ミドルウェアの例

✅ CORS(クロスオリジンリクエスト)
ブラウザから別ドメイン(オリジン)にAPIを呼ぶときに、CORS設定がないとブラウザがブロックします。

例えば:

  • フロントが http://localhost:3000
  • APIが http://localhost:8080
    だと、ブラウザは「別オリジン」とみなしてリクエストを止めるんです。
    CORSミドルウェアを入れることで、「このオリジンからのリクエストは許可するよ」 という設定をサーバー側でまとめて管理できます。

✅ ロギング
APIを呼ばれたときに、どんなリクエストが来て、どう応答したかを記録する仕組みです。

  • 例: Ginのginzap(Zapロガーと連携)など

ログが残ることで…

  • 何かトラブルが起きたときに、原因を追いやすい
  • いつ、誰が、どんなAPIを呼んだか履歴がわかる

✅ Panic Recovery
Goアプリでは、時にpanic(致命的エラー)が発生することがあります。
もし対策しないと、サーバー全体が落ちちゃう。
Panic Recoveryミドルウェアは、panicが起きたときに自動でキャッチして、サーバーが落ちないように守ってくれます。
同時にエラーログを残してくれるので、原因も追いやすいです。

Ginではこんな感じで設定します。

r.Use(middleware.CorsMiddleware())
r.Use(middleware.GinZap())
r.Use(middleware.RecoveryWithZap())

テストを整備する

作ったAPIが「ちゃんと動くか」「バグがないか」…
それを自動的に確かめるのが テスト です。
テストを書いておくと、修正しても安心できるし、後で「何が壊れたか」もわかりやすいです。

単体テスト(Unit Test)

ビジネスロジックやユーティリティなど、1つの関数・クラス単位をテストします。

  • 記事を新規作成するときに、タイトルが空だとエラーになるか?
  • 公開日のバリデーションが正しく動くか?

など

✅ ポイント

  • DBや外部APIにはつながない(= 速くて安定!)
  • バグの原因をピンポイントで見つけやすい
func TestIsValidTitle(t *testing.T) {
  valid := IsValidTitle("My Blog Post")
  if !valid {
    t.Error("expected title to be valid")
  }
}

統合テスト(Integration Test)

複数のパーツが一緒に動くかを確認するテスト。APIで言うと、以下をまとめて動かします。

  • ハンドラ
  • ビジネスロジック
  • DBアクセス

例えば、

  • POST /blogs が 実際にDBに記事を作れるか?
  • GET /blogs/:id が 作成された記事を正しく取得できるか?

✅ ポイント

  • DBも動かすので「実際にアプリとして動くか」を確かめられる
  • ただし単体テストよりは少し重い

E2Eテスト(End-to-End Test)

APIサーバー全体を「外から」叩くテストです。

例:

  • フロントエンドから記事投稿をして、一覧に反映されるか?
  • 本番に近い「ユーザー目線」で一連の流れを確認する

✅ ポイント

  • 開発環境に近いので「リリース前の最後の保証」になる
  • ただし重いので、すべてのケースをここでやる必要はない

ツール例:

  • Goでも net/http で書ける
  • PlaywrightやCypressを使うことも多いです

単体テストでの流れ

  • DBには依存しないので、モックを作る(例: Goの testify/mock)
  • Usecase関数だけテストする

統合テストでの流れ

  1. Docker ComposeでテストDBを立てる
  2. APIサーバーをテスト用設定(APP_ENV=integration など)で起動
  3. go testでAPIにリクエストを送る
  4. DBのデータを確認する

Go × Gin × MVC構成でテスト設計および実装方法をご紹介しています。合わせてご参考ください。

https://shinagawa-web.com/blogs/go-gin-mvc-testing

どうやって始める?

まずは ビジネスロジックの単体テストから始めます。
速く書けて「ここは正しい」と保証できるので、一番手軽です。

それが慣れたら、統合テストでAPI全体の動きを確かめます。
例えば「POST /blogs が本当にDBに記事を作っているか?」を確認します。

本番リリース前には、E2Eテストで最終チェックを行います。
まるで「本物のユーザーが使っている」状態で試せるので、安心感があります。

CI/CDを導入する

開発フローが安定してきたら、CI(継続的インテグレーション)/CD(継続的デリバリーまたはデプロイ)を取り入れるのがおすすめです。
これによって、「手動での手順ミス」をなくし、自動でテストやビルドを回せるようになります。

CI/CDとは?

CI(継続的インテグレーション)
-「コードをマージするたびに、テストやビルドを自動で行う仕組み」
-「テストが通ってる!=壊れてない!」という安心感が得られる。

CD(継続的デリバリー or デプロイ)
-「動くアプリを本番環境に自動デプロイする仕組み」

  • 例: PRがマージされたら自動的に本番にデプロイされる。

何を自動化する?

GoのAPIサーバーだと、こんな作業を自動化します。

テストの実行

  • go test ./... を自動で実行
  • 失敗したらプルリクがマージできないようにする

Lint・静的解析

  • golangci-lint などでコードの静的チェックを自動化
  • コード品質を一定に保つ

Dockerビルド・動作確認

  • docker build でイメージを作って起動する
  • 必要なら docker-compose up でテストDB込みで統合テストを回す

デプロイ(必要に応じて)

  • 本番やステージングへのデプロイを自動化
  • 例: mainブランチにマージされたら本番へデプロイ

CI/CD導入のメリット

人為的なミスが減る

  • 「テスト忘れてた!」「設定間違えた!」がなくなる

プルリク・マージの安心感

  • 「ちゃんと全部テストが通ってる」とみんなで確認できる

本番でのトラブルが減る

  • 本番リリースまでの手順が自動化されるから、安全性アップ!

最初の一歩

CI/CDを難しそうに感じるかもしれませんが、最初は「テストを自動化するだけ」でも十分なスタートです。
例えばGitHub Actionsなら、以下のような最小構成を置くだけで動きます。

name: Go CI

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up Go
        uses: actions/setup-go@v4
        with:
          go-version: "1.19"
      - run: go test ./...

まとめ

GoでWeb APIサーバーを作るときは…

✅ まずは小さく「Hello, World!」から
✅ 設計を決めて、順にAPIを作っていく
✅ ミドルウェア・テストを整備して信頼性アップ
✅ 仕組みを整えていくとチーム開発でも強い

こういう順番で、少しずつ「動くもの」を積み上げていくのが大事です。
最初から完璧を目指さず、まずは小さく作って育てるイメージで進めてみましょう。

Xでシェア
Facebookでシェア
LinkedInでシェア

記事に関するお問い合わせ📝

記事の内容に関するご質問、ご意見などは、下記よりお気軽にお問い合わせください。
ご質問フォームへ

技術支援などお仕事に関するお問い合わせ📄

技術支援やお仕事のご依頼に関するお問い合わせは、下記よりお気軽にお問い合わせください。
お問い合わせフォームへ

関連する技術ブログ

弊社の技術支援サービス

お問い合わせ

経営と現場をつなぐ“共創型”の技術支援。
成果に直結するチーム・技術・プロセスを共に整えます。

お問い合わせ