🦸🏼‍♂️

Iris(Go言語フレームワーク)の使い方を最速でマスターする

2022/04/25に公開
2

初めに

https://www.iris-go.com

Irisロゴ
Iris のマスコットキャラクターらしい(可愛い)

Iris(アイリス)とは何か

Iris はGo言語で書かれたWebフレームワークです.

公式サイトでも『最速のWebフレームワーク』を謳っており,Webサーバ・デスクトップ・スマートフォンなど様々な環境を問わず超高速のパフォーマンスを発揮します

その他の特徴としてクロスプラットフォーム・MVCモデルなどが挙げられます
また,Go言語フレームワークの中でも圧倒的なドキュメント量を実現しており,情報量の多さから最も効率良く学習が出来るともいえます.

実際に,Go言語のwebフレームワークを専門にさまざまな比較を行なっているリポジトリ を参考に他のGoフレームワークと比較してみます

高速性

Iris の最大の特徴は『最速のWebフレームワークである』ということです

他のどのHTTP/2フレームワークよりも高速に動作し,数多くの競合フレームワークと1秒あたりのリクエスト数・転送されたデータ・リクエストとレスポンスの間の時間の測定(ベンチマーク)を実行したところ一番優秀な数値を叩き出しています

Name Language Reqs/sec Latency Throughput Time To Complete
Iris Go 150430 826.05us 41.25MB 1.33s
Chi Go 146274 0.85ms 39.32MB 1.37s
Gin Go 141664 0.88ms 38.74MB 1.41s
Echo Go 138915 0.90ms 38.15MB 1.44s
Kestrel C# 136935 0.91ms 39.79MB 1.47s
Martini Go 128590 0.97ms 34.57MB 1.56s
Buffalo Go 58954 2.12ms 16.18MB 3.40s
Koa JavaScript 50948 2.61ms 14.15MB 4.19s
Express JavaScript 38451 3.24ms 13.77MB 5.21s

ドキュメント・情報量

Name Examples Reference Real time support
Iris 92 https://github.com/kataras/iris/tree/master/_examples rocket chat
Beego 49 https://beego.me/docs
Echo 20 https://echo.labstack.com/cookbook/hello-world
Gin 15 https://github.com/gin-gonic/gin/tree/master/examples gitter
Revel 6 http://revel.github.io/examples/index.html gitter
Buffalo 6 https://gobuffalo.io/docs/installation slack

Gin や Echo などの他の競合Goフレームワークと比べて,Iris のドキュメントの量はやはり多いですね
これは私も勉強しながら非常に感じました

機能性

Name Iris Beego Revel Echo Gin Buffalo
Router: Named Path Parameters & Wildcard*
Router: Regex*
Router: Grouping*
Router: All the above Mixed Without Conflict*
Router: Custom HTTP Errors*
100% compatible with net/http*
Middleware ecosystem*
Sinatra-like API*
Server: Automatic HTTPS*
Server: Gracefully Shutdown*
Server: Multi Listeners*
Full HTTP/2* standard standard
Subdomains* secondary secondary secondary secondary secondary
Sessions* secondary
Websockets*
View (aka Templates) Embedded Into App*
View Engine: STD*
View Engine: Pug*
View Engine: Django*
View Engine: Handlebars*
View Engine: Amber*
Renderer: Markdown, JSON, JSONP, XML...*
MVC* generator
Caching*
File Server*
File Server: Embedded Into App*
Response can be Modified Many times through lifecycle before sent*
Gzip* middleware middleware middleware
Testing Framework*
Typescript Transpiler*
Online Editor*
Logging System*
Maintenance & Auto-Updates*
Performance ★★★★★ ★★★ ★★ ★★★★★ ★★★★★ ★★★

これまでの表とも合わせて見るに,
他のGoフレームワークに実現できて Iris に実現できないことは全くと言っていいほど無さそうです

※ その他の比較詳細

準備

早速使っていきましよう

1. まず,Goがインストールされているか以下コマンドにて確認

$ go version
go version go1.17.6

2. Iris をgetしていきます!

// 新規フォルダ作成(既存フォルダにダウンロードする際は不要)
$ mkdir myapp 

// Iris をダウンロードしたいフォルダに移動
$ cd myapp

// go mod 初期化
$ go mod init myapp

// Irisのパッケージ取得
$ go get github.com/kataras/iris/v12@master
// go のバージョンが 1.17 以降
$ go install github.com/kataras/iris/v12@latest

※ 参考はこちら

Iris の基本編

Iris を使って簡単なAPIを作成してみます(※ MVCにしない場合)

main.go
package main

import "github.com/kataras/iris/v12"

func main() {
    app := iris.New()

    app.Handle("GET", "/", func(ctx iris.Context) {
        ctx.JSON(iris.Map{"message": "ping"})
    })
	
    app.Listen(":8080")
}

go run main.go でサーバーを立ち上げて localhost:8080 にアクセスしてみると,
Jsonメッセージの {"message":"ping"} が返ります

もしもフレームワーク等を使わずに素のGoで同じサーバーを作る場合,以下のようになります 👇

main.go
package main

import (
	"encoding/json"
	"net/http"
)

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, q *http.Request) {
        message := map[string]string{
            "message": "ping",
        }
        jsonMessage, err := json.Marshal(message)
        if err != nil {
            panic(err.Error())
        }
        w.Write(jsonMessage)
    })
    http.ListenAndServe("127.0.0.1:8080", mux)
}

コードの量がほぼ倍になりました...

この理由を見てみましょう

iris/context/context.go
// Context is the midle-man server's "object" dealing with incoming requests.
//
// A New context is being acquired from a sync.Pool on each connection.
// The Context is the most important thing on the iris's http flow.
//
// Developers send responses to the client's request through a Context.
// Developers get request information from the client's request a Context.
type Context struct {
    // the http.ResponseWriter wrapped by custom writer.
    writer ResponseWriter
    // the original http.Request
    request *http.Request
    // the current route registered to this request path.
    currentRoute RouteReadOnly

    // the local key-value storage
    params RequestParams  // url named parameters.
    values memstore.Store // generic storage, middleware communication.
    query  url.Values     // GET url query temp cache, useful on many URLParamXXX calls.
    // the underline application app.
    app Application
    // the route's handlers
    handlers Handlers
    // the current position of the handler's chain
    currentHandlerIndex int
    // proceeded reports whether `Proceed` method
    // called before a `Next`. It is a flash field and it is set
    // to true on `Next` call when its called on the last handler in the chain.
    // Reports whether a `Next` is called,
    // even if the handler index remains the same (last handler).
    //
    // Also it's responsible to keep the old value of the last known handler index
    // before StopExecution. See ResumeExecution.
    proceeded int
    
    // if true, caller is responsible to release the context (put the context to the pool).
    manualRelease bool
}

つまり,素のGoで HandleFunc を書く際にパラメータとして存在する http.ResponseWriterhttp.Request が,Iris の Context構造体(struct) の構成要素として格納されていて,それが関数の内部で使用されているという仕組みです

ちなみに,app.Listen(":8080") も実際には http.ListenAndServe(address, engine) などが中身で呼ばれています

元々のGoのコードを活かして便利な処理を実現していることが分かります!

ミドルウェアの使用

リクエストに対する処理は基本下記のようになります

Request -> Route Parser -> Middleware -> Route Handler -> Middleware -> Response

つまり,実際に処理を行う関数に到達する前に必ずミドルウェアを通る必要があります

上記でのmain.goに合わせて使うとこんな感じです 👇
ポイントは,『ミドルウェアは実装の前で使用する』 ということです

main.go
package main

import (
    "net/http"

    "github.com/kataras/iris/v12"
)

func main() {
    app := iris.New()

    // こんな感じで
    // 実装の前の部分で使用!!!!!
    app.WrapRouter(routerWrapper)
    app.UseRouter(routerMiddleware)
    app.UseGlobal(globalMiddleware)
    app.Use(useMiddleware)
    app.UseError(errorMiddleware)
    app.Done(done)
    app.DoneGlobal(doneGlobal)

    app.Handle("GET", "/", func(ctx iris.Context) {
        ctx.JSON(iris.Map{"message": "ping"})
    })
    
    // 以下 様々な処理等...

    app.Listen(":8080")
}

Iris ではミドルウェアが豊富にあり,それらを覚えきるのは大変なので...

まずは「ふむふむこんな感じで使えばいいんやね〜〜」と覚えておいてください.
(業務で使うとなるとミドルウェア一つ一つ覚えていく必要は,やはりあります)

HTMLや静的ファイルを表示する

HTMLファイルを表示する

超簡単です

  • app.RegisterView()

という Iris の組み込み関数を使い,表示用ディレクトリとその中のどの種類のファイル(.html など)を表示するかを指定して,あとはURLによって表示したいHTMLファイルを指定していくだけです

実際に見てみましょう

ディレクトリ構造は以下の想定です ※

myapp
|- public
|- |- books
|- |- |- list.html
|- |- |- purchase.html
|- go.mod
|- main.go

コードはこんな感じです 👇

main.go
package main

import "github.com/kataras/iris/v12"

func main()  {
    app := iris.New()
    
    // "public" ディレクトリ配下の ".htmlファイル" を返却するように設定
    // 上書きされバグが潜む可能性があるため基本的には一度だけ設定するようにし,
    // 指定したディレクトリ(今回は "public")配下にディレクトリを増やしていくようにする
    app.RegisterView(iris.HTML("/public", ".html"))
    
    // GET: "/"
    app.Get("/", func(ctx iris.Context) {
        // 返却するviewファイルの指定("/public" フォルダからのパス)
        ctx.View("index.html")
    })

    // "/books/"から始まるURLを受け取った際の処理をグループ化
    books := app.Party("/books")
    {
        // GET: "/books/"
        books.Get("/", func(ctx iris.Context) {
            // "/public" フォルダからのパスで指定
            ctx.View("/books/list.html")
        })
        // GET: "/books/buy"
        books.Get("/buy", func(ctx iris.Context) {
            // "/public" フォルダからのパスで指定
            ctx.View("/books/purchase.html")
        })
    }
    
    app.Listen(":8080")
}

サーバーを立ち上げて localhost:8080 にアクセスすると,public/index.html の内容が確認できるはずです
localhost:8080/books/buy にアクセスしても public/books/index.html の内容が確認できるはずです.

静的ファイルを表示する

これも簡単です

  • app.HandleDir("受け取るURL", iris.Dir("表示したいファイルや画像があるディレクトリまでのパス"))

と書くだけです

main.go
package main

import "github.com/kataras/iris/v12"

func main()  {
    app := iris.New()
    
    // 静的ファイルの表示
    // "public" フォルダ以下のファイルが表示される
    app.HandleDir("/", iris.Dir("/public"))
    
    // 以下 様々な処理等...
    
    app.Listen(":8080")
}

サーバーを立ち上げて localhost:8080 をアクセスすると public ディレクトリ以下の任意のファイルや画像が表示されるはずです.

ファイルのアップロード

Iris としては

  • ctx.SaveFormFile(ファイル, 保存先までのパス)

といった機能などが備わっています

コードで見た方が早いと思います 👇

const maxSize = 8 * iris.MB

func main() {
    app := iris.Default()

    app.Post("/upload", func(ctx iris.Context) {
        // ファイルの最大容量はあらかじめ決めておいてもいいかもしれません
        ctx.SetMaxRequestBodySize(maxSize)
        // 👆 はミドルウェアでも指定できます
        // app.Use(iris.LimitRequestBodySize(maxSize))
        // または
        // iris.WithPostMaxMemory(maxSize) なども

        file, fileHeader, err:= ctx.FormFile("file")
        if err != nil {
            ctx.StopWithError(iris.StatusBadRequest, err)
            return
        }
		    
        // 保存先を作っておく
        // ここでは "destination" に "./public/ファイル名" というパスが文字列で格納される
        destination := filepath.Join("./public", fileHeader.Filename)
		
        // 保存処理
        ctx.SaveFormFile(fileHeader, destination)
    })

    app.Listen(":8080")
}

リクエストからクエリ / パラメータを取得(Get, Post, Put, Delete...)

こちらも Iris に備え付きの機能を使用すれば簡単です

クエリ取得

  • ctx.ReadQuery()
  • ctx.URLParamInt()

パラメータ取得

  • ctx.Params().Get()

など...

クエリ取得

main.go
package main

import "github.com/kataras/iris/v12"

type MyType struct {
    // "url" タグでクエリ名を指定しています
    Name string `url:"name,required"`
    Age  int    `url:"age"`
}

func main()  {
    app := iris.New()
    
    // GET: "localhost:8080/users?name=tom&?age=19"
    // パターン 1.
    app.Handle("GET", "/users", func(ctx iris.Context) {
        var t MyType
        // クエリがある場合,iris.Context の機能を使って以下のように取得できます
        // ここではクエリから受け取ったデータを構造体(struct)に格納しています
        err := ctx.ReadQuery(&t)
        
        //「t」を使った様々な処理等...
    })
    
    // もちろんメソッドへの切り出しもできます
    app.Handle("GET", "/users", getUser)
    func getUser(ctx iris.Context) {
        // 以下略
    }
    
    
    // パターン 2.
    app.Handle("GET", "/users", func(ctx iris.Context) {
        // iris.Context の機能を使って以下のようにも取得できます
        // "name" と言うクエリを取得し,変数に格納しています
        name, err := c.Ctx.URLParamInt("name")  // name => "Tom"
        
        // 「name」を使った様々な処理等...
    })
    
    app.Listen(":8080")
}

パラメータ取得

main.go
package main

import "github.com/kataras/iris/v12"

func main()  {
    app := iris.New()
    
    // GET: "localhost:8080/users/123(IDなど)"
    // パターン 1.
    app.Handle("GET", "/users/{id:int}", func(ctx iris.Context) {
        // iris.Context の機能を使ってこのように取得できます
        id, _ := ctx.Params().Get("id")
        
        // 「id」を使った様々な処理等...
    })
    
    // もちろんメソッドへの切り出しもできます
    app.Handle("GET", "/users/{id:int}", getUser)
    func getUser(ctx iris.Context) {
        // 以下略
    }
    
    // パターン 2.
    app.Handlefunc("PUT", "/users/{id:int}", updateUser) 
    func updateUser(id int) response {
        // こう書くだけで,もうパラメータの「id」が引数として取得できています
        // 「id」を使った様々な処理等...
    })
}

Iris でMVCモデルの簡単なAPIを作ってみよう

最初に説明

今回は以下の機能を実装しようと思います

実装機能

ユーザーの



さて,基本編で作成したAPIは,main.go の中にあくまで受け取りたいパスやその後の処理などを”ベタ書き”したものに過ぎず,Iris のパフォーマンスを活かしきれているとは言えません

今回は Iris の強みを活かして,MVCモデルを形成しながらAPIを作っていきたいと思います

ディレクトリ構成

example-mvc-api
|- controller
|- |- users
|- |- |- users_controller.go
|- setups
|- |- configure_users_controllers.go  // DI(依存性注入)を行う部分
|- model
|- |- user.go
|- service
|- |- user.go
|- |- init.go
|- go.mod
|- main.go

必要なパッケージをgetします(Iris は既にgetできている想定)

また,今回DBとのやりとりを行うためのORMに関しては gorp パッケージを使用してます − 公式リポジトリ

$ go get github.com/go-sql-driver/mysql
$ go get github.com/go-gorp/gorp

// go 1.17 以降
$ go install github.com/go-sql-driver/mysql@latest
$ go install github.com/go-gorp/gorp@latest

main.go

main.go
package main

import (
    "github.com/kataras/iris/v12"
    "github.com/kataras/iris/v12/middleware/accesslog"
    "github.com/kataras/iris/v12/middleware/recover"
    "github.com/kataras/iris/v12/mvc"
	
    "go-iris-sample/setups"
)

func main() {
    app := iris.New()

    // ミドルウェアの使用
    app.Use(iris.Compression)
    app.Configure(iris.WithoutBodyConsumptionOnUnmarshal)
	
    // ログ記録(これも備え付きミドルウェア)
    ac := accesslog.File("./access.log")
    defer ac.Close()
    app.UseRouter(ac.Handler)
    app.UseRouter(recover.New())

    // "/users/"から始まるURLを受け取った際の処理をグループ化
    users := app.Party("/users")
    mvc.Configure(users, setups.ConfigureUsersControllers)

    // ポートの指定
    app.Listen(":8080")
}

setups/configure_users_controllers.go(※ DI - 依存性注入 を行う)

Iris でMVCモデルを形成するためには,main.go で作ったパスのグループ(を表す変数など)に対して,使用する controller などを DI(依存性注入)を行う必要がありますが,今回はそれをこの setups ディレクトリで行なっています(ディレクトリの名前は何でも大丈夫です)

具体的なところはコードを見てください

setups/configure_users_controllers.go
import (
    "github.com/kataras/iris/v12/middleware/accesslog"
    "github.com/kataras/iris/v12/mvc"
    "go-iris-sample/controller/users"
)

// ConfigureUsersControllers
// main.go で定義したURLのグループを表す変数(ここではusers)が引数に入り,
// それに対してDI(依存性注入)を行っている
func ConfigureUsersControllers(app *mvc.Application) {
    // ログを取得してくれる機能のDIもここで行う
    app.Register(accesslog.GetFields)
    
    // URLが "/users" から始まるリクエストを受け取った際に,
    // 以下の Controllerを使用させるという指示
    app.Handle(new(users.UsersController))
}

controller/users/users_controller.go(※ ここがポイント!!!!)

さて,main.gousers から始まるパスのグループを作りましたが,ここで今回のAPIのエンドポイント(受け取るURL)を再び確認してみましょう

  • ~/users
  • ~/users/list
  • ~/users/details/{id:uint}
  • ~/users/details/{id:uint}

どれも /users/ からURLが始まりますが,/users/list/users/details... などのようにURLは分岐しています

これをどう実装しましょう.

基礎編で書いたコードのように,また他のGoフレームワークではそうですが....
app.Get("GET", "/users/list", ...) といった具合に,メソッドや一つ一つのパスを”ベタ書き”したような関数をたくさん作っていくのでは大変です
そもそも,「関数」のことを controller とするのは美しいMVC形成と言えません(機能の分割などが困難で小回りが利かない・一つの関数に書く量が多くなっていくのは保守性が低い) ❌

また,例えばRailsなど他のフレームワークのようにルーティングについてまとめたファイルも Iris では書きません ❌

もっといい方法があります!Iris には『MVCモデルを形成するためだけの機能』がたくさんあるので,そちら使いましょう

正解は...
『コントローラー(controller)のメソッドの名前を変える』だけ
です!

これが超便利なんです

具体的に説明します!

まず,main.go などでURLのグルーピングをします(今回は "~/users" ).
その上で,例えば GET で /users/list というURLを受け取る際の処理を行うには,関連する controllerに GetList() というメソッドを,
POST で /users/details というURLを受け取る際の処理を行うには,controllerに PostDetails() というメソッドを作りその中に処理を書いていく.....(※ パラメータやクエリについては,そこまでは書かなくて大丈夫です)
といった具合に,受け取る想定のURLの,app.Party() などで最初に指定された部分(ここでは users)以降の部分をキャメルケースでcontrollerのメソッドの名前にすれば, それを Iris が自動で判別してそのメソッドを自動で行なってくれるのです!

つまりこの場合,

  • GET で /users/list というURLでリクエストがきた場合,Iris が自動でそれを判別してcontrollerの GetList() という名前のメソッドの処理が行われる
  • POST で /users/details というURLでリクエストがきた場合,Iris が自動でそれを判別してcontrollerの PostDetails() という名前のメソッドの処理が行われる

となります
(※ users := app.Party("/users") などとしてURLのグルーピングされている・DIされている前提)

ですので,例えば今回 GET で users/users/users/ というURLも受け取る場合,controllerに GetUsersUsers() という名前のメソッドがあればもちろんそのメソッドの処理が行われます

実際にコードを見てみましょう 👇
ここでの機能としては,上記の通りリクエスト毎に controller のメソッドを判別 -> 処理を service にハンドル -> レスポンスを返す となっています

controller/users/users_controller.go
package users

import (
    "github.com/kataras/iris/v12"
    "github.com/kataras/iris/v12/mvc"
    "go-iris-sample/model"
    "go-iris-sample/service"
)

type UsersController struct {
	UserService service.UserService
	Ctx         iris.Context
}

// メソッド名でパスの違い・リクエストメソッド・パラメータを受け付けます(超便利)
// [例]
// GetList()                GET: "http://localhost:8080/users/list"
// Post()                   POST: "http://localhost:8080/users"
// PutDetails()             PUT: "http://localhost:8080/users/details"
// PutDetailsBy(id uint)    PUT: "http://localhost:8080/users/details/{id:int}"
// DeleteDetails()          DELETE: "http://localhost:8080/users/details"
// DeleteDetailsBy(id uint) DELETE: "http://localhost:8080/users/details/{id:int}"
// [その他の例]
// POST: http://localhost:8080/users/details/example -> PostDetailsExample()
// PUT: http://localhost:8080/users -> Put()

func (c *UsersController) GetList() mvc.Response {
    // 一覧取得
    users, err := c.UserService.GetUserList()
    if err != nil {
        return mvc.Response{
            Code: iris.StatusInternalServerError,  // エラーハンドリング
        }
    }
    
    // Iris に備え付きのレスポンス用構造体(struct)
    return mvc.Response{
        Code:   iris.StatusOK,
        Object: users,
    }
}

func (c *UsersController) Post() mvc.Response {
    // リクエストボディのjsonデータを構造体(struct)に格納する
    var user model.User
    err := c.Ctx.ReadJSON(&user)
    
    // エラーハンドリング(Iris 備え付きのもので作れます)
    if err != nil {
        c.Ctx.StopWithError(iris.StatusBadRequest, err)
        return mvc.Response{
            Code: iris.StatusBadRequest,
        }
    }
    
    // 新規作成
    err = c.UserService.CreateUser(&user)
    if err != nil {
        return mvc.Response{
            Code: iris.StatusInternalServerError,  // エラーハンドリング
        }
    }
    
    // Iris 備え付きのレスポンス用構造体(struct)
    return mvc.Response{ Code: iris.StatusCreated }
}

func (c *UsersController) PutDetailsBy(id int) mvc.Response {
    // リクエストボディのjsonデータを構造体(struct)に格納する
    var user model.User
    err := c.Ctx.ReadJSON(&user)
    
    // エラーハンドリング(Iris 備え付きのもので作れます)
    if err != nil {
        c.Ctx.StopWithError(iris.StatusBadRequest, err)
        return mvc.Response{
            Code: iris.StatusBadRequest,
        }
    }
    
    user.Id = id
    
    // 更新
    err = userService.UpdateUser(&user)
    if err != nil {
        return mvc.Response{
            Code: iris.StatusInternalServerError,  // エラーハンドリング
        }
    }
    
    // Iris 備え付きのレスポンス用構造体(struct)
    return mvc.Response{ Code: iris.StatusOK }
}

func (c *UsersController) DeleteDetailsBy(id int) mvc.Response {
    // 削除
    err := c.UserService.DeleteUser(id)
    if err != nil {
        return mvc.Response{
            Code: iris.StatusInternalServerError,  // エラーハンドリング
        }
    }
    
    // Iris 備え付きのレスポンス用構造体(struct)
    return mvc.Response{ Code: iris.StatusOK }
}

model/user.go

User構造体(struct)を定義しています
dbタグをつけておくことで,ORMを使ってDBとやりとりできます

model/user.go
package model

type User struct {
    Id    string  `json:"id"   db:"id"`
    Name  string  `json:"name" db:"name"`
    Age   uint32  `json:"age"  db:"age"`
}

service/init.go

データベースへの接続とテーブルの初期化を実装します

service/init.go
package service

import (
    "database/sql"
    "fmt"
    "github.com/go-gorp/gorp"
    "go-iris-sample/model"
    "log"
    "os"
    
    _ "github.com/go-sql-driver/mysql"
)

// gorp初期化処理
func InitDb() *gorp.DbMap {
    dbUserName := "DB_USERNAME"
    dbPassWord := "DB_PASSWORD"
    dbHost := "DB_HOST"
    dbPort := "DB_PORT"
    dbDbName := "DB_DBNAME"
    db, err := sql.Open("mysql", fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?parseTime=true", dbUserName, dbPassWord, dbHost, dbPort, dbDbName))
    if err != nil {
        fmt.Printf("error! can't open sql driver %v", err)
    }
    dbmap := &gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{"InnoDB", "UTF8"}}
    
   // テーブル作成
    dbmap.AddTableWithName(model.User{}, "user").SetKeys(true, "Id")
    err = dbmap.CreateTablesIfNotExists()
    if err != nil {
        fmt.Printf("error! can't craete table: %v", err)
    }
    
    // ログの取得
    dbmap.TraceOn("[gorp]", log.New(os.Stdout, "go-iris-sample:", log.Lmicroseconds))
    
    return dbmap
}

service/user.go

実装の部分です
ここではコントローラからハンドリングされた以下の処理を行います
ユーザーの

  • 一覧取得
  • 新規作成
  • 更新
  • 削除

を行っています

service/user.go
package service

import (
    "go-iris-sample/_example-mvc-api/model"
    
    _ "github.com/go-sql-driver/mysql"
)

type UserService struct {}

func (UserService) GetUserList() ([]model.User, error) {
    // initialize the DbMap
    dbMap := InitDb()
    defer dbMap.Db.Close()
    
    var users []model.User
    
    // ユーザーを全取得
    _, err := dbMap.Select(&users, `SELECT * FROM users`)
    if err != nil {
        return []model.User{}, err
    }
    
    return users, nil
}

func (UserService) CreateUser(user *model.User) error {
    // initialize the DbMap
    dbMap := InitDb()
    defer dbMap.Db.Close()
    
    // トラン ザクションを走らせながらinsert
    tx, _ := dbMap.Begin()
    
    err := tx.Insert(user)
    if err != nil {
        tx.Rollback()
        return err
    }
    
    tx.Commit()
    
    return nil
}

func (UserService) UpdateUser(user *model.User) error {
    // initialize the DbMap
    dbMap := InitDb()
    defer dbMap.Db.Close()
    
    // トランザクションを走らせながらupdate
    tx, _ := dbMap.Begin()
    
    _, err := tx.Update(user)
    if err != nil {
        tx.Rollback()
        return err
    }
    
    tx.Commit()
    
    return nil
}

func (UserService) DeleteUser(id int) error {
    // initialize the DbMap
    dbMap := InitDb()
    defer dbMap.Db.Close()
    
    // id から削除するユーザーを取得
    var user model.User
    err := dbMap.SelectOne(&user, `SELECT * FROM users WHERE id = :id`,
        map[string]interface{}{
            "id": id,
        })
    if err != nil {
        fmt.Printf("error! can't find user by id: %v.\n", id)
        return err
    }
    
    // トランザクションを走らせながらdelete
    tx, _ := dbMap.Begin()
    
    _, err := tx.Delete(&user)
    if err != nil {
        tx.Rollback()
        return err
    }
    
    tx.Commit()
    
    return nil
}

こんな感じで,Iris を使ってAPIを作れます

go run main.go でサーバーを立ち上げて,それぞれのエンドポイントにリクエスト内容を正しい内容にしてアクセスし,正常に動作することを確認してください

また,以下は例ですが,起動後URLへアクセスをするとこんな感じのログも確認できるはずかと思います

access.log
2022-04-17 19:08:16|1.19426ms|200|GET|/|::1|0 B|10 B||
2022-04-17 19:08:16|42.803µs|404|GET|/favicon.ico|::1|0 B|0 B||
2022-04-17 19:08:21|27.538µs|404|GET|/favicon.ico|::1|0 B|0 B||
2022-04-17 19:09:36|112.584µs|404|GET|/favicon.ico|::1|0 B|0 B||
2022-04-17 19:09:40|32.466µs|404|GET|/favicon.ico|::1|0 B|0 B||
2022-04-17 19:09:44|180.006µs|200|GET|/|::1|0 B|10 B||
2022-04-17 19:09:44|25.901µs|404|GET|/favicon.ico|::1|0 B|0 B||
2022-04-17 19:09:58|168.375µs|200|GET|/users|::1|0 B|10 B||
2022-04-17 19:09:58|29.095µs|404|GET|/favicon.ico|::1|0 B|0 B||
2022-04-17 19:10:47|322.583µs|200|GET|/users|127.0.0.1|64 B|10 B|{"firstname":"Tanaka","lastname":"ryo","age":15}|



長くなってしまいましたが,以上になります.

終わりに

これまでも述べてきたように,Iris はGo言語のつよつよフレームワークです
ぜひ一度使ってみてください!

参考記事

大感謝です 🙇🏼‍♂️

https://qiita.com/Syoitu/items/8e7e3215fb7ac9dabc3a#構造体を使用したバリデーション

GitHubで編集を提案

Discussion

kyoh86kyoh86

差し出がましい指摘ではございますが、過去には作者のライセンス、コミットログ、Contributors、Issue等の扱い方が悪質であったがゆえにawesome-goなどにも掲載を拒否されたことがあるようなフレームワークですので、採用には慎重さが求められます。
現在の作者の動向は私も把握しておりませんが、念の為にご注意を。

mkosakanamkosakana

コメントありがたいです.こちら5,6年ほど前のIrisの割と有名な話ですよね.....現在においては大きな問題はないと思っていますがそこらへんは職場でも非常に注意して進めていきたいです.読んでいただきありがとうございます!🤲🏻

ログインするとコメントできます