goagen:goa のツール


コード生成ツール

goagen は、goa デザインパッケージからさまざまなアーティファクト(中間生成物)を生成するツールです。

次のようにインストールします:

go install github.com/goadesign/goa/goagen

それぞれのタイプのアーティファクトは、独自のフラグセットを公開する goagen コマンドに関連付けられています。 内部的には、これらのコマンドは、アーティファクトを生成するロジックを含む"ジェネレータ"にマップされます。 これは次のように動作します:

  1. goagen はコマンドラインを解析して、必要な出力のタイプを判断し、適切なジェネレータを呼び出す。
  2. ジェネレータは、最終出力を生成するツールのコードを一時ディレクトリに書き込む。
  3. デザインパッケージとツールコードで構成されるツールは、一時ディレクトリでコンパイルされる。
  4. このツールが実行され、最終的な出力を書き込むためにデザインのデータ構造をたどる。

各ジェネレータは goagen ツールのコマンドとして公開され、goagen --help で利用可能なすべてのコマンドを一覧できます。 それらは以下になります:

  • app: コントローラー、コンテキスト、メディアタイプ、ユーザータイプなどのサービス定型コードを生成します。
  • main: デフォルトの main と同様に、リソースコントローラごとにスケルトンファイルを生成します。
  • client: API クライアントの Go パッケージとツールを生成します。
  • js: JavaScript APIクライアントを生成します。
  • swagger: API の Swagger 仕様書を生成します。
  • schema: API の Hyper-schema JSON を生成します。
  • gen: サードパーティ製のジェネレータを起動します。
  • controller: 各リソースごとにコントローラーのひな形を生成します。
  • bootstrap: appmainclientswagger の各ジェネレータを呼び出します。

goagen での作業: Scaffold(足場) vs. 生成されるコード

デザインが発展するにつれ、goagen を何度も実行する必要があるので Scaffold(足場)生成された コードとの区別を理解することが重要になってきます。

main コマンドによって生成された Scaffold コードは、すぐに開始する方法として一度生成されます。 このコードは、編集、テストされ、手動で書かれた他のファイル同様一般的な処理が行われることを意味します。デフォルトでは goagen main は Scaffold ファイルがすでに存在する場合には上書きしませんが、--regen 引数をつければ Scaffold ファイルを更新することが出来ます。 client コマンドによって生成されるクライアントツールの main パッケージも Scaffold です。

他のすべてのコマンドの出力(および client コマンドの main パッケージを除く出力)から構成される生成されたアーティファクトは、編集できませし、すべきではありません。アーティファクトは goagen が実行されるたびに、一から作り直されます。 それらがインポートされ、公開された関数と他の Go のパッケージと同様のデータ構造を消費して生成された Go パッケージを、ユーザーコードは利用します。

共通のフラグ

次のフラグは、すべてのgoagenコマンドに適用できます:

  • --design|-d=DESIGN は、Go パッケージパスをサービスのデザインパッケージとして定義します。
  • --out|-o=OUT は、ファイルを生成する場所を指定します。デフォルトは現在のディレクトリです。
  • --debug は、goagen のデバッグを可能にします。 これにより、goagen は一時ファイルの内容を出力し、それらを残します。
  • --help は、コンテキスト・ヘルプを表示します。

コンテキストとコントローラ:goagen app

app がおそらく最も重要なコマンドです。 これは、goa サービスを支えるためのすべてのコードを生成します。 このコマンドは、テストヘルパを含む test サブパッケージも生成します。 テストヘルパは、コントローラのアクションとビューごとに1つずつ生成されます。 これらのテスト・ヘルパーを使用すると、管理された値で呼び出して返されたメディアタイプを検証するよう実装することで、アクションを簡単にテストできます。

このコマンドはいくつかの追加フラグをサポートしています:

  • --pkg=app は、生成されたGoパッケージの名前を指定します。デフォルトはappです。これは、生成された Go ファイルを格納するために作成されるサブディレクトリの名前でもあります。
  • --notest は、テストヘルパーの生成を止めます。

このコマンドは毎回既存のディレクトリを削除して同じ名前で再作成します。 それは、これらのファイルは決して編集されるべきではないという考えに基づいています。

Scaffolding(足場):goagen main

main コマンドは、デザイン・パッケージに定義されている各リソースコントローラのデフォルトの(空の)実装と同様に、デフォルトのmain.go を生成することによって、新しい goa サービスをブートストラップするのに役立ちます。 デフォルトでは、このコマンドは出力ディレクトリに生成されるファイルが存在しない場合にのみファイルを生成します。 このコマンドは、2つの追加フラグを受け取ります:

  • --force は、同じ名前のファイルがすでに存在していても、空の Sacaffold ファイルで上書きします。
  • --regen は、実装されたコントローラをそのまま残して、既存のファイルを再生成します。

goagen main でサービスを立ち上げて、新しいリソースやアクションがデザインに追加されたら、goagen main --regen を走らせて、既存のコントローラを保持しながら新しい空のコントローラ実装を追加する、というのが典型的なワークフローになるでしょう。

注: --regen を機能させるために、コントローラの実装は 必ず コメントの間に置かなければなりません。

// ControllerName_Action: start_implement

... your logic ...

// ControllerName_Action: end_implement

再生成コードは、これらのコメントを頼りにして、保持すべき非 Scaffold なコードを見つけます。

クライアント・パッケージとツール:goagen client

client コマンドは、API クライアントパッケージと CLI ツールの両方を生成します。 クライアント・パッケージは、各リソースアクションに対して1つのメソッドを公開した Client オブジェクトを実装します。 また、対応する HTTP リクエストオブジェクトを、送信せずに、作成するメソッドも公開しています。 生成された CLI ツールのコードは、パッケージを利用してサービスの API リクエストを作成します。

Client オブジェクトは、アクションに対してセキュリティが有効になっている場合(アクション DSL がセキュリティ機能を使用する場合)、要求を送信する前に呼び出されるリクエストの認証方法を使用するように設定されています。 認証方法は、たとえば、認証ヘッダーを含めるようにリクエストを変更します。 goaには、 Basic 認証JWT 認証API キーOAuth2 のサブセットを実装する認証方法が付属しています。

JavaScript:goagen js

js コマンドは、クライアント側とサーバー側の両方のアプリケーションに適した JavaScript API クライアントを生成します。 生成されたコードは、匿名の AMD モジュールを定義し、実際のHTTPリクエストを作成するために axios の promise ベースの JavaScript ライブラリに依存しています。

生成されたモジュールは axios クライアントをラップし、API 固有の関数を追加します。たとえば:

// List all bottles in account optionally filtering by year
// path is the request path, the format is "/cellar/accounts/:accountID/bottles"
// years is used to build the request query string.
// config is an optional object to be merged into the config built by the function prior to making the request.
// The content of the config object is described here: https://github.com/mzabriskie/axios#request-api
// This function returns a promise which raises an error if the HTTP response is a 4xx or 5xx.
client.listBottle = function (path, years, config) {
        cfg = {
                timeout: timeout,
                url: urlPrefix + path,
                method: 'get',
                params: {
                        years: years
                },
                responseType: 'json'
        };
        if (config) {
                cfg = utils.merge(cfg, config);
        }
        return client(cfg);
}

生成されたクライアントモジュールは、requirejs を使用してロードできます:

requirejs.config({
        paths: {
                axios: '/js/axios.min',
                client: '/js/client'
        }
});
requirejs(['client'], function (client) {
        client().listBottle ("/cellar/accounts/440/bottles", 317)
                .then(function (resp) {
                        // All good, use resp
                })
                .catch(function (resp) {
                        // Woops, request failed or returned 4xx or 5xx.
                });
});

上記のコードでは、生成されたファイル client.jsaxios.min.js の両方が /js から提供されているものと仮定しています。 promise に返される resp の値は次のフィールドを持つオブジェクトです:

{
        // `data` is the response that was provided by the server
        data: {},

        // `status` is the HTTP status code from the server response
        status: 200,

        // `statusText` is the HTTP status message from the server response
        statusText: 'OK',

        // `headers` is the headers that the server responded with
        headers: {},

        // `config` is the config that was provided to `axios` for the request
        config: {}
}

また、ジェネレータは、JavaScript をすばやくテストするために サンプル HTML とgoa サービスにマウントできるコントローラを生成します。 サービスのメインで js Go パッケージをインポートし、コントローラをマウントするだけです。 サンプル HTML は /js の下で提供されるので、このパスをブラウザにロードすると、生成された JavaScript がトリガーされます。

Swagger:goagen swagger

swagger コマンドは、API の Swagger 仕様を生成します。 コマンドは追加のフラグを受け付けません。 Swagger JSON とYAML の両方を生成します。 生成されたファイルは、デザインの Files で定義されたファイルサーバーを使用して API 自体から提供できます。

JSON Schema:goagen schema

schema コマンドは、API を表現する Heroku ライク な JSON ハイパースキーマを生成します。 goa サービスにマウントして /schema.json の下でそれを提供できるように JSON とコントローラの両方を生成します。

プラグイン:goagen gen

gen コマンドを使用すると、goagen プラグインを呼び出すことができます。 このコマンドは、1つのフラグを受け取ります:

  • --pkg-path=PKG-PATH は、プラグインパッケージへの Go パッケージのインポートパスを指定します。

goa プラグインの詳細については、ジェネレータプラグインのセクションを参照してください。

Scaffolding(足場):goagen controller

controller コマンドは、デザインパッケージに定義された各リソースコントローラーに対して、デフォルトの(空の)実装を生成します。 デフォルトでは、このコマンドはファイルが出力ディレクトリに存在しない場合にのみ生成します。 このコマンドは次のフラグをとります:

  • --force は、同じ名前のファイルがすでに存在していても、空の Sacaffold ファイルで上書きします。
  • --regen は、実装されたコントローラをそのまま残して、既存のファイルを再生成します。詳細は goagen main の項を参照してください。
  • --res 強制的にリソースの名前を指定します。
  • --pkg 生成されるコントローラパッケージの名前を指定します。以下のように挙動します。
    • --out が指定されていない (default)
      • --pkg が指定されていない (default)
        • パッケージは main として生成されます。 (この挙動は mainbootstrap コマンドに準じています。)
      • --pkg が指定されている (bar)
        • パッケージは bar として生成されます。
    • --out が指定されている (foo)
      • --pkg が指定されていない (default)
        • パッケージは foo として生成されます。
      • --pkg が指定されている (bar)
        • パッケージは bar として生成されます。
  • --app-pkg コントローラをサポートするコード(コンテキスト、メディアタイプ、ユーザタイプなど)を含む Go パッケージの名前を設定します。デフォルトは app です。