お久しぶりです。開発部のyanagitaです。
以前、Play FrameworkプロジェクトでSwaggerを導入した記事を本ブログで投稿させていただきました。
執筆は、開発部のNishikawa氏 lab.astamuse.co.jp
今回は、Akka HTTPを使用したプロジェクトでSwagger Specification(以下、Swagger Spec)を出力したいと思います。
使用するライブラリ
今回はswagger-akka-http/swagger-akka-httpを使用します。
サンプルプロジェクトがあるのでそちらで解説を入れていきます。
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を生成するサービス作成とルート追加が必要となります。
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
アスタミューゼではたくさんのエンジニア&デザイナをまだまだまだ募集しています。 気になる方は下からご応募下さい!新しい出会いをメンバー一同お待ちしてます!