KotlinとSpring Bootを使ってサクッと叩けるAPIを作る

Kotlin Spring SpringBoot

Posted on Oct 4


以前から大分アツいAndroidでのKotlin話であるが、今回はKotlinとSpring Bootを使って簡単にjsonを吐くAPIアプリケーションを作ってみたいと思う。

KotlinについてとSpring Framework,Spring Bootに関しては特記しないので各々よしなに。

プロジェクトの作成

Spring Initializerという素晴らしいものがあるのでこれを使っていく。
今回は

  • Gradle Procjet
  • with Kotlin 1.1.4-3
  • and Spring Boot 1.5.6

で作成。
依存にはwebjpaを追加している。

1
2
compile('org.springframework.boot:spring-boot-starter-data-jpa')  
compile('org.springframework.boot:spring-boot-starter-web')  

がbuild.gradleに追加される形になる。

RESTの基本

クラスに@RestControllerアノテーションを付けるとそのクラスがいい感じにコントローラーとして認識される。 リクエストに対するメソッドのbindは@RequestMapping(PATH, REQUEST_METHOD)というアノテーションをメソッドに対して付与する。

1
2
3
4
5
@RestController
class IndexController {
  @RequestMapping("/", arrayOf(RequestMethod.GET))
  fun index(): String = "Hello Spring with Kotlin!"
}

このクラスを作った状態で./gradlew bootRunをしてあげるとlocalhost:8080Hello Wpring with Kotlin!を表示される。

DBとの接続

単に静的なものを返してもアレなので、DBに保存してあるデータをAPIが叩かれたらjsonで吐くみたいなことをしたい。
Postgresqlで行っていく。

Spring Initializerで依存追加したSpring Data JPAというのがとりあえず強いのでそれを使う。
postgresqlを使うときは更に依存に runtime('org.postgresql:postgresql') を追加してあげるといい。

そしてKotlinを使う場合、EntityとかのモデルクラスをDataClassとしてそのまま作成するとデフォルトコンストラクターが〜みたいなエラーを吐くのでbuild.gradleに以下を追加してあげる。

1
2
classpath ("org.jetbrains.kotlin:kotlin-noarg:${kotlinVersion}")
apply plugin: "kotlin-jpa"

該当のstackoverflowはここ

更にDataSourceの設定として、src/main/resourceの下にconfigディレクトリを作成し、application.ymlを追加してそこにDBへの接続情報を書き込む。

1
2
3
4
5
6
pring:
  datasource:
    url: jdbc:postgresql://localhost/[データベース名]
    username: username
    password: password
    driverClassName: org.postgresql.Driver

これでDBに接続する準備は完了。次に必要なクラスとインターフェースを作っていく。

Entity

まずサンプルを見てもらったほうが理解しやすいのでサンプルコード

1
2
3
4
5
6
7
8
9
10
11
12
13
@Entity
@Table(name = "テーブル名")
data class User (
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  val id: Int,

  @Column(name = "name")
  val name: String,

  @Column(name = "post_code")
  val postCode: String
)

@Columnアノテーションをつけてあげると、スネークケースとキャメルケースの変換をしてくれる(Androidでよく使うところとしてはMoshiとかgsonとかのあんな感じ)。
@GeneratedValueを付与すると、値を指定しなくても自動される。@Idをつけるとプライマリーキーとして指定することができる。

Repository

これがSpring Data JPAの強さ(?)

1
interface UserRepository : JpaRepository<User, Int> {}

これだけ書いておけばOK。JpaRepositoryを継承していればSQLを書かずにメソッド名からいい感じにSQL文を作ってくれてよしなにしてくれるらしい。 例えば名前からselectしたいメソッドが欲しい場合は

1
2
3
interface UserRepository : JpaRepository<User, Int> {
  fun findByName(name: String): List<User>
}

findBy〜とか書いておけばいい感じに勝手にしてくれる。もちろんASCとかDESCとかでの並び替え等々や複雑なものも書ける。参考
あまりに複雑にするとメソッド名が長くなりすぎると思うのでそこはいい感じにしてほしい。

Service

RepositoryとControllerを繋ぐ。

1
2
3
4
5
6
7
8
9
10
@Service
@Transactional
class UserService {
  @Autowired
  lateinit var repository: UserRepository

  fun selectAll(): Lise<User> = repository.findAll(Sort(Sort.Direction.ASC, "id"))

  fun selectFromName(name: String): List<User> = repository.findByName(name)
}

こんな感じで書いてあげる。findAll()メソッドはJpaRepositoryに最初から何も書かずとも生えてるので追加しなくてもOK。
このサービスでのselectAll()findAll()したものをid昇順でソートしてControllerに渡すように書いている。
@Autowiredを書いておけば依存注入を勝手にいい感じにやってくれる。あまりにもいい感じにやってくれすぎててこわい。

Controller

最後にこれを作るとjsonを吐くAPIの完成 上で書いたようなControllerを作ってあげればよい。

1
2
3
4
5
6
7
8
9
10
11
12
13
@RestController
@RequestMapping("/user")
class UserController {

  @Autowired
  lateinit var service: UserService

  @RequestMapping("/all", arrayOf(RequestMethod.GET))
  fun selectAll(): List<User> = service.selectAll()

  @RequestMapping("/name", arrayOf(RequestMethod.GET))
  fun selectFronName(@RequestParam("name")name: String): List<User> = service.selectFromName(name)
}

こんな感じ。
最初のサンプルでは使わなかったが、クラスに@RequestMappingアノテーションを付けると、そのクラスがそのパスにマッピングされる。
なので/user/allfun selectAll()にマッピングされていることになる。

GETでのリクエストパラメータを受け取りたいときは、メソッドの引数に@RequestParam("パラメータ名")変数名: 型を書いてあげればOK。

上記のコントローラーを作れば

localhost:8080/user/all
localhost:8080/user/name?name="なまえ"

でGETするといい感じにDBに入っているデータが適切に取れる。

まとめ

さくっととは言い難いかもしれないが、Kotlinを使っていい感じにAPIアプリケーションを作ることが出来た。
Androidアプリを業務趣味問わずKotlinで書いてる人でAPIが欲しい!って思ったらさくっと作れるのではなかろうか。試してみて欲しい(自分はやってる)。

さくっと作るというとKotlin/ktorのほうが適していると思うので、こちらもそのうちやってみてまとめようと思う。


このエントリーをはてなブックマークに追加
comments powered by Disqus

<< Kotlin Android Extensionsを使ってfindViewByIdとさよならする     OnePlus5が最高すぎる件について >>



2018やぎ小屋