エントリー
私の名前はマキシムで、Miranサービスコントロールパネルのフロントエンド開発者です。 この一連の記事では、システムがどのように進化しているか、近い将来にどのような新しいことを期待するかについて説明します。 猫へようこそ。
恐竜の時代。
古いパネル(panel_v1)は、フロントエンドのAPI + AngularJSとしてのバックエンド+ TastyPie側のDjangoに基づいています。 選択は、適切なドキュメントと、必要な状態にフレームワークをもたらすために小さなファイルを処理する能力に基づいていました。 DjangoとTastypieの束がクエリに必要なすべてのツールを提供し、AngularJSはデータを表示するのに十分便利でした。
ご存知のように、要件は絶えず拡大しており、パネルの能力を超え始めたとき、アーキテクチャとテクノロジースタックの進化を完全に変更することが決定されました。 コードの「インベントリ」が実行され、その後の作業は凍結され、最小限の変更のみに制限されました。 そして、新しいコントロールパネルを選択する機会を得ました。
選択の小麦粉
主な問題は、アーキテクチャの選択でした。 panel_v1の既存のエクスペリエンスとtastypie機能を考慮して、アイデアを開発し、パネル全体をパーツに分割し、APIを介して接続し、すべてのパーツを個別に管理することにしました。 したがって、マイクロサービスが選択になりました。 結局のところ、タスクを厳密に実行し、作業を変更する小さなモジュールがあると非常に便利ですか? 作業の変更は、残りのマイクロサービスのインターフェースを更新するのに十分です。
決定が下されます、超。 バックエンドには、十分な軽量でありながら強力なフラスコがあり、フロントエンドは新しいAngular2に移行します。 すべてが見栄えが良いように見えますが、どのように通信しますか?
ここでは、十分な柔軟性があり、最小限の変更でバックエンドとフロントエンドに適したAPIが必要です。 さらに、顧客に公開する必要があります。つまり、使用例が記載された詳細なドキュメントは避けられません。 これが私たちが考えた場所です。
ひらめき
この問題の解決策は、Swagger実装のOpenAPI仕様でした。 Swagger機能の短いリストは次のとおりです。
- バックエンドおよびフロントエンド用の単一のAPI記述ファイル。
- yamlおよびjson形式で動作します。
- API仕様ファイルで実行され、それに基づいてルートを構築するPython用の接続パッケージ。
- swagger uiを使用すると、すべてのドキュメントがAPI自体のメソッドの説明に保存されるため、追加のツールは必要ありません。 質問があります:メソッドは何をし、どのデータを入力する必要がありますか? -uiへようこそ! そこでクエリを実行し、結果を見ることができます。 彼らが言うように、100回聞くよりも1回見る方が良いです。
- 着信データの厳密な制御。 たとえば、標準的な状況を考えてみましょう。ユーザーがフォームに入力すると、いくつかのチェックが行われます。
-まず、フロントエンド側での簡単な検証。
-さらに、仕様ファイルに従って、接続はフロントエンドからの着信データをチェックします。
-そして、バックエンドが特定のチェックを追加で実行できるようになります。
ユーザーがエラーにならないようにするのは、入力データに対するこのような多段階制御です。 - フロントエンド専用:swagger-codegenユーティリティ。仕様ファイルを入力として受け取り、Angular2に必要なすべてのサービスを提供します。 さらに、JavascriptとTypescriptの両方の形式(実際、利用可能な言語のリストはより広範囲で、 ここにあります )。
- UIの退屈な壁紙:
これらすべての点を考えると、すべての変更について単一のソースを受け取りました。
機能を追加する必要がありますか? いいね! 最初に説明が仕様ファイルに入力され、次にロジックがバックエンドに説明されます。その後、フロントエンド用の新しいメソッドでAPIが再構築され、これらのメソッドを使用し続けます。
メソッドから返されたデータを変更する必要はありますか? 簡単! 仕様ファイルへの変更を記録し、それに応じてバックエンドを変更し、フロントエンドのAPIを再構築し、影響を受けるメソッドを最小限に修正しました。
その結果、すべてのルーティング、それらへのすべての要求と応答が1つのファイルに記述されます。 そして、バックエンドとフロントエンドは連携して動作します。
すべてがそれほど明確ではない
しかし、物事はスムーズに進みません。 以下は、私たちが遭遇した落とし穴の短いリストです。
仕様ファイル
デフォルトでは、仕様ファイルを分割して、たとえば定義(操作で循環するデータの説明を含むオブジェクト)を別々に保存し、リンクを介してアクセスできます。 しかし、このオプションは接続のために機能しませんでした。 現在のバージョンのパッケージにはこの機能がありません(将来のバージョンで追加されることを心から願っています)。 その間、私は次のように抜け出す必要がありました。すべてのエンティティオブジェクト(定義、パス、応答など)がファイルに選択され、gruntを使用して収集されました。 結果は、簡単に追加および変更できるタスクのセットです。 私の意見では、このオプションは、最終ファイルの〜2500行から目的の行を見つけるよりも優れています。
クライアント側のタスクからの抜粋を次に示します。
- 組み立て前の清掃
clean: client: [ '<%= client_interim_dir %>' '<%= client_root %>/definitions.yml' '<%= client_root %>/paths.yml' ]
インデントを追加する
indent: client_common_definitions: src: ['<%= client_common %>/definitions/*.yml'] dest: '<%= client_interim_dir %>/common/definitions/' options: style: 'space' size: 2 change: 1 client_dedic_definitions: src: ['<%= client_dedic_project %>/definitions/*.yml'] dest: '<%= client_interim_dir %>/dedic/definitions/' options: style: 'space' size: 2 change: 1 client_common_paths: src: ['<%= client_common %>/paths/*.yml'] dest: '<%= client_interim_dir %>/common/paths/' options: style: 'space' size: 2 change: 1 client_dedic_paths: src: ['<%= client_dedic_project %>/paths/*.yml'] dest: '<%= client_interim_dir %>/dedic/paths/' options: style: 'space' size: 2 change: 1 client_misc: src: [ '<%= client_root %>/projects.yml' ] dest: '<%= client_interim_dir %>/' options: style: 'space' size: 2 change: 1
中間ファイルと最終ファイルの「接着」
concat: client_common_definitions: src: ['<%= client_interim_dir %>/common/definitions/*.yml'] dest: '<%= client_interim_dir %>/common_definitions.yml' client_dedic_definitions: src: ['<%= client_interim_dir %>/dedic/definitions/*.yml'] dest: '<%= client_interim_dir %>/dedic_definitions.yml' client_common_paths: src: ['<%= client_interim_dir %>/common/paths/*.yml'] dest: '<%= client_interim_dir %>/common_paths.yml' client_dedic_paths: src: ['<%= client_interim_dir %>/dedic/paths/*.yml'] dest: '<%= client_interim_dir %>/dedic_paths.yml' client_misc_paths: src: [ '<%= client_interim_dir %>/common_paths.yml', '<%= client_interim_dir %>/projects.yml' ] dest: '<%= client_interim_dir %>/common_paths.yml' client_target_paths: src: [ '<%= client_root %>/paths_header.yml' '<%= client_interim_dir %>/common_paths.yml' '<%= client_interim_dir %>/dedic_paths.yml' ] dest: '<%= client_root %>/paths.yml' client_target_definitions: src: [ '<%= client_root %>/definitions_header.yml' '<%= client_interim_dir %>/common_definitions.yml' '<%= client_interim_dir %>/dedic_definitions.yml' ] dest: '<%= client_root %>/definitions.yml' client_swagger: src: [ '<%= client_root %>/info.yml' '<%= client_root %>/tags.yml' '<%= client_root %>/security.yml' '<%= client_root %>/definitions.yml' '<%= client_root %>/parameters.yml' '<%= client_root %>/responses.yml' '<%= client_root %>/paths.yml' ] dest: '<%= client_output_path %>/client_swagger.yaml'
フロントエンドAPIをビルドする
この問題は、私がswagger-codegenをどのように構築できるかを探っていたときに発見されました。 仕様ファイルを提供するかダウンロードするという2つのオプションがあります。 APIサービスが失敗し、これがフロントエンドの動作に影響する可能性があるため、ここでファイルから収集することにしました。 したがって、完成したファイルを選択しました。 リポジトリはgitサブモジュールとして接続され、常に関連性が確保されました。 アルゴリズムは次のとおりです。
- 依存リポジトリの更新:
git submodule update
- Gruntビルドタスクを実行します。
grunt compile
- 結果のファイルでswagger-codegenを実行します。
しかし、swagger-codegenが入力としてJSONを受け入れるという詳細が表示されます。 そして、YAMLがあります。 そして、Gruntで推測したことに気付きました。 プラグインのYAMLをJSONに接続することにより、ズボンは... YAMLはJSONに変わります。 そして、必要な仕様ファイルを取得します。
名前の問題
タイプスクリプトでメソッドと変数に名前を付けるとき、swagger-codegen設定に影響しました。 たとえば、プロパティの名前は「total_count」です。 タイプスクリプトのコンパイル設定がない場合、変数名はtotalCountになりました。 この問題を解決しようとすると、構成ファイルとともに、追加の設定ファイルをJSON形式で転送できることが発見されました。 そしてこの行:
{ "modelPropertyNaming": "original" }
名前は変更されません。
次号では、フロントエンド開発の厄介な道がどのように始まり、どのようにパネルの読み込みを最適化するかを説明します。 ご清聴ありがとうございました!)