Go言語とPostgreSQLを用いたREST API開発:sqlxを活用して親子関係のテーブルデータをJSONで統合する方法

本記事では、Go言語(Golang)、PostgreSQL、およびsqlxライブラリを使用して、親データと子データを取得し、それらをJSON形式で返すREST APIの構築方法を解説します。

ここでは、実際に使えるコード例を複数紹介し、データベースの操作方法を段階的に説明します。

コード例

商品データの取得

まず、商品情報を取得する基本的なAPIエンドポイントを作成します。

package main

import (
    "database/sql"
    "encoding/json"
    "log"
    "net/http"

    _ "github.com/lib/pq"
    "github.com/jmoiron/sqlx"
)

type Product struct {
    ID    int    `db:"id" json:"id"`
    Name  string `db:"name" json:"name"`
    Price int    `db:"price" json:"price"`
}

func main() {
    db, err := sqlx.Connect("postgres", "user=foo dbname=bar sslmode=disable")
    if err != nil {
        log.Fatalln(err)
    }

    http.HandleFunc("/products", func(w http.ResponseWriter, r *http.Request) {
        var products []Product
        if err := db.Select(&products, "SELECT * FROM products"); err != nil {
            log.Fatalln(err)
        }

        json.NewEncoder(w).Encode(products)
    })

    http.ListenAndServe(":8080", nil)
}

注文と商品詳細の統合

次に、注文情報とそれに関連する商品詳細を結合するクエリの例です。

// ...(前述のコードと同様のimport文)

type Order struct {
    ID         int      `db:"id" json:"id"`
    CustomerID int      `db:"customer_id" json:"customer_id"`
    Products   []Product `db:"products" json:"products"`
}

func main() {
    // ...(前述のDB接続コード)

    http.HandleFunc("/orders", func(w http.ResponseWriter, r *http.Request) {
        var orders []Order
        query := `
            SELECT orders.id, orders.customer_id, json_agg(products.*) as products
            FROM orders
            JOIN order_details ON orders.id = order_details.order_id
            JOIN products ON products.id = order_details.product_id
            GROUP BY orders.id`
        if err := db.Select(&orders, query); err != nil {
            log.Fatalln(err)
        }

        json.NewEncoder(w).Encode(orders)
    })

    http.ListenAndServe(":8080", nil)
}

複数テーブルの統合データ取得

最後に、顧客、注文、商品データを一度に取得する複雑なクエリの例を紹介します。

// ...(前述のコードと同様のimport文)

type CustomerOrder struct {
    CustomerID int     `db:"customer_id" json:"customer_id"`
    Orders     []Order `db:"orders" json:"orders"`
}

func main() {
    // ...(前述のDB接続コード)

    http.HandleFunc("/customer-orders", func(w http.ResponseWriter, r *http.Request) {
        var customerOrders []CustomerOrder
        query := `
            SELECT customers.id as customer_id, json_agg(json_build_object('id', orders.id, 'products', products)) as orders
            FROM customers
            JOIN orders ON customers.id = orders.customer_id
            JOIN order_details ON orders.id = order_details.order_id
            JOIN products ON products.id = order_details.product_id
            GROUP BY customers.id`
        if err := db.Select(&customerOrders, query); err != nil {
            log.Fatalln(err)
        }

        json.NewEncoder(w).Encode(customerOrders)
    })

    http.ListenAndServe(":8080", nil)
}

完成系

package main

import (
    "database/sql"
    "encoding/json"
    "log"
    "net/http"

    _ "github.com/lib/pq"
    "github.com/jmoiron/sqlx"
)

// 商品データ構造
type Product struct {
    ID    int    `db:"id" json:"id"`
    Name  string `db:"name" json:"name"`
    Price int    `db:"price" json:"price"`
}

// 注文データ構造
type Order struct {
    ID         int      `db:"id" json:"id"`
    CustomerID int      `db:"customer_id" json:"customer_id"`
    Products   []Product `db:"products" json:"products"`
}

// 顧客とその注文のデータ構造
type CustomerOrder struct {
    CustomerID int     `db:"customer_id" json:"customer_id"`
    Orders     []Order `db:"orders" json:"orders"`
}

func main() {
    db, err := sqlx.Connect("postgres", "user=foo dbname=bar sslmode=disable")
    if err != nil {
        log.Fatalln(err)
    }

    // 商品データ取得のエンドポイント
    http.HandleFunc("/products", func(w http.ResponseWriter, r *http.Request) {
        var products []Product
        if err := db.Select(&products, "SELECT * FROM products"); err != nil {
            log.Fatalln(err)
        }
        json.NewEncoder(w).Encode(products)
    })

    // 注文と商品詳細の統合エンドポイント
    http.HandleFunc("/orders", func(w http.ResponseWriter, r *http.Request) {
        var orders []Order
        query := `
            SELECT orders.id, orders.customer_id, json_agg(products.*) as products
            FROM orders
            JOIN order_details ON orders.id = order_details.order_id
            JOIN products ON products.id = order_details.product_id
            GROUP BY orders.id`
        if err := db.Select(&orders, query); err != nil {
            log.Fatalln(err)
        }
        json.NewEncoder(w).Encode(orders)
    })

    // 顧客と注文の統合エンドポイント
    http.HandleFunc("/customer-orders", func(w http.ResponseWriter, r *http.Request) {
        var customerOrders []CustomerOrder
        query := `
            SELECT customers.id as customer_id, json_agg(json_build_object('id', orders.id, 'products', products)) as orders
            FROM customers
            JOIN orders ON customers.id = orders.customer_id
            JOIN order_details ON orders.id = order_details.order_id
            JOIN products ON products.id = order_details.product_id
            GROUP BY customers.id`
        if err := db.Select(&customerOrders, query); err != nil {
            log.Fatalln(err)
        }
        json.NewEncoder(w).Encode(customerOrders)
    })

    http.ListenAndServe(":8080", nil)
}

まとめ

この記事では、Go言語、PostgreSQL、sqlxライブラリを用いたECアプリケーション開発におけるREST APIの作成方法を紹介しました。商品情報、注文データ、顧客情報を統合して効率的なAPIエンドポイントを構築することで、柔軟かつ効果的なデータ管理が可能になります。これらのテクニックを活用し、高品質なECアプリケーションの開発に役立ててください。

タイトルとURLをコピーしました