Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
0
Help us understand the problem. What is going on with this article?
@nisitanisubaru

サーバサイドKotlinのボイラープレート開発で思ったこと

はじめに

お久しぶりです。k.s.ロジャースの西谷です。

最近はKotlinを使ったREST APIサーバのボイラープレートを設計及び開発を行いました。
リリースが無事完了し、弊社の開発に導入されています。
今回はサーバサイドKotlinを使ってみて思ったことや困ったことを共有できたらと思います。

間違い等があればコメントにて教えて頂けたらと思います。

環境など

今回は以下の構成で実装しました。

  • Kotlin 1.3.61
  • SprintBoot 2.2.4.RELEASE
  • Exposed 0.21.1
  • Mysql 8.0.19

Webフレームワークは選択肢としてSpringBootKtorがありましたが、SpringBootの実績や安定性を考慮してSpringBootを使いました。

作ったもの

DDDベースの設計を行いました。
具体的なディレクトリ構成は次の通りです。

.
├── kotlin
│   └── com
│       └── ksrogers
│           ├── application
│           │   ├── common
│           │   │   ├── annotation
│           │   │   └── error
│           │   │       ├── exception
│           │   │       └── handler
│           │   ├── controller
│           │   ├── middleware
│           │   │   ├── advice
│           │   │   ├── filter
│           │   │   └── interceptor
│           │   ├── request
│           │   └── response
│           ├── config
│           ├── domain
│           │   ├── model
│           │   ├── repository
│           │   └── service
│           ├── infrastructure
│           │   ├── table
│           │   ├── mysql
│           │   └── repository
│           └── util
└── resources
    ├── db
    │   └── migration
    └── i18n
        ├── common
        └── errors

中心となる層の実装内容は以下の通りで、詳細なDDDアーキテクチャの解説は他記事にお任せしたいと思います。

  • application
    • controller: APIのエンドポイントと処理
    • middleware: controller前の共通処理
    • request: リクエスト
    • response: レスポンス
  • infrastructure
    • table: DBのテーブル構造
    • repository: DBのレコード操作
  • domain
    • model: ドメインモデル
    • repository: repositoryのインターフェイス定義
    • service: ドメインサービス

サーバサイドKotlinの良かったところ

コードが直感的

Kotlin独特の書き方は少ない印象でした。
過度な省略記法や暗黙的な呼び出しもなく、必要に応じてコードを追いかけることが容易でした。

このことから複数の言語を触ったことのある方でしたら気軽にKotlinに移ることができると思います。

言語機能が豊富

Collection, Generics, Extensionなどの機能が揃っており、実装したい機能に対して「あの言語のこれがあれば」みたいなことは無かった印象です。
また、ライブラリ関連もJavaのものが使えるため困ることがありませんでした。

解説記事が多い

Kotlinの解説記事は少ないですが、Javaに関する解説記事は大量にあります。
特にSpringBootを使う場合は、困ったときにJavaの記事から調査ができるため手詰まりになることは少ないです。
InteliJを使っている場合はJavaのコードをKotlinに自動変換する機能もあり、そのまま動いたりすることもあります。

サーバサイドKotlinで困ったところ

Kotlinは凄くいい言語と感じましたが、SpringBootの方は落とし穴が結構ありました。
他言語から来た場合は学習コストが高いかもしれません。

RequestのValidationは全てnullableで行う必要がある

SpringBootはRequestの定義とValidationを同時に行います。
具体的には以下のようなクラスを定義します。

data class SampleRequest(
  @field:NotNull
  val title: String?,
  val other: String?

上記のサンプルの場合、titleはNon-NullにもかかわらずNullableで定義する必要があります。
(Nullableで設定しない場合はNullが飛んできたときに例外が発生します)

Non-Nullにも関わらず毎回nullチェックが必要になり非常に煩雑です。
これを回避するために以下のように実装しました。

data class SampleRequest(
  @JsonProperty("title")
  @field:NotNull
  private val _title: String?,
  val other: String?
) {
  val title: String
    get() = _title ?: ""
}

リクエストの前処理が大掛かりになる

通常のWebフレームワークであれば、ControllerのBaseクラスにbeforeExecuteXXXを書いて終わりと思っていました。
しかし、SpringBootは複雑で幾つもの割り込みのタイミングがあります。
こちらの記事に詳細が纏められており、参考にさせて頂きました。

RequestBodyをコントローラに渡す前にメタデータを付与したい

リクエストの生データ自体はrequest.getInputStream()で取得することができます。
しかし、これを使ってしまうとメソッド名の通りstreamとして取得してしまうため、Controllerにデータが流れなくなります。

こちらに関しては以下のようにoverrideすることで解決できました。

class RequestControllerAdvice : RequestBodyAdvice {
  override fun beforeBodyRead(
    inputMessage: HttpInputMessage,
    parameter: MethodParameter,
    targetType: Type,
    converterType: Class<out HttpMessageConverter<*>>
  ): HttpInputMessage {
    val body = IOUtils.toString(inputMessage.body)

    val builder = StringBuilder()
    builder.append(body)

    val parser = Parser.default()
    val json = parser.parse(builder) as JsonObject

    // do something
    json["_meta"] = "hogehoge"

    val returnInputStream: InputStream = json.toJsonString().byteInputStream()
    val returnHeaders: HttpHeaders = inputMessage.headers

    return object : HttpInputMessage {
      override fun getBody(): InputStream = returnInputStream
      override fun getHeaders(): HttpHeaders = returnHeaders
    }
  }
}

マイグレーションツールがない

JavaのマイグレーションはFlywayが主流です。
しかし、これはバージョンに沿ってSQLを実行するだけで機能として不十分な印象があります。
モデルベースの操作やロールバックなども必要だと思いました。

今後のExposedに期待したいです。

おわりに

今回はサーバサイドKotlinを触ってみた感想について共有させて頂きました。
今後はKtorの方も触ってみようと思います。

間違い等あればご指摘頂けたらと思います。

Wantedlyでもブログ投稿してます

Techブログに加えて会社ブログなどもやっているので、気になった方はぜひ覗いてみてください。
https://www.wantedly.com/companies/ks-rogers

0
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ks-rogers
エンジニアによるエンジニアのためのエンジニアの会社

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
0
Help us understand the problem. What is going on with this article?