astamuse Lab

astamuse Labとは、アスタミューゼのエンジニアとデザイナーのブログです。アスタミューゼの事業・サービスを支えている知識と舞台裏の今を発信しています。

Akka HTTPプロジェクトでSwagger Specificationを出力する。

お久しぶりです。開発部のyanagitaです。

以前、Play FrameworkプロジェクトでSwaggerを導入した記事を本ブログで投稿させていただきました。

執筆は、開発部のNishikawa氏 lab.astamuse.co.jp

今回は、Akka HTTPを使用したプロジェクトでSwagger Specification(以下、Swagger Spec)を出力したいと思います。

使用するライブラリ

今回はswagger-akka-http/swagger-akka-httpを使用します。

github.com

サンプルプロジェクトがあるのでそちらで解説を入れていきます。

github.com

build.sbtへライブラリ追加

build.sbtに以下を追加します。

libraryDependencies ++= Seq(
  "javax.ws.rs" % "javax.ws.rs-api" % "2.0.1", 
  "com.github.swagger-akka-http" %% "swagger-akka-http" % "2.0.4", 
  "com.github.swagger-akka-http" %% "swagger-scala-module" % "2.0.5",
  "com.fasterxml.jackson.module" %% "jackson-module-scala" % jacksonVersion,
  "io.swagger.core.v3" % "swagger-core" % swaggerVersion,
  "io.swagger.core.v3" % "swagger-annotations" % swaggerVersion,
  "io.swagger.core.v3" % "swagger-models" % swaggerVersion,
  "io.swagger.core.v3" % "swagger-jaxrs2" % swaggerVersion,
  "com.typesafe.akka" %% "akka-http" % akkaHttpVersion,
  ...
)

Swagger Spec生成に必要なライブラリは以下です。
javax.ws.rs-api → サンプルではリクエストメソッドの指定で使用します。
com.github.swagger-akka-http %% swagger-xxx → Swagger Specを生成するライブラリセットです。
io.swagger.core.v3 % swagger-xxx → Swaggerアノテーションを使用するためのライブラリセットです。

ルート定義とSwagger Spec情報定義

まずはAPIの定義から入ります。
参考コードはHelloService.scalaからの抜粋ですが、一部修正を入れています。

 // 44行目から  
  // アノテーション定義がSwagger Spec生成の情報定義になります。
  @Path("/hello/{name}")
  @GET
  @Operation(summary = "Return Hello greeting", description = "Return Hello greeting for named user",
    parameters = Array(new Parameter(name = "name", in = ParameterIn.PATH, description = "user name")),
    responses = Array(
      new ApiResponse(responseCode = "200", description = "Hello response",
        content = Array(new Content(schema = new Schema(implementation = classOf[Greeting])))),
      new ApiResponse(responseCode = "500", description = "Internal server error"))
  )
  // 以下はルート定義
  def getHelloSegment =
    path("hello" / Segment) { name =>
      get {
        complete { (hello ? Hello(name)).mapTo[Greeting] }
      }
    }

結果が先に来てしまうのですが、上記定義で生成されるSwagger Specの定義が以下になります。

  /hello/{name}:
    get:
      summary: Return Hello greeting
      description: Return Hello greeting for named user
      operationId: getHelloSegment
      parameters:
      - name: name
        in: path
        description: user name
        required: true
        schema:
          type: string
      responses:
        "200":
          description: Hello response
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/Greeting'
        "500":
          description: Internal server error

Swagger SpecのAPI定義に当たる箇所はすべてアノテーションで定義します。
一見、アノテーション定義は複雑に見えますが、Swagger Specを記述されたことがある方はどのアノテーション定義がSwagger Spec上の記述となるか簡単に紐づくと思います。Swagger Specが初見の方は一度Swagger Specの理解から入られるとアノテーションの理解が早まると思います。

Swagger Spec生成サービスの追加

swagger-akka-httpでは、リクエストに対してSwagger Specを返却する仕組みとなているため、Swagger Sepcを生成するサービス作成とルート追加が必要となります。

SwaggerDocService.scala

object SwaggerDocService extends SwaggerHttpService {
  override val apiClasses = Set(classOf[AddService], classOf[AddOptionService], classOf[HelloService], EchoEnumService.getClass)
  override val host = "localhost:12345"
  override val info = Info(version = "1.0")
  override val externalDocs = Some(new ExternalDocumentation().description("Core Docs").url("http://acme.com/docs"))
  //override val securitySchemeDefinitions = Map("basicAuth" -> new BasicAuthDefinition())
  override val unwantedDefinitions = Seq("Function1", "Function1RequestContextFutureRouteResult")
}

SwaggerDocServiceは、SwaggerHttpServiceを継承しSwagger Specに出力する情報を定義します。
最低限必要な定義はapiClasses、hostになります。apiClassesは、Swagger Specに掲載するAPIクラス(Swaggerアノテーションを定義したクラス)を羅列します。(apiClassesに含まないクラスはSwagger Specに出力されません。)hostはSwagger UIからAPI実行するためのエンドポイントのホスト情報として必要となります。
あとはAkkaのルーティングにSwaggerDocService(SwaggerDocService.route)を追加して終わりです。
Swagger Specの出力形式はjson形式、yaml形式の両方があります。アプリを起動し、以下のでURLにアクセスすれば出力可能です。

json形式はこちら → http://localhost:12345/api-docs/swagger.json
yaml形式はこちら → http://localhost:12345/api-docs/swagger.yaml

※ アクセスのパスの「/api-docs/」はSwaggerDocService内の定義で変更可能です。

まとめ

以上、サンプルをベースにAkka HTTPプロジェクトからSwagger Specを出力するコードを紹介しました。
アノテーションの定義が多く面倒に感じる部分がありますが、導入コストは非常に低く制限も少ないので導入は容易だと感じました。

PR

アスタミューゼではたくさんのエンジニア&デザイナをまだまだまだ募集しています。 気になる方は下からご応募下さい!新しい出会いをメンバー一同お待ちしてます!

社内無線LAN環境改善のためにやったこと (2019/Summer)

こんにちは。並河(@namikawa)です。

すっかり秋の足音が聞こえてまいりました。秋といえば食欲の秋。ラーメンの秋です。

会社では最近新しい方がたくさん入社してきてくれていて嬉しい限りで、エンジニアやデザイナーも増えてきています。

面接をしていても「社内の雰囲気ってどんな感じなんですか〜?」なんて聞かれることも多いので、ちょっと最近入社されたエンジニアの方のデスクを紹介してみようと思います。

弊社では、入社される方全員に、業務で使うマシンの希望を伺っているのですが、エンジニア・デザイナーは MacBook Pro を選択される方がほとんどです。エンジニアの場合はそれに 32 インチの 4K モニターを一緒に貸与することが多く、デザイナーは EIZO のモニター(27インチ、2枚等)とか希望を伺いながら決める感じです。

参考までに、池田さんが書いてくれた、4Kモニターを使っているレポートのエントリを貼っておきます。

本日のエンジニアのデスク

f:id:astamuse:20191001191856j:plain

・・・で、こちらの方は、ErgoDox!!というエルゴノミクス的なキーボードをご使用で、なんというか姿勢が良い!さすがですねw

分離型のキーボードを使っていると、こんな感じでノートが中央に置けるんですね。スペースが広く使えて良さそうです。

少しでも社内の雰囲気が伝わりましたでしょうか・・・?各エンジニアのデスクを見てると、結構個性やこだわりが出ていて面白いなぁと思います。

こんな感じで、またシリーズ的に紹介してみたいと思います。嫌がられなければ・・・w

閑話休題、そろそろ無線LANの話を

最近、全社的にたくさん入社される方がいて、一定規模になってきたベンチャー企業が、いよいよ情シスまわりどうするの?的な問題が強くなってきたと感じている日々なのですが、そのうちの1つの業務が社内ネットワークまわり。

下記のエントリーでも torigaki さんが書いてくれていますが、弊社オフィスでは数台の無線LANアクセスポイントがありまして、時折不調になったりしています。

構成としては、オフィスの社内LANについては、YAMAHAの機器で構成していて、無線LANのAPが計7台動いており、内訳は下記のような感じです。

  • WLX302 : 5台
  • WLX402 : 2台

で、無線LANが不調になる、という事象には問題になるパターンが何種類かある気がしていまして、ざっくり書くと、

  • APには繋がっているが、スループットが不安定になり、すごく遅くなる。
  • APには繋がっているが、通信できなくなる。(DHCP経由でクライアントにIPアドレスが付与されないケースもある)
  • APのメモリ使用量が急増し、再起動がかかってしまう。

振る舞いとしてはこういったパターンが見えます。

で、色々と設定を変えながら切り分けを行った結果、部分的に改善が見られまして、まだ改善途中ではあるのですが、その内容を簡単にまとめておこうと思います。

YAMAHA のメーカーサポートについて

最初に書いておくと、後述の試行錯誤の過程で、YAMAHAのサポートには連絡・相談させてもらっていて、Debugログの提出をしながら解析をしていただいたのですが、結論からすると原因は究明されていません。

尚、YAMAHAのサポートの方は、大変丁寧に対応していただきまして、感謝しております。

試してみたこと

WLX402 の 2.4GHz 帯を利用しないようにする

実は前のオフィスでにいた時も、時折、WLX402 が不安定になることがありまして、その時に調べた時は、随分とまわりに無線LANのSSIDがありまして、干渉が見受けられたのと、AP周辺での需要がなかったこともあり、2.4GHz帯の利用をやめて、その結果、安定したことがありました。

それもあり、今回も 2.4GHz 帯の ON/OFF を試してみましたが、結果は変わりませんでした。

送信出力と受信レートの調整

社内MTGで移動していると、遠くのAPにつながったまま通信が継続することがあったため、送信出力を少し弱めたのと、受信レートで低レートで接続されないように調整した。

通常利用において、多少良くなかったかな、という体感はできたのですが、上記で挙げた問題の1つである「APには繋がっているが、スループットが不安定になり、すごく遅くなる。」の解決には至りませんでした。(なぜか6Mbpsでの接続が有効となり切られない)

DFSの影響を受けないチャンネル調整

5.0GHz帯のチャンネルについては、一部が気象レーダー等、各種レーダーシステムで利用されており、これらに影響を与えないよう、無線LANアクセスポイントには、DFS (Dynamic Frequency Selection) という機能が用意されています。

DFSがレーダー波を検出することで、使用チャンネルの変更が行われるということで、であればレーダーシステムの使用しない W52 (36ch/40ch/44ch/48ch) に固定してみるのも試してみましたが、こちらは症状変わらずでした。レーダーシステムの影響ではない、と。

チャンネル設定の確認

Mac OS 標準のワイヤレス診断ツールでスキャンした感じだと、オフィス近辺は飛んでいる SSID も多く、無線LAN的には過酷な環境であることはわかっていまして、前オフィス同様にチャンネル設定は自動で、チャンネル範囲は選べるものを全て選択していました。

ところが、見える化ツール (ステータスをモニタリングするYAMAHA社の無線AP標準ツール) を見ていると、CRCエラーレートがそれなりにある状態。

ワイヤレス診断ツールで眺めている感じ、 5.0GHz帯でさえも、社内のいくつかあるAPのほとんどが、36チャンネルに集中して自動設定されていたりしていました。

チャンネルの自動設定があまり期待できない可能性があるので、これはきちんとチャンネルを干渉しないようセグメンテーションする必要があると思い、2.4GHz帯については、極力干渉しないように場所を考慮しつつ、チャンネルを直接指定して分散させました。5.0GHz帯については、チャンネル設定は自動のままにしつつ、チャネル幅を小さくし、自動チャンネル選択範囲を増やしつつ、干渉しないよう、W52/W53/W56 からバランスよくAPごとに選びようにしました。

その結果、社内のいくつかのポイントで干渉がそれほど起きていないことを確認できました。

あわせて、前述していた受信レートの設定が、少し攻め気味に設定していた部分があったので、Basicレートを 11Mbps(2.4GHz)/12Mbps(5.0GHz) まで落としました。

この辺までで、問題として挙げていた「APには繋がっているが、スループットが不安定になり、すごく遅くなる。」この点はほぼ解消できたと思っています。あとの2つの問題も発生頻度が少なくなりました。 ひょっとしたら干渉が(おそらく)かなりマシになった点が寄与しているのかもしれません。

さいごに

オフィスの無線LAN運用は、複数台の無線APを協調的に動作させたりとか、様々な外部要因が影響することで、なんだかんだ色々トラブルが潜在的に潜んでいることがあり、運用の難しさを感じています。

基本的には問題に対して、ロギング・モニタリングをちゃんとやるのと、解決のための仮説を立てて、1つずつ地道に切り分けていくしかないとは思っています。解決手段の仮説が出尽くしたところでプロに頼もうとは考えていますが、エンジニアとしてついトラブルシューティングしてしまいますね・・・。(致命的な問題であれば、解決最優先となるので、また別の話になりますが。)

一旦こんな感じで、問題が出たタイミングで試行錯誤しながら今後もやっていこうかと思っています。

最後に、、、毎度で恐縮なPRタイムですが、弊社ではエンジニア・デザイナーを絶賛大募集しておりますので、少しでも気になれば、カジュアルにランチでもしながらお話しさせてくださいー!

弊社は、今年オフィスの引っ越しを行ったのですが、オフィスビルの隣には有名なカレー屋(ボンディ)さんがありますので、美味しいカレーでも食べながら是非!

少しでもご興味があればお手数ですが @namikawa まで、お気軽にDM等いただければと思います。

それでは!=͟͟͞͞(๑•̀=͟͟͞͞(๑•̀д•́=͟͟͞͞(๑•̀д•́๑)=͟͟͞͞(๑•̀д•́

@namikawa が書いた過去記事)

Pythonでも型を明記しよう

f:id:astamuse:20190918114322j:plain

こんにちは、Scalaエンジニアのnishikawaです。今回はpythonについて少し話したいと思います。

Pythonって世間では

  • ライブラリが充実している
  • インタプリタ言語でコーディングから実行までが手軽

という印象が強く、初心者やプログラムが本職じゃない人からも好かれる言語だと思います。特に動的型付けによりスクリプトっぽい書き味に加え、オブジェクト指向プログラミングや関数型プログラミングなど、色んなスタイルでコードを組めるのも人気の一つなのではないかと思っております。

そんなPython、書き捨てレベルのコードならいざ知らず、本気で何か組もうと思うとある問題に差し掛かります。

それは

コードを書いているうちにどのようなデータを扱っているかを見失う

ということです。

これを読んでいる人は「そんなことないでしょw」と思うかもしれませんが、少しでもそのアプリから離れると途端に何をやってたか分からなくなることは少しプログラムを組んだことある人なら誰しも経験があると思います。これは動的型付け言語あるあるだと個人的には思っています。

これを解決するには型を宣言するのが一番でPython3からではそれができます。

そもそもPythonにはどんな型があるのか

Pythonにはどんな型があるのか代表的なものと自分が少し気になったものを以下にまとめてみました。

組み込み型 説明
bool 真偽値
int 整数
float 浮動小数点数
complex 複素数
list リスト
tuple タプル
str 文字列
bytes バイトオブジェクト
bytearray 可変バイトオブジェクト
memoryview バッファプロトコルをサポートするオブジェクトの内部データへ直にアクセスすることができるオブジェクト
set 集合型
dict マッピングオブジェクト(俗にいう連想配列やハッシュマップ)

複素数のcomplexやmemoryviewなんかは目からウロコでした。(複素数の型があるとか斬新w)

Pythonで型を宣言しながら変数を定義してみる

では、本題の型の宣言を行いながら変数を定義してみます。

書式は簡単で変数の直後にコロン区切りで組み込み型を定義します。

<変数名>: <組み込み型>

以下はREPLで変数宣言して値を代入し、出力した時の例

>>> zero: int = 0
>>> print(zero)
0
>>>

変数宣言時の例

>>> def test_print(txt: str):
...     print(txt)
...
>>> test_print("test")
test
>>>

実装時に型を宣言した方がいいと思った場所

ここまで型について色々書いてきましたが、最後にpythonでアプリケーションを実装する上で最低限こういう場合に型の宣言を入れておいた方がいいなと思った箇所をまとめておきます(備忘的な意味も込めて)

  • メソッド宣言時の引数と返り値
  • フィールドメンバー
  • 生成したインスタンスを格納するための変数

メソッド宣言時の引数と返り値

メソッドを宣言する時、何をするものなのかをメソッド名に込めて実装することは多いと思いますが、メソッド名やコメントだけではどういうデータをインプットにどういうアウトプットを出すのかを見失うことがあります。そのため引数やメソッドの返り値の型を明確にすることでこの問題を回避できます。

フィールドメンバー

クラス内に定義するフィールドメンバーの型定義も重要なポイントだと思います。フィールドメンバーはクラスがどういう属性のデータを格納しているかを知るにはとてもいい情報だと思うからです。

これらの情報をしっかり書き込むことで、クラスの改修時や設計の見直しにも役立つと思います。

生成したインスタンスを格納するための変数

これはどちらかというとIDE用にあるといいなという感じです。IDEで全く型を定義しないでコーディングを行うと補完機能が使えないことが多々あります。 そのため型の定義はやった方がいいと思います。

もっと言うとIDEの機能を最大限に活かすなら全ての変数の型を定義した方がいいと思います。

まとめ

Pythonはバージョンが3になってからより多くの機能が追加されました。変数に型を明示してもどんな値も受け入れてしまうなど、依然として型の重要性は低いですが、少なくとも人間がコーディングを行う限り今回紹介した型を明示的に表記できる機能は地味ながらとても重要だと思います。

この機能を活用してpythonのコードをより良いものにしてみてはいかがでしょうか。 

Copyright © astamuse company, ltd. all rights reserved.