こんにちは。エンジニアの松下です。
最近は龍が如く 8 をクリアし、 FF7 リバースを進めているところです。
MP 消費なしで属性攻撃できるようになってて快適!
今回は Spring Boot で OpenAPI ドキュメントを自動生成するときの小技を紹介します。
また、 JSON ライブラリは Kotlin Serialization ドキュメント生成は springdoc-openapi を使うとします。
例えば以下の様な JSON があったとき。
[ { "type": "music", "id": "music1234", "url": "xxxxx/audio.mp3", "artist": "hoge" }, { "type": "photo", "id": "photo1234", "url": "xxxxx/photo.jpg", "description": "例の画像です。" }, { "type": "movie", "id": "movie1234", "url": "xxxxx/movie.mp4", "description": "例の動画です。", "duration": 90 } ]
モデル側は以下の様になると思います。
sealed interface Content data class Music( val id: String, val url: String, val artist: String, ): Content data class Photo( val id: String, val url: String, val description: String, ): Content data class Movie( val id: String, val url: String, val description: String, val duration: Int, ): Content
Kotlin Serialization の場合は @JsonClassDiscriminator
を使うことで JSON を出力すること自体は可能です。
kotlinlang.org
@JsonClassDiscriminator("type") @Serializable sealed interface Content @SerialName("music") @Serializable data class Music( val id: String, val url: String, val artist: String, ): Content @SerialName("photo") @Serializable data class Photo( val id: String, val url: String, val description: String, ): Content @SerialName("movie") @Serializable data class Movie( val id: String, val url: String, val description: String, val duration: Int, ): Content
これに springdoc-openapi のアノテーションを以下のように付与すると表現できます!
@Schema( discriminatorProperty = "type", discriminatorMapping = [ DiscriminatorMapping(value = "music", schema = Music::class), DiscriminatorMapping(value = "photo", schema = Photo:class), DiscriminatorMapping(value = "movie", schema = Movie:class), ], oneOf = [ Music::class, Photo::class, Movie::class, ], ) @JsonClassDiscriminator("type") @Serializable sealed interface Content @SerialName("music") @Serializable data class Music( val id: String, val url: String, val artist: String, ): Content @SerialName("photo") @Serializable data class Photo( val id: String, val url: String, val description: String, ): Content @SerialName("movie") @Serializable data class Movie( val id: String, val url: String, val description: String, val duration: Int, ): Content
生成されるドキュメントのイメージは以下です。
Content: type: object discriminator: propertyName: type mapping: music: '#/components/schemas/Music' photo: '#/components/schemas/Photo' movie: '#/components/schemas/Movie' oneOf: - $ref: '#/components/schemas/Music' - $ref: '#/components/schemas/Photo' - $ref: '#/components/schemas/Movie'
これでクライアントサイドチームが OpenAPI からコード自動生成をしていても、意図どおりのコードが生成されます!
備考:
swagger.io
最後に
弊社ではいっしょに働くアプリエンジニアを募集しています!
ご興味のある方はぜひご応募いただけますと嬉しいです。
Androidエンジニア募集中!: www.wantedly.com
リードエンジニア(Android、iOS問わず)も募集中!:www.wantedly.com