Scala用のDIライブラリAirframeを試してみた

ScalaではJavaと違ってDIコンテナの必要性を感じることがあまりないのですが、フレームワークを作っているとユーザコードにフレームワークが提供するコンポーネントを供給したり、フレームワーク自体を拡張するための拡張ポイントを提供するためにDIコンテナ的なものを使いたいというケースがあったりします。

PlayではGoogle Guiceが導入されていますが、もう少し簡潔でScalaらしいDIコンテナはないものかと思っていたところ@taroleoさんがAirframeというライブラリを開発されていたのを思い出したので試してみました。

github.com

基本的にはフィールドインジェクションぽい感じで、DIするフィールドを以下のように宣言しておきます。

import wvlet.airframe._

class AccountController {
  val accountService = bind[AccountService]
}

そしてDesignというバインディングを定義するオブジェクトを用意します。GuiceModule相当のもののようです。

val design = newDesign
  .bind[AccountController].toInstance(new AccountControllerImpl())

以下のようにしてDI済みのインスタンスを取得することができます。

val session = design.newSession
val controller = session.build[AccountController]

上記の例ではバインドするインスタンスtoInstanceで指定しましたが、他にもtoSingletonでシングルトンにしたり、to[T]でコンクリートクラスの型を指定してバインドしたりといろいろできます。

同じ型のコンポーネントを複数使い分ける場合、Guiceなどでは名前を指定してDIしますが、Airframeではタグを使って区別することができます。READMEの例に少し手を加えたものですが、以下のような感じです。

import wvlet.obj.tag.@@

case class Fruit(name: String)

trait Apple
trait Banana

trait TaggedBinding {
  val apple  = bind[Fruit @@ Apple]
  val banana = bind[Fruit @@ Banana]
}

val design = newDesign
  .bind[Fruit @@ Apple].toInstance(Fruit("Apple"))
  .bind[Fruit @@ Banana].toInstance(Fruit("Banana"))

Scala用のDIライブラリにはAirframeの他にもSubCutScaladiMacWireなどがあります。各ライブラリを詳細に比較したわけではないのですが、Airframeはこれらの中でも直感的ながら柔軟性も高く扱いやすいように感じます。なかなか良いフィーリングなのでもう少しいろいろ触ってみたいと思います。

Scala用のREST APIフレームワークResty 0.0.5をリリースしました

Scala用の超シンプルなREST APIフレームワークとしてRestyというものを作っています。

takezoe.hatenablog.com

github.com

前回ブログで書いてからちょこちょこいじりつつバージョンアップを重ねているので、前回のブログで紹介できなかった機能や、これまでに新たに追加した機能について簡単にまとめてみたいと思います。

全自動Zipkin

Restyはもともと全自動でSwagger、Hystrixと連携する機能を備えていましたが、これに加えてZipkinも全自動で利用できるようになりました。

以下のようにコントローラーにHttpClientSupportというトレイトをミックスインし、このトレイトが提供するメソッドを使用して別サービスの呼び出しを行うことでZipkinでトレースを行うことができます。

class HelloController extends HttpClientSupport {
  @Action(method = "GET", path = "/hello/{id}")
  def hello(id: Int): Message = {
    // Call other API using methods provided by HttpClientSupport
    val user = httpGet[User](s"http://localhost:8080/user/${id}")
    Message(s"Hello ${user.name}!")
  }
}

なお、全自動と言いつつweb.xmlで少しだけ設定が必要です。Zipkinインテグレーションを使用するかどうか、サンプリングレート、ZipkinサーバのURLを指定します。

<context-param>
  <param-name>resty.zipkin</param-name>
  <param-value>enable</param-value>
</context-param>
<context-param>
  <param-name>resty.zipkin.sample.rate</param-name>
  <param-value>1.0</param-value>
</context-param>
<context-param>
  <param-name>resty.zipkin.server.url</param-name>
  <param-value>http://127.0.0.1:9411/api/v1/spans</param-value>
</context-param>

web.xmlでの設定

全自動SwaggerやHystrixが使えるのは便利なのですが、セキュリティ上運用時はエンドポイントを無効にしたいというケースもあるはずなのでweb.xmlで設定できるようにしました。

どちらもデフォルトでは無効になっており、web.xmlに以下の設定を追加することで有効になります。

<context-param>
  <param-name>resty.swagger</param-name>
  <param-value>enable</param-value>
</context-param>

<context-param>
  <param-name>resty.hystrix</param-name>
  <param-value>enable</param-value>
</context-param>

今後はもう少し設定可能なパラメータを増やしていこうと思っています。

ケースクラスのバリデーション

JSONマッピングするケースクラスのコンストラクタでassertすることで入力値のバリデーションができるようになりました。

case class Message(message: String){
  assert(message.length < 10, "message must be less than 10 charactors.")
}

以下のようなレスポンスが400 BadRequestステータスで返却されます。

{
  "errors": [
    "message must be less than 10 charactors."
  ]
}

もう少し本格的なバリデーションフレームワークを入れようかなとも思ったのですが、Restyはシンプル第一なので標準機能としてはこのくらいにしておこうと思います。

ServletAPIへのアクセス

Restyのコントローラーは基本的にServlet API非依存ですが、Restyが提供する機能だけでは不可能な細かい処理を行う必要がある場合や、HttpSessionを使用したい場合など、Servlet APIを使う必要がある場合はコントローラーにServletAPIトレイトをミックスインするとrequestresponseHttpServletRequestHttpServletResponseにアクセスできるようになります。

class HelloController extends ServletAPI {
  @Action(method = "GET", path = "/hello")
  def hello(): Message = {
    val name = request.getParameter("name")
    Message(s"Hello ${name}!")
  }
}

まとめ

Restyは関数型プログラミングや非同期処理の知識がなくてもScalaで簡単にJSONベースのREST APIを実装することができます。サンプルプロジェクトから始めるのが手っ取り早いと思いますので興味のある方は是非試してみていただければと思います。

github.com

GitBucket 4.8をリリースしました

Scalaで実装されたオープンソースのGitサーバ、GitBucket 4.8をリリースしました。

https://github.com/takezoe/gitbucket/releases/tag/4.8

リポジトリ名での検索

GitBucketで管理しているリポジトリが増えてくると、目的のリポジトリを探すのが難しいという要望があったため、新たにリポジトリを検索するための機能を追加しました。

まず、グローバルヘッダの検索ボックスからリポジトリの検索が可能になりました。

f:id:takezoe:20161223192630p:plain

また、ダッシュボードのサイドバーに表示されるリポジトリの一覧を絞り込み検索できるようになりました。

f:id:takezoe:20161223192639p:plain

IssuesとWikiの検索

IssuesとWikiにテキスト検索のための検索ボックスを設置しました。

f:id:takezoe:20161223192749p:plain

f:id:takezoe:20161223192801p:plain

プルリクエストのコメントの改善

これまでプルリクエストのソースコードにつけたコメントは新しいコミットがプッシュされると表示されなくなってしまっていましたが、今回のリリースから新しいコミットがコメント行を変更していない場合は引き続き表示されるようになりました。

f:id:takezoe:20161223192948p:plain

この改善によってプルリクエストへのコメント機能がコードレビュー用途に使いやすくなるのではないかと思います。

このリリースは他にも以下の修正を含んでいます。

この他にも様々な改善やバグフィックスを行っています。詳細についてはIssueの一覧をご覧ください。

ポートとソケットがわかればインターネットがわかる――TCP/IP・ネットワーク技術を学びたいあなたのために (Software Design plus)

技術評論社さんから送っていただきました。ありがとうございます。

f:id:takezoe:20161210165934j:plain

内容的にそれほど踏み込んでいないということもあるのですが、わかりやすい説明とイラストのおかげで非常に読みやすいです。とはいえ、中盤では軽くですがCによるソケットプログラミングやネットワークコマンドの使い方の解説など手を動かして体験してみるパートもあります。ただ、「ポートとソケットがわかれば〜」というタイトルは若干釣りっぽい気がしないでもないですw

最近はWebアプリを作っているだけだとなかなかネットワーク周りに触れることもないのではと思うのですが、HTTP以下の知識がないエンジニアがネットワークについて最初に読むにはちょうどよさそうです。また、少し難しい部分もあるかと思いますが、非エンジニアの方が読むのにもよいかもしれません。

ちなみにこの書籍のイラストは「小悪魔女子大生のサーバエンジニア日記」の方が描かれているそうです。

小悪魔女子大生のサーバエンジニア日記 ――インターネットやサーバのしくみが楽しくわかる

小悪魔女子大生のサーバエンジニア日記 ――インターネットやサーバのしくみが楽しくわかる

JJUG CCC 2016 FallでGitBucketの話をしてきました

以前ScalaMatsuriでGitBucketについてお話しさせていただいたことはあるのですが、用途を考えると受託開発の現場で使われているケースが多いはずで、JavaコミュニティのほうがGitBucketのユーザ層に近い方が多いのでは…と思ったこともありJJUG CCCのCfPに応募してみたところ無事採択いただきました。

発表に使用したスライドは以下になります(公開用に少し編集してあります)。

www.slideshare.net

今回はGitBucketの紹介に加えて、OSSには継続性が大切だけど、個人レベルの活動だと限界があるのでコミュニティやエコシステムを作ることが必要で、そのためにはどうすべきなのか?ということをお話ししたかったのですが、いろいろと思うところがありすぎてまとまりのない話になってしまったかもしれません。

自分自身、今の会社の業務ではGitHubを使えているのでなかなかGitBucketの開発を継続するモチベーションが難しい部分もあるのですが、そこは今日お話しさせていただいたように個人で頑張るだけではなく、持続可能なコミュニティとエコシステムを作る方向に持っていくことができればと思います。

セッション後にGitBucketステッカー配布させていただいたのですが、だいぶ消費しました。会場がガラガラだったらどうしようと思っていたのですが、多くの方に参加していただきありがとうございました。

セッションの最後にもお話しさせていただいた通り、私自身もGitHubが使えるのであればそちらを使ったほうが間違いなくよいと思っています。しかし諸事情によりGitHubが使えないという場合はまずGitBucketでコストをかけずにGitを導入し、GitHubへの移行の足がかりにしていただくのもよいかもしれません。そのような形であっても開発現場の皆様のお役に立てれば幸いです。

ちなみにTISさんではかなり大規模にGitBucketをご利用いただいているようです。

もちろんGitBucketの開発にご協力いただけるのが一番嬉しいのですが、独自プラグインの開発、バグレポートや機能追加の要望などのフィードバック、ユーザサポートのヘルプなどなんでも構いませんので可能な範囲でサポートいただけるとありがたいです。よろしくお願いしますw

RestyというScala用のREST APIフレームワークを作ってみました

GitHubリポジトリはこちら。

github.com

なぜ作ったのか?

Scala業界のフレームワークは関数型的なアプローチのものが主流になっています。これらのフレームワークはノンブロッキングI/Oや並列処理をうまく扱うことができますが、本質的な複雑さをもたらします。自分の経験では、特に企業システムなどの場合は従来の同期サーブレットでも十分というケースも多いのではないかと感じています。

また、既存のScala用のフレームワークはタイプセーフなDSLでルーティングや入出力パラメータなどを定義するものが多いのですが、この手のものはシンプルな静的解析でメタ情報を抽出することが難しいためSwaggerなどの外部ツールとの相性が悪いという欠点もあります。

Restyはこのようなケースにおいてもプログラミング言語としてのScalaのアドバンテージを活かすことのできるシンプルなフレームワークがあるといいのではということで作ってみたものです。

使ってみよう

以下のコマンドを実行することでサンプルプロジェクトを実行することができます。

$ git clone https://github.com/takezoe/resty-sample.git
$ cd resty-sample/
$ sbt ~jetty:start

Swagger UIもデフォルトで組み込まれているのでhttp://localhost:8080/swagger-ui/にアクセスすることでサンプルプロジェクトで実装されているAPIの動作を確認することができます。

それでは実際のソースコードも簡単に見ていきましょう。以下は最もシンプルなコントローラの実装例です。

class HelloController {
  @Action(method = "GET", path = "/hello/{name}")
  def hello(name: String): Message = {
    Message(s"Hello ${name}!")
  }
}

case class Message(message: String)

APIのエンドポイントになるメソッドには@Actionというアノテーションを付与する必要があります。メソッドの引数はパスやクエリ文字列、オブジェクトの場合はリクエストボディとして送信されたJSONからRestyによって自動的に渡されます。また、戻り値も型に応じて自動的にテキストやJSONとして返却されます。

コントローラをRestyに登録するために以下のようなリスナも作成しておく必要があります。

@WebListener
class InitializeListener extends ServletContextListener {
  override def contextDestroyed(e: ServletContextEvent): Unit = {
  }
  override def contextInitialized(e: ServletContextEvent): Unit = {
    Resty.register(new HelloController())
  }
}

基本的にはこれだけでWeb APIを実装することができます。

SwaggerとHystrix

Restyでは何もしなくてもSwagger、Hystrixとの連携が可能です。追加で設定を行なったり、メタデータを定義したりする必要はありません。

まずSwaggerですが、SwaggerのJSONはコントローラから自動的に生成され、http://localhost:8080/swagger.jsonで公開されます。また、前述のようにSwagger UIはhttp://localhost:8080/swagger-ui/で利用可能です。

f:id:takezoe:20161128005405p:plain

Hystrixのメトリクスはアクションごとに送信されています。ストリームのエンドポイントはhttp://localhost:8080/hystrix.streamで利用可能なのでHystrixのダッシュボードにこのURLを追加すればすぐにモニタリングを開始することができます。

f:id:takezoe:20161128005416p:plain

まとめ

RestyはScalaJSONベースのWeb APIを作成するための最短の方法を提供します。サーブレット上で動作し、関数型アプローチを採っていません。昨今のScala業界のトレンドに反してはいますが、とても簡単でシンプルで安定しており安全です。また、全自動のSwaggerとHystrix連携が標準で組み込まれています。

是非GitHubリポジトリにアクセスして試してみていただければと思います。

【改訂新版】Gitポケットリファレンス

技術評論社さんのポケットリファレンスシリーズから出ているGitポケットリファレンンスが改訂されるとのことで見本誌を送っていただきました。ありがとうございます。

【改訂新版】Gitポケットリファレンス

【改訂新版】Gitポケットリファレンス

なんと社内に設置可能なGitサーバとしてGitLabと並んでGitBucketを紹介していただいています。ありがたや…。ちなみに「GitBucketはGitLabのような細かいアクセス制御ができない」とありますが、先日リリースした4.7ではGitHubやGitLabと同等以上のアクセス制御が可能になっています。

肝心の内容ですが、単なるコマンドリファレンスに留まらず、Gitの内部構造、実践的なノウハウや最新の情報もカバーするなど、コマンドを覚えて使えるようになるためのリファレンスではなく、きちんとGitを理解して欲しいという意図を感じます。これからGitを始めてみようという初心者だけでなく、すでにGitを使っているけどいまいち使いこなせていない、きちんと理解しているか不安があるという方にもオススメできるリファレンスです。

自分は普段Gitの操作はGUIクライアントを使うことが多いのですが、せっかくなのでこれを機会にしばらくコマンドライン修行をしてみようかと思いますw