この記事の一部は機械翻訳を使ってるよ
Go バックエンドのシンプルな (非技術的なフレームワーク) 実装
~~皆さんご存知のとおり、~~バックエンド開発は一般的にインターフェース指向開発、つまり CRUD エンジニアです。この記事では、Go を使用して、データベースからデータを読み取り、JSON データを返す方法について説明します。
データベース
この例では、MySQL データベースのカテゴリ テーブルからカテゴリ名と ID を読み取ります。テーブル構造は次のとおりです。
DROP TABLE IF EXISTS categories ;
CREATE TABLE categories (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description VARCHAR(255)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
プロジェクト構造
この例のプロジェクト構造は次のようになります。
project/
├── database/ // データベースパッケージ
│ └── database.go // データベース接続
├── handler/ // ハンドラパッケージ
│ └── category.go // カテゴリ関連のインターフェース
├── model/ // データモデルパッケージ
│ ├── category.go // カテゴリテーブルモデル
│ └── response.go // レスポンスデータモデル
├── router/ // ルーティングパッケージ
│ └── router.go // ルーティング設定
├── utils // ツールキット
│ └── response.go // 統合レスポンス
├── main.go // プログラムエントリ
次にディレクトリについて説明します
database
このパッケージはデータベースへの接続を管理します
// database.go
package database
import (
"database/sql"
"fmt"
"log"
_ "github.com/go-sql-driver/mysql"
)
var DB *sql.DB
func InitDB() {
var err error
dsn := "username:password@tcp(address:3306)/name?charset=utf8"
DB, err = sql.Open("mysql", dsn)
if err != nil {
log.Fatalf("Failed to open database: %v", err)
}
// Test Connect
err = DB.Ping()
if err != nil {
log.Fatalf("Failed to ping database: %v", err)
}
fmt.Println("Successfully connected Database!")
}
handler
このパッケージは、特定の処理のロジック(3 層アーキテクチャの service に似ています)を処理して、データベース処理も階層化できます(Mapper に似ています)が、これは単なる簡単な例です、それだけです〜
// category.go
package handler
import (
"net/http"
"project/database"
"project/model"
"project/utils"
)
func GetCategories(w http.ResponseWriter, r *http.Request) {
// Select Database
rows, err := database.DB.Query("select id,name from categories")
if err != nil {
http.Error(w, "Failed to query Categories", http.StatusInternalServerError)
return
}
defer rows.Close()
// analyze data
var categories []model.Category
for rows.Next() {
var category model.Category
err = rows.Scan(&category.Id, &category.Name)
if err != nil {
utils.JSONResponse(w, http.StatusInternalServerError, "Failed to analyze Categories", nil)
//http.Error(w, "Failed to analyze Categories", http.StatusInternalServerError)
return
}
categories = append(categories, category)
}
// return JSON
//w.Header().Set("Content-Type", "application/json")
//json.NewEncoder(w).Encode(categories)
utils.JSONResponse(w, http.StatusOK, "", categories)
}
コメントアウトされた内容は統合レスポンスインターフェースには適用されず、JSON が直接返されます。
model
ここでのデータモデルは、一般的にフロントエンドから受け取るもの、データベースから受け取るもの、フロントエンドに返すものの 3 つに分けられます。これは単純な例なので、細かくは説明していません。
// category.go
package model
type Category struct {
Id int `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
}
応答のデータモデルは
package model
type Response struct {
Code int `json:"code"`
Msg string `json:"msf"`
Data interface{} `json:"data"`
}
router
このパッケージはルーティング、つまり、どのパスにアクセスして対応する処理ロジックを指定するかを管理します(3 層アーキテクチャの controller に似ています)
// router.go
package router
import (
"github.com/gorilla/mux"
"project/handler"
)
func InitRouter() *mux.Router {
router := mux.NewRouter()
router.HandleFunc("/categories", handler.GetCategories).Methods("GET")
return router
}
utils
このパッケージはツールクラスであり、一般的なツールを定義するために使用されます
// response.go
package utils
import (
"encoding/json"
"log"
"net/http"
"project/model"
)
func JSONResponse(w http.ResponseWriter, code int, message string, data interface{}) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(http.StatusOK)
err := json.NewEncoder(w).Encode(model.Response{Code: code, Msg: message, Data: data})
if err != nil {
log.Fatal(err)
return
}
}
main
プログラムエントリー
// main.go
package main
import (
"log"
"net/http"
"project/database"
"project/router"
)
func main() {
// init Database
database.InitDB()
// Init Router
r := router.InitRouter()
// start
log.Println("Starting server on port 8848")
log.Fatal(http.ListenAndServe(":8848", r))
}
go run main.go
を実行すると、プログラムはポート 8848 をリッスンします。