カテゴリ: Go言語 更新日: 2026/03/07

Go言語のMVCパターンとAPIアーキテクチャの関係!初心者でもわかる設計パターン完全ガイド

Go言語のMVCパターンとAPIアーキテクチャの関係
Go言語のMVCパターンとAPIアーキテクチャの関係

先生と生徒の会話形式で理解しよう

生徒

「Go言語でWeb APIを作っているんですが、MVCパターンっていうのを使うべきでしょうか?APIとMVCってどう関係しているんですか?」

先生

「MVCパターンは、Webアプリケーションでよく使われる設計パターンです。APIアーキテクチャでも考え方は応用できますが、少し形を変えて使うことが多いですね。」

生徒

「MVCとAPIって、どう違うんですか?どちらも同じように使えないんですか?」

先生

「それでは、MVCパターンの基本から、APIアーキテクチャでどのように応用するのか、詳しく見ていきましょう!」

1. MVCパターンとは何か?

1. MVCパターンとは何か?
1. MVCパターンとは何か?

MVCパターンとは、Model-View-Controllerの略で、アプリケーションを3つの役割に分けて設計する手法です。このパターンは、1970年代に考案され、現在でも広く使われている定番の設計パターンです。

Model(モデル)は、データとビジネスロジックを担当します。例えば、ユーザー情報や商品情報などのデータ構造と、それらを操作する処理を含みます。データベースとのやり取りもこの部分で行います。

View(ビュー)は、画面表示を担当します。HTMLを生成したり、ユーザーが見る画面を作ったりする部分です。Modelから受け取ったデータを、見やすい形で表示します。

Controller(コントローラー)は、ModelとViewの橋渡しをします。ユーザーからのリクエストを受け取り、Modelを呼び出してデータを取得し、Viewに渡して画面を表示する役割を果たします。

例えるなら、レストランのようなものです。お客さん(ユーザー)が注文を伝えると、ウェイター(Controller)がそれを聞き、厨房(Model)に伝えます。厨房で料理ができたら、ウェイターが美しく盛り付けられた料理(View)をお客さんに提供します。

2. APIアーキテクチャとMVCの違い

2. APIアーキテクチャとMVCの違い
2. APIアーキテクチャとMVCの違い

従来のMVCパターンは、HTMLを返すWebアプリケーション向けに設計されていました。しかし、現代のWeb開発では、JSON形式でデータを返すAPIが主流になっています。

APIアーキテクチャとMVCパターンの最大の違いは、Viewの扱いです。従来のMVCでは、サーバー側でHTMLを生成してブラウザに返しますが、APIではJSONやXML形式のデータだけを返します。画面の表示は、フロントエンド側(ReactやVue.jsなど)が担当します。

従来のMVC

サーバーがHTMLを生成して返す。View層でテンプレートエンジンを使ってHTMLを作成。ブラウザはそのままHTMLを表示するだけ。

API方式

サーバーがJSONデータを返す。View層は存在しないか、最小限。フロントエンド側でデータを受け取って画面を構築。

このため、Go言語でAPIを作る場合、MVCをそのまま使うのではなく、MVC-R(Model-View-Controller-Repository)やMCS(Model-Controller-Service)といった変形版を使うことが多くなります。

3. Go言語でのModelの実装

3. Go言語でのModelの実装
3. Go言語でのModelの実装

それでは、実際のGo言語のコードで、MVCパターンをAPIアーキテクチャに適用してみましょう。まずはModelから見ていきます。


package model

import "time"

type User struct {
    ID        int       `json:"id"`
    Name      string    `json:"name"`
    Email     string    `json:"email"`
    CreatedAt time.Time `json:"created_at"`
}

func (u *User) Validate() error {
    if u.Name == "" {
        return errors.New("名前は必須です")
    }
    if u.Email == "" {
        return errors.New("メールアドレスは必須です")
    }
    if !strings.Contains(u.Email, "@") {
        return errors.New("有効なメールアドレスを入力してください")
    }
    return nil
}

このコードでは、User構造体でユーザーのデータ構造を定義しています。JSONタグを付けることで、JSON形式への変換が自動的に行われます。Validateメソッドは、ユーザーデータが正しいかどうかを検証するビジネスロジックです。Modelには、このようにデータ構造とそれに関連するビジネスルールを実装します。

4. Go言語でのControllerの実装

4. Go言語でのControllerの実装
4. Go言語でのControllerの実装

次に、Controllerを実装します。APIアーキテクチャでは、ControllerはHTTPリクエストを受け取り、適切な処理を実行して、JSON形式のレスポンスを返します。


package controller

import (
    "encoding/json"
    "net/http"
    "strconv"
    "myapp/model"
    "myapp/service"
)

type UserController struct {
    userService *service.UserService
}

func NewUserController(userService *service.UserService) *UserController {
    return &UserController{userService: userService}
}

func (c *UserController) GetUser(w http.ResponseWriter, r *http.Request) {
    idStr := r.URL.Query().Get("id")
    id, err := strconv.Atoi(idStr)
    if err != nil {
        c.respondError(w, http.StatusBadRequest, "無効なIDです")
        return
    }
    
    user, err := c.userService.GetByID(id)
    if err != nil {
        c.respondError(w, http.StatusNotFound, "ユーザーが見つかりません")
        return
    }
    
    c.respondJSON(w, http.StatusOK, user)
}

func (c *UserController) respondJSON(w http.ResponseWriter, status int, data interface{}) {
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(status)
    json.NewEncoder(w).Encode(data)
}

func (c *UserController) respondError(w http.ResponseWriter, status int, message string) {
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(status)
    json.NewEncoder(w).Encode(map[string]string{"error": message})
}

このコードでは、UserControllerがHTTPリクエストを処理しています。GetUserメソッドは、URLパラメータからユーザーIDを取得し、ServiceLayerを通じてデータを取得します。そして、JSON形式でレスポンスを返します。従来のMVCと違い、HTMLテンプレートを使わず、JSONで直接データを返している点が特徴です。

5. ServiceLayerの追加

5. ServiceLayerの追加
5. ServiceLayerの追加

APIアーキテクチャでは、ControllerとModelの間にServiceLayerを配置することが一般的です。ServiceLayerは、ビジネスロジックを担当し、Controllerを軽量に保ちます。


package service

import (
    "errors"
    "myapp/model"
    "myapp/repository"
)

type UserService struct {
    userRepo *repository.UserRepository
}

func NewUserService(userRepo *repository.UserRepository) *UserService {
    return &UserService{userRepo: userRepo}
}

func (s *UserService) GetByID(id int) (*model.User, error) {
    if id <= 0 {
        return nil, errors.New("IDは正の整数である必要があります")
    }
    return s.userRepo.FindByID(id)
}

func (s *UserService) CreateUser(name, email string) (*model.User, error) {
    user := &model.User{
        Name:  name,
        Email: email,
    }
    
    if err := user.Validate(); err != nil {
        return nil, err
    }
    
    exists, err := s.userRepo.ExistsByEmail(email)
    if err != nil {
        return nil, err
    }
    if exists {
        return nil, errors.New("このメールアドレスは既に使用されています")
    }
    
    return s.userRepo.Save(user)
}

ServiceLayerは、複数のRepositoryを組み合わせたり、複雑なビジネスルールを実装したりする場所です。この層を追加することで、Controllerはリクエストの処理だけに集中でき、ビジネスロジックとHTTP処理が分離されます。

6. RepositoryLayerの役割

6. RepositoryLayerの役割
6. RepositoryLayerの役割

RepositoryLayerは、データベースとのやり取りを担当します。MVCパターンのModelの一部として扱われることもありますが、APIアーキテクチャでは独立した層として分離することが推奨されます。


package repository

import (
    "database/sql"
    "myapp/model"
)

type UserRepository struct {
    db *sql.DB
}

func NewUserRepository(db *sql.DB) *UserRepository {
    return &UserRepository{db: db}
}

func (r *UserRepository) FindByID(id int) (*model.User, error) {
    query := "SELECT id, name, email, created_at FROM users WHERE id = ?"
    
    user := &model.User{}
    err := r.db.QueryRow(query, id).Scan(
        &user.ID,
        &user.Name,
        &user.Email,
        &user.CreatedAt,
    )
    
    if err == sql.ErrNoRows {
        return nil, errors.New("ユーザーが見つかりません")
    }
    if err != nil {
        return nil, err
    }
    
    return user, nil
}

func (r *UserRepository) ExistsByEmail(email string) (bool, error) {
    query := "SELECT COUNT(*) FROM users WHERE email = ?"
    var count int
    err := r.db.QueryRow(query, email).Scan(&count)
    return count > 0, err
}

func (r *UserRepository) Save(user *model.User) (*model.User, error) {
    query := "INSERT INTO users (name, email, created_at) VALUES (?, ?, ?)"
    result, err := r.db.Exec(query, user.Name, user.Email, time.Now())
    if err != nil {
        return nil, err
    }
    
    id, err := result.LastInsertId()
    if err != nil {
        return nil, err
    }
    
    user.ID = int(id)
    return user, nil
}

Repositoryパターンを使うことで、データベースの実装を簡単に切り替えられます。例えば、MySQLからPostgreSQLに変更する場合、Repository層だけを書き換えれば、Service層やController層には影響を与えません。

7. REST APIとMVCの組み合わせ

7. REST APIとMVCの組み合わせ
7. REST APIとMVCの組み合わせ

REST APIでは、HTTPメソッド(GET、POST、PUT、DELETE)を使って、リソースに対する操作を表現します。MVCパターンをREST APIに適用する場合、各HTTPメソッドに対応するControllerメソッドを実装します。

HTTPメソッド URLパターン Controllerメソッド 動作
GET /users ListUsers ユーザー一覧を取得
GET /users/:id GetUser 特定のユーザーを取得
POST /users CreateUser 新しいユーザーを作成
PUT /users/:id UpdateUser ユーザー情報を更新
DELETE /users/:id DeleteUser ユーザーを削除

このように、RESTの原則に従って、各リソースに対する操作をControllerのメソッドとして実装します。URLとHTTPメソッドの組み合わせで、どの操作を実行するかが決まります。

8. APIアーキテクチャでのディレクトリ構成

8. APIアーキテクチャでのディレクトリ構成
8. APIアーキテクチャでのディレクトリ構成

Go言語でMVCパターンをAPIアーキテクチャに適用する場合、以下のようなディレクトリ構成が推奨されます。


myapi/
├── cmd/
│   └── server/
│       └── main.go
├── internal/
│   ├── controller/
│   │   └── user_controller.go
│   ├── service/
│   │   └── user_service.go
│   ├── repository/
│   │   └── user_repository.go
│   ├── model/
│   │   └── user.go
│   └── middleware/
│       ├── auth.go
│       └── logger.go
├── pkg/
│   └── database/
│       └── connection.go
├── api/
│   └── routes.go
└── go.mod

この構成では、controllerディレクトリがMVCのController、serviceディレクトリがビジネスロジック、repositoryディレクトリがデータアクセス、modelディレクトリがModelに対応しています。middlewareディレクトリには、認証やログ出力などの共通処理を配置します。apiディレクトリには、ルーティング設定を配置します。

9. ミドルウェアとの連携

9. ミドルウェアとの連携
9. ミドルウェアとの連携

APIアーキテクチャでは、ミドルウェアという仕組みを使って、共通処理を効率的に実装できます。ミドルウェアは、リクエストがControllerに到達する前や、レスポンスが返される前に実行される処理です。

認証ミドルウェア

ユーザーが正しくログインしているかを確認します。認証に失敗した場合、Controllerに処理が渡らず、エラーレスポンスを返します。

ロギングミドルウェア

全てのリクエストとレスポンスをログに記録します。どのエンドポイントにどんなリクエストが来たか、処理時間はどのくらいかなどを記録できます。

レート制限ミドルウェア

短時間に大量のリクエストが来た場合に、一時的にアクセスを制限します。サーバーへの負荷を軽減し、DoS攻撃を防ぎます。

ミドルウェアを使うことで、Controllerは本来の処理だけに集中でき、認証やログ出力といった共通処理を別の場所で管理できます。これにより、コードの重複を減らし、保守性を高めることができます。

Go言語を基礎からスッキリ学びたい人や、 文法だけでなく「実用的な使い方」まで押さえたい人には、 定番の入門書がこちらです。

基礎からわかるGo言語をAmazonで見る

※ Amazon広告リンク

10. MVCとAPIアーキテクチャの実践的な使い分け

10. MVCとAPIアーキテクチャの実践的な使い分け
10. MVCとAPIアーキテクチャの実践的な使い分け

MVCパターンとAPIアーキテクチャは、それぞれ適した用途があります。プロジェクトの特性に応じて、適切な方を選択しましょう。

従来のMVCが適している場合

  • サーバー側でHTMLを生成する必要がある
  • SEO対策が重要で、初期表示速度を優先したい
  • シンプルな管理画面や社内システム
  • フロントエンドフレームワークを使わない場合

APIアーキテクチャが適している場合

  • フロントエンドとバックエンドを分離したい
  • モバイルアプリとWebアプリで同じAPIを使いたい
  • React、Vue.js、Angularなどのフロントエンドフレームワークを使う
  • マイクロサービスアーキテクチャを採用している

現代のWeb開発では、APIアーキテクチャが主流になっています。フロントエンドとバックエンドを分離することで、それぞれの技術を独立して選択でき、開発チームも分けやすくなります。Go言語は、高速で並行処理に強いため、APIサーバーの構築に非常に適しています。

MVCパターンの考え方を理解した上で、APIアーキテクチャに適用することで、保守性が高く、拡張しやすいシステムを構築できます。最初は複雑に感じるかもしれませんが、各層の役割を理解し、実際にコードを書いていくことで、自然と身についていくでしょう。

関連セミナーのご案内

【超入門】ゼロから始めるGo言語プログラミング:最速で「動くアプリ」を作るマンツーマン指導

「プログラミングの仕組み」が根本からわかる。Go言語でバックエンド開発の第一歩を。

本講座を受講することで、単なる文法の暗記ではなく、「プログラムがコンピュータの中でどう動いているか」という本質的な理解につながります。シンプルながら強力なGo言語(Golang)を通じて、現代のバックエンドエンジニアに求められる基礎体力を最短距離で身につけます。

具体的な開発内容と環境

【つくるもの】
ターミナル(黒い画面)上で動作する「対話型計算プログラム」や、データを整理して表示する「ミニ・ツール」をゼロから作成します。自分の書いたコードが形になる感動を体験してください。

【開発環境】
プロの現場でシェアNo.1のVisual Studio Code (VS Code)を使用します。インストールから日本語化、Go言語用の拡張機能設定まで、現場基準の環境を一緒に構築します。

この60分で得られる3つの理解

1. 環境構築の完全な理解

「なぜ動くのか」という設定の仕組みを理解し、今後の独学で詰まらない土台を作ります。

2. Go言語の基本構造(変数・型)

データの種類やメモリの概念など、他言語にも通じるプログラミングの本質を学びます。

3. 読みやすいコードの書き方

ただ動くだけでなく、誰が見ても分かりやすい「綺麗なコード」を書くための考え方を伝授します。

※本講座は、将来的にバックエンドエンジニアクラウドインフラに興味がある未経験者のためのエントリー講座です。マンツーマン形式により、あなたの理解度に合わせて進行します。

セミナー画像

初めてのGo言語を一緒に学びましょう!

カテゴリの一覧へ
新着記事
New1
Swift
Swiftのnilとは?Optionalとの関係や初期化について初心者向けにやさしく解説!
New2
Swift
Swift文字列操作総まとめ|性能・安全性・多言語対応の指針
New3
Go言語
Go言語の配列の基本!定義・初期化・アクセス方法をやさしく解説
New4
Go言語
Go言語のARM向けクロスコンパイル完全ガイド Raspberry Piで動かすGoプログラムの作り方
人気記事
No.1
Java&Spring記事人気No1
Kotlin
Android Studioのインストール手順と初期設定を初心者向けに完全解説!
No.2
Java&Spring記事人気No2
Swift
Swift Playgroundの使い方を完全解説!初心者に最適な学習環境の始め方
No.3
Java&Spring記事人気No3
Kotlin
Gradleファイル(build.gradle.kts)の書き方と役割をやさしく解説!Kotlin初心者向け完全ガイド
No.4
Java&Spring記事人気No4
Swift
Swift開発環境の構築方法を徹底解説!Xcode・Windows・Linux対応
No.5
Java&Spring記事人気No5
Kotlin
Kotlinのメモリプロファイリングツールの使い方を完全解説!初心者でも理解できるメモリ使用量の調べ方
No.6
Java&Spring記事人気No6
Swift
Swift Xcode ArchiveとApp Store Connectへのアップロード完全ガイド!初心者でもわかる公開手順
No.7
Java&Spring記事人気No7
Kotlin
KotlinでAndroidアプリ開発を始める!基本環境構築からHello Worldまで
No.8
Java&Spring記事人気No8
Swift
Swift入門ガイド|基本構文と書き方をマスターしよう