LoginSignup
8
3

More than 5 years have passed since last update.

florestを使ってWebAPIを作ってみた

Last updated at Posted at 2016-12-09

この記事はGo (その3) Advent Calendar 2016の9日目の記事です。

マイクロサービスの調査のいっかんとして、go製のWebAPI用フレームワークflorestというフレームワークを試してみたので、ここにまとめる。

前提条件

ここでは以下のバージョンを使用した。

  • go 1.7.3
  • florest (githubの2016/11/7のmasterのhead)
  • gingko

gingkoのインストールは以下

$ go get github.com/onsi/ginkgo/ginkgo
$ go get github.com/onsi/gomega

プロジェクトの作成

まず、florest-coreのリポジトリをローカルにcloneします。

$ git clone https://github.com/jabong/florest-core

さらにcloneしたflorest-coreのフォルダに移動して、アプリの雛形をつくります。
make newappを実行する際に環境変数NEWAPPに展開先のフォルダを指定します。

$ cd florest-core
$ make newapp NEWAPP="~/newapp"
building new app
copying dependent libs
$ cd ~/newapp

これでホームフォルダの下にnewappが作られました。

ファイルの構成は以下のような感じです。

.
├── Makefile
├── _libs
├── config
│   ├── logger
│   │   └── logger.json
│   └── newapp
│       └── conf.json
├── main.go
├── scripts
│   ├── README.md
│   ├── logger.sh
│   └── swagger.sh
└── src
    ├── README.md
    ├── common
    │   ├── appconfig
    │   │   └── application_config.go
    │   └── appconstant
    │       └── error_codes.go
    ├── hello
    │   ├── api_definition.go
    │   ├── data_structures.go
    │   ├── hello_world.go
    │   ├── hello_world_health_checker.go
    │   └── swagger.go
    └── test
        ├── coverage.sh
        ├── servicetest
        │   ├── config_initialize.go
        │   ├── logger_initialize.go
        │   ├── service_initialize.go
        │   ├── service_test.go
        │   ├── service_test_helper.go
        │   ├── test_web_server.go
        │   └── testdata
        │       ├── testconf.json
        │       └── testloggerAsync.json
        └── utils
            ├── request_helper.go
            └── response_status_helper.go

さらに実行エラーなどを吐き出すログ用のフォルダを作成します。
デフォルトでは、/var/log/アプリ名に作られるので、sudoを使ってフォルダを作成したあとに、florestを実行するユーザーに所有者を変更しておきます。

$ sudo mkdir /var/log/newapp
$ sudo chown myuser /var/log/newapp

最低限の準備ができたので、試しにデプロイします。

$ cd ~/newapp
$ make deploy

binフォルダ配下に実行ファイルが作成されます。binフォルダに移動して実行します。

$ cd bin
$ ./newapp
APPLICATION BEGIN
2016/11/15 00:14:41 Web server Initialization begin
2016/11/15 00:14:41
Initializing Config
config &{AppName: AppVersion: ServerPort: LogConfFile: MonitorConfig:{APPName: APIKey: APPKey: AgentServer: Platform: Verbose:false Enabled:false MetricsServer:} Performance:{UseCorePercentage:0 GCPercentage:0} DynamicConfig:{Active:false RefreshInterval:0 ConfigKey: CacheKey:} HTTPConfig:{MaxConn:0 MaxIdleConns:0 ResponseHeaderTimeout:0 DisableKeepAlives:false} Profiler:{Enable:false SamplingRate:0} ResponseHeaders:{CacheControl:{ResponseType: NoCache:false NoStore:false MaxAgeInSeconds:0}} ApplicationConfig:0xc4200cbe20 AppRateLimiterConfig:<nil>}
2016/11/15 00:14:41 Application Config Created
2016/11/15 00:14:41
Global Config=&{AppName:newapp AppVersion:1.0.0 ServerPort:8080 LogConfFile:conf/logger.json MonitorConfig:{APPName:newapp APIKey: APPKey: AgentServer:datadog:8125 Platform:DatadogAgent Verbose:false Enabled:false MetricsServer:datadog:8065} Performance:{UseCorePercentage:100 GCPercentage:1000} DynamicConfig:{Active:false RefreshInterval:0 ConfigKey: CacheKey:} HTTPConfig:{MaxConn:0 MaxIdleConns:0 ResponseHeaderTimeout:0 DisableKeepAlives:false} Profiler:{Enable:false SamplingRate:0} ResponseHeaders:{CacheControl:{ResponseType: NoCache:false NoStore:false MaxAgeInSeconds:0}} ApplicationConfig:0xc4200cbe20 AppRateLimiterConfig:<nil>}
2016/11/15 00:14:41
Application Config=&{Hello:{ResponseHeaders:{CacheControl:{ResponseType: NoCache:false NoStore:false MaxAgeInSeconds:0}}}}
No of Cpu Core to be Used = 4

8080ポートにアクセスしてみるとサーバが起動していることがわかります。

エンドポイントの追加

bookという新しいエンドポイントを追加します。

必要なファイルを用意

最初に、srcフォルダの下のhelloフォルダをコピーして、ファイルをリネームして、
内部の変数名などの値を全て置換します。

$ cp -R src/hello src/book
$ find src/book -name "hello_world*" -exec rename s/hello_world/book/ {} +
$ find src/book -name "*.go" -exec sed -i 's/helloWorld/book/g' {} +
$ find src/book -name "*.go" -exec sed -i 's/hello/book/g' {} +
$ find src/book -name "*.go" -exec sed -i 's/HelloWorld/Book/g' {} +
$ find src/book -name "*.go" -exec sed -i 's/Hello/Book/g' {} +

main.goへのAPIの追加

次にmain.goに、さきほど複製してリネームしたbook APIへのimportの追加と、
florestのserviceにBookAPIを追加します。

import (
        "common/appconfig"
        "common/appconstant"
        "fmt"
        "hello"
        "book" // 追加

        "github.com/jabong/florest-core/src/core/service"
)

//main is the entry point of the florest web service
func main() {
        fmt.Println("APPLICATION BEGIN")
        webserver := new(service.Webserver)
        registerConfig()
        registerErrors()
        registerAllApis()
        webserver.Start()
}

func registerAllApis() {
        service.RegisterAPI(new(hello.HelloAPI))
        service.RegisterAPI(new(book.BookAPI)) // 追加
}

エンドポイントのパスの設定

src/book/api_definition.go

で、ホスト名以下のパス名を定義します。
さらに、Book IDを指定して、指定のIDの情報が取得できるように、パス内にリクエストパラメータbookIdを追加します。

func (a *BookAPI) GetVersion() versionmanager.Version {
        return versionmanager.Version{
                Resource: "BOOK", //エンドポイントの終端のパス名
                Version:  "V1", // アプリ名の次にくるバージョン名
                Action:   "GET", // リクエストメソッド
                BucketID: constants.OrchestratorBucketDefaultValue, //todo - should it be a constant
                Path:     "{bookId}", // bookIdを取得できるようにする
        }
}

上記の設定により

http://ホスト名:8080/newapp/v1/book/{bookId}

というパスが定義されます。

newappの部分は、bin/conf/conf.jsonの、ルートのAppNameキーで定義されている値になります。

リクエストを受けた時の処理の追加

src/book/book.goの、func (a Book) Execute(io workflow.WorkFlowData) (workflow.WorkFlowData, error)にBook APIの処理ロジックを記載します。

引数のioにはリクエストの情報とレスポンスの情報が含まれます。

リクエストパラメータの取得

ioIOData.Getメソッドを使って値を取得します。

引数に入る値は、request_response_constants.goに定義されている定数を使います。PathParamsを取得したいので、引数にconstants.PathParams
を入力します。

        pathp, _ := io.IOData.Get(constants.PathParams)
        fmt.Println(pathp)

deployして実行します。サーバの起動を確認したら、コンソールからcurlでbookIdを指定してリクエストを投げてみます。

$ curl -XGET "http://localhost:8080/newapp/v1/book/123" | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   158  100   158    0     0  22829      0 --:--:-- --:--:-- --:--:-- 26333
{
  "status": {
    "httpStatusCode": 200,
    "success": true,
    "errors": null
  },
  "data": null,
  "_metaData": {
    "urlParams": {},
    "apiMetaData": {}
  }
}

サーバを起動しているコンソール側のスタンダードアウトには

123

と、リクエストパラメータに指定した値が取得できていることがわかります。

レスポンスの記述

処理した結果などをレスポンスの内容に記述するには、ioIOData.Setメソッドを使います。

こちらも先ほどと同じように、第一引数には、request_response_constants.goの定数から選択します。

レスポンスのJSONのdataキーの値に結果をレンダリングするには、constants.Resultを使います。

        io.IOData.Set(constants.Result, "test")

同様に、DeployしたあとにWebAPIのサーバを起動して、curlを使ってレスポンス値を確認します。

$ curl -XGET "http://localhost:8080/newapp/v1/book/123" | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   125  100   125    0     0   8965      0 --:--:-- --:--:-- --:--:--  9615
{
  "status": {
    "httpStatusCode": 200,
    "success": true,
    "errors": null
  },
  "data": "test",
  "_metaData": {
    "urlParams": {},
    "apiMetaData": {}
  }
}

第2引数に指定した文字列testがdataキーに入っていることがわかります。

Swaggerの出力

依存のインストール

Swaggerを扱うために、まずgoのswaggerライブラリをインストールします。

$ go get github.com/yvasiyarov/swagger

Swaggerの定義を記述

src/book/swagger.go

にAPIの仕様を記述します。

package の記述の上に、APIのバージョンとbasePathを記述します。

// @APIVersion 1.0.0
// @basePath /newapp/v1
package book

次にtestを取得するメソッドを記述します。

// @Title test
// @Description get test book
// @Accept  json
// @Param   BookId     path    string     true        "book_id"
// @Router /book/{BookId} [get]
func test() {}

メソッド名は、nicknameとして出力されます。
そのほかの定義については、

Whats swagger

を確認してください。

Swaggerの生成

Swaggerを生成するために、以下のコマンドを実行します。

$ make deploy SWAGGER=book

サーバを起動します。そうすると、以下のURLにアクセスすることで、swagger形式のJSONにアクセスできます。

ここまでできれば、あとはSwagger UIを使ってドキュメントを生成したりなど、やり放題です。

その他に提供される機能

ここまで、最低限の機能について、紹介していました。

florestで用意されている他の機能としては、

  • MySQL Components
  • mongodb Components
  • A/B Test
  • 非同期のLogging (Logstash形式のJSONに対応)
  • Datadogを使ったレスポンスタイムなどのモニタリング
  • 各メソッドなどコードの実行時間の計測
  • バックグラウンドで非同期実行されるWorker pool
  • エラーやタイムアウトなどHttp Utilitiy
  • Fault toleranceな機能
  • 単純なバリデーション
  • Rate limit

などが提供されます。

まとめ

駆け足でまとめたため、説明不足の部分が多々ありますが、go初心者の自分には、デザインパターンなど学ぶ部分が多々あり勉強になりました。

8
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3