こんにちは。KOUKIです。
とあるWeb系企業でエンジニアをやってます。
今日は、Go言語のWebフレームワークであるFiberとORMライブラリであるGORMを使って、簡単なWebアプリケーションを実装します。
めちゃくちゃ簡単ですが説明は省きますので、中級者向けの内容かも知れません。
下記のYoutubeを参考にしました。というかめっちゃそのままです。
<目次>
プロジェクトの準備
最初にプロジェクトを用意しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
mkdir fiber-app cd fiber-app go mod init fiber-app touch main.go mkdir book touch book/book.go mkdir repository touch repository/sqlite.go # Install module go get github.com/gofiber/fiber/v2 go get github.com/jinzhu/gorm go get github.com/jinzhu/gorm/dialects/sqlite |
Webサーバーの実装
Fiberを使って、簡単なWebサーバーを構築します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// main.go package main import ( "log" "github.com/gofiber/fiber/v2" ) func helloworld(c *fiber.Ctx) error { return c.SendString("Hello, World!!!!") } func main() { app := fiber.New() app.Get("/", helloworld) log.Fatal(app.Listen(":8080")) } |
Webサーバーは、下記のコマンドで起動します。
1 2 3 4 5 6 7 8 9 10 |
$ go run main.go ┌───────────────────────────────────────────────────┐ │ Fiber v2.27.0 │ │ http://127.0.0.1:8080 │ │ (bound on host 0.0.0.0 and port 8080) │ │ │ │ Handlers ............. 2 Processes ........... 1 │ │ Prefork ....... Disabled PID .............. 2668 │ └───────────────────────────────────────────────────┘ |
ブラウザから「http://localhost:8080」にアクセスしてみましょう。

OKですね。簡単ですが、Webサーバーを作成しました。
ハンドラーの実装
続いて、ハンドラーを実装しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// book.go package book import ( "github.com/gofiber/fiber/v2" ) func GetBooks(c *fiber.Ctx) error { return c.SendString("All Books") } func GetBook(c *fiber.Ctx) error { return c.SendString("A Single Book") } func NewBook(c *fiber.Ctx) error { return c.SendString("Adds a new book") } func DeleteBook(c *fiber.Ctx) error { return c.SendString("Deletes a Book") } |
このハンドラーは、main.goから登録します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
// main.go package main import ( "log" "fiber-app/book" "github.com/gofiber/fiber/v2" ) func setupRoutes(app *fiber.App) { app.Get("/api/v1/books", book.GetBooks) app.Get("/api/v1/book/:id", book.GetBook) app.Post("/api/v1/book", book.NewBook) app.Delete("/api/v1/book/:id", book.DeleteBook) } func main() { app := fiber.New() setupRoutes(app) log.Fatal(app.Listen(":8080")) } |
下記のコマンドで、Webサーバーを起動し、Curlでテストしましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# Webサーバーの起動 $ go run main.go # テスト $ curl -X GET http://localhost:8080/api/v1/books All Books $ curl -X GET http://localhost:8080/api/v1/book/1 A Single Book $ curl -X POST http://localhost:8080/api/v1/book Adds a new book $ curl -X DELETE http://localhost:8080/api/v1/book/1 Deletes a Book |
OKですね。
DB Connectionの実装
続いて、DB Connection処理を実装していきましょう。ちなみに、sqlite3に接続します。
sqlite3はローカルにファイル(DB)を作成してくれるので、MySQLやPostgresのようにDBを構築する必要はありません。
手軽にGORMの機能を試せるわけですね^^
1 2 3 4 5 6 7 8 9 10 11 |
// sqlite.go package repository import ( "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/sqlite" ) var ( DBConn *gorm.DB ) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
// main.go package main import ( "log" "fiber-app/book" "fiber-app/repository" "github.com/gofiber/fiber/v2" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/sqlite" ) func setupRoutes(app *fiber.App) {...} func initDatabase() { var err error repository.DBConn, err = gorm.Open("sqlite3", "books.db") if err != nil { panic("Oh My God!!! DB Connection fail!") } log.Println("Database connection successfully opend!") } func main() { app := fiber.New() initDatabase() defer repository.DBConn.Close() setupRoutes(app) log.Fatal(app.Listen(":8080")) } |
下記のコマンドで、Webサーバーを起動してみましょう(停止はCtrl + cです)。
1 2 3 4 5 6 7 8 9 10 |
$ go run main.go 2022/02/22 05:37:45 Database connection successfully opend! ┌───────────────────────────────────────────────────┐ │ Fiber v2.27.0 │ │ http://127.0.0.1:8080 │ │ (bound on host 0.0.0.0 and port 8080) │ │ │ │ Handlers ............. 6 Processes ........... 1 │ │ Prefork ....... Disabled PID .............. 2758 │ |
「Database connection successfully opend!」と出たので、OKですね。
接続に成功するとローカルに「books.db」ファイルが作成されます。
1 2 3 4 5 6 7 8 9 10 |
$ tree . ├── book │ └── book.go ├── books.db <<<<<<<<<<<<<<<<<<<<<<<<<<< ⭐️ ├── go.mod ├── go.sum ├── main.go └── repository └── sqlite.go |
マイグレーション処理の実装
次に、マイグレーション処理の実装を行います。
book.goにBook Structを定義します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// book.go package book import ( "github.com/gofiber/fiber/v2" "github.com/jinzhu/gorm" ) type Book struct { gorm.Model Title string `json:"title"` Author string `json:"author"` Rating int `json:"rating"` } |
この構造体が、DBのスキーマーになります。
また、「gorm.Model」は、下記の構造体です。
1 2 3 4 5 6 |
type Model struct { ID uint `gorm:"primary_key"` CreatedAt time.Time UpdatedAt time.Time DeletedAt *time.Time `sql:"index"` } |
リクエスト受信時に上記のパラメータが自動的に更新されるので、大変便利です。
GORMには、(大変便利なことに)マイグレーションを実行するAutoMigrateメソッドが定義されています。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// main.go package main func initDatabase() { var err error repository.DBConn, err = gorm.Open("sqlite3", "books.db") if err != nil { panic("Oh My God!!! DB Connection fail!") } log.Println("Database connection successfully opend!") repository.DBConn.AutoMigrate(&book.Book{}) log.Println("Database Migrated") } |
Webサーバーを起動し直しましょう。
1 2 3 |
$ go run main.go 2022/02/22 05:48:59 Database connection successfully opend! 2022/02/22 05:48:59 Database Migrated |
OKですね。
GetBooksの実装
GetBooksの中身を実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// book.go package book import ( "fiber-app/repository" "github.com/gofiber/fiber/v2" "github.com/jinzhu/gorm" ) type Book struct { gorm.Model Title string `json:"title"` Author string `json:"author"` Rating int `json:"rating"` } func GetBooks(c *fiber.Ctx) error { db := repository.DBConn var books []Book db.Find(&books) return c.JSON(books) } |
db.Find(&books)では、DBの検索結果をBookのスライスにそのまま格納してくれます。めちゃくちゃ便利です。
ただし、現状はDBは空なのでCurlを打っても「[]」が返却されます。
1 2 3 4 5 6 |
$ go run main.go 2022/02/22 05:51:21 Database connection successfully opend! 2022/02/22 05:51:21 Database Migrated $ curl -X GET http://localhost:8080/api/v1/books [] |
GetBookの実装
GetBookを実装します。
1 2 3 4 5 6 7 8 |
func GetBook(c *fiber.Ctx) error { // URLからidを取り出す id := c.Params("id") db := repository.DBConn var book Book db.Find(&book, id) return c.JSON(book) } |
URLの定義が、「”/api/v1/book/:id”」になっていたと思います。
c.Params(“id”)にて、「:id」に指定された値を取得することが可能です。
NewBookの実装
NewBookを実装します。
1 2 3 4 5 6 7 8 9 10 |
func NewBook(c *fiber.Ctx) error { db := repository.DBConn var book Book book.Title = "2021" book.Author = "SelfNote" book.Rating = 5 db.Create(&book) return c.JSON(book) } |
下記のボタンで、Webサーバーを起動します。
1 2 3 |
$ go run main.go 2022/02/22 13:12:34 Database connection successfully opend! 2022/02/22 13:12:34 Database Migrated |
curlで動作確認をしましょう。
1 2 3 4 5 6 7 8 |
$ curl -X POST http://localhost:8080/api/v1/book {"ID":1,"CreatedAt":"2022-02-22T13:13:11.800387+09:00","UpdatedAt":"2022-02-22T13:13:11.800387+09:00","DeletedAt":null,"title":"2021","author":"SelfNote","rating":5} $ curl -X GET http://localhost:8080/api/v1/book/1 {"ID":1,"CreatedAt":"2022-02-22T13:13:11.800387+09:00","UpdatedAt":"2022-02-22T13:13:11.800387+09:00","DeletedAt":null,"title":"2021","author":"SelfNote","rating":5} $ curl -X GET http://localhost:8080/api/v1/books [{"ID":1,"CreatedAt":"2022-02-22T13:13:11.800387+09:00","UpdatedAt":"2022-02-22T13:13:11.800387+09:00","DeletedAt":null,"title":"2021","author":"SelfNote","rating":5}] |
OKですね。
DeleteBookの実装
最後にDeleteBookの実装をしましょう。
1 2 3 4 5 6 7 8 9 10 11 12 |
func DeleteBook(c *fiber.Ctx) error { id := c.Params("id") db := repository.DBConn var book Book db.First(&book, id) if book.Title == "" { return c.Status(500).SendString("No book found with given ID") } db.Delete(&book) return c.SendString("Book successfully deleted") } |
最初にDBからデータを取得し、取得したデータをもとに削除をしました。
下記のコマンドで、Webサーバーを起動しましょう。
1 2 3 |
$ go run main.go 2022/02/22 13:18:59 Database connection successfully opend! 2022/02/22 13:18:59 Database Migrated |
1 2 3 4 5 6 7 8 9 10 11 12 |
$ curl -X GET http://localhost:8080/api/v1/book/1 {"ID":1,"CreatedAt":"2022-02-22T13:13:11.800387+09:00","UpdatedAt":"2022-02-22T13:13:11.800387+09:00","DeletedAt":null,"title":"2021","author":"SelfNote","rating":5} $ curl -X DELETE http://localhost:8080/api/v1/book/1 Book successfully deleted $ curl -X GET http://localhost:8080/api/v1/book/1 {"ID":0,"CreatedAt":"0001-01-01T00:00:00Z","UpdatedAt":"0001-01-01T00:00:00Z","DeletedAt":null,"title":"","author":"","rating":0} $ curl -X DELETE http://localhost:8080/api/v1/book/1 No book found with given ID |
OKですね。
NewBook改
NewBookを改良します。
1 2 3 4 5 6 7 8 9 10 11 |
func NewBook(c *fiber.Ctx) error { db := repository.DBConn book := new(Book) if err := c.BodyParser(book); err != nil { return c.Status(503).SendString(err.Error()) } db.Create(&book) return c.JSON(book) } |
今度は、リクエストパラメータの値を利用してデータを作成するように実装しました。
BodyParserは、リクエストしたデータをそのままGoのStructにはめ込んでくれる便利メソッドです。
下記のコマンドで、Webサーバーを起動します。
1 2 3 |
$ go run main.go 2022/02/22 13:25:56 Database connection successfully opend! 2022/02/22 13:25:56 Database Migrated |
1 2 3 4 5 |
$ curl -X POST -H "Content-Type: application/json" --data "{\"title\": \"2021\", \"author\": \"Selfnote\", \"rating\": 5}" http://localhost:8080/api/v1/book {"ID":2,"CreatedAt":"2022-02-22T13:29:19.034613+09:00","UpdatedAt":"2022-02-22T13:29:19.034613+09:00","DeletedAt":null,"title":"2021","author":"Selfnote","rating":5} $ curl -X GET http://localhost:8080/api/v1/book/2 {"ID":2,"CreatedAt":"2022-02-22T13:29:19.034613+09:00","UpdatedAt":"2022-02-22T13:29:19.034613+09:00","DeletedAt":null,"title":"2021","author":"Selfnote","rating":5} |
OKですね。
まとめ
sqlite3を使うとDB操作系のプログラムをサクッとかけてとても便利ですね。
また、GORMを利用するとマイグレーションやDB操作プログラムなどお手軽に実装できます。
あとは、処理速度ですね。GORMの処理速度は早いのか気になるところです。
それでは、また!
次回
次回は、HTTPリクエストのUnit Testを実装します。
Go言語まとめ
ソースコード
main.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
// main.go package main import ( "log" "fiber-app/book" "fiber-app/repository" "github.com/gofiber/fiber/v2" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/sqlite" ) func setupRoutes(app *fiber.App) { app.Get("/api/v1/books", book.GetBooks) app.Get("/api/v1/book/:id", book.GetBook) app.Post("/api/v1/book", book.NewBook) app.Delete("/api/v1/book/:id", book.DeleteBook) } func initDatabase() { var err error repository.DBConn, err = gorm.Open("sqlite3", "books.db") if err != nil { panic("Oh My God!!! DB Connection fail!") } log.Println("Database connection successfully opend!") repository.DBConn.AutoMigrate(&book.Book{}) log.Println("Database Migrated") } func main() { app := fiber.New() initDatabase() defer repository.DBConn.Close() setupRoutes(app) log.Fatal(app.Listen(":8080")) } |
book.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
// book.go package book import ( "fiber-app/repository" "github.com/gofiber/fiber/v2" "github.com/jinzhu/gorm" ) type Book struct { gorm.Model Title string `json:"title"` Author string `json:"author"` Rating int `json:"rating"` } func GetBooks(c *fiber.Ctx) error { db := repository.DBConn var books []Book db.Find(&books) return c.JSON(books) } func GetBook(c *fiber.Ctx) error { // URLからidを取り出す id := c.Params("id") db := repository.DBConn var book Book db.Find(&book, id) return c.JSON(book) } func NewBook(c *fiber.Ctx) error { db := repository.DBConn book := new(Book) if err := c.BodyParser(book); err != nil { return c.Status(503).SendString(err.Error()) } db.Create(&book) return c.JSON(book) } func DeleteBook(c *fiber.Ctx) error { id := c.Params("id") db := repository.DBConn var book Book db.First(&book, id) if book.Title == "" { return c.Status(500).SendString("No book found with given ID") } db.Delete(&book) return c.SendString("Book successfully deleted") } |
sqlite.go
1 2 3 4 5 6 7 8 9 10 11 |
// sqlite.go package repository import ( "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/sqlite" ) var ( DBConn *gorm.DB ) |
コメントを残す
コメントを投稿するにはログインしてください。