Akka-Http와 Swagger를 연계

18195 단어 Akka-HTTPswaggerScala
연계시키는데 빠졌기 때문에 비망록입니다.

사용할 라이브러리


libraryDependencies ++= Seq(
  "com.typesafe.akka"            %% "akka-http"         % "10.1.7",
  "com.github.swagger-akka-http" %% "swagger-akka-http" % "2.0.3",
  "javax.ws.rs"                  % "javax.ws.rs-api"    % "2.0.1",
  "ch.megard"                    %% "akka-http-cors"    % "0.4.1"
)

API 엔드포인트 정의



/items에서 응답을 반환하는 API를 만듭니다.

ItemContoller
package json_server.http.controller

import akka.http.scaladsl.model.{ ContentType, HttpEntity, HttpResponse, MediaTypes, StatusCodes }
import akka.http.scaladsl.server.{ Directives, Route }
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.media.{ Content, Schema }
import io.swagger.v3.oas.annotations.parameters.RequestBody
import io.swagger.v3.oas.annotations.responses.ApiResponse
import javax.ws.rs._

@Path("/items")
@Consumes(Array("application/json"))
@Produces(Array("application/json"))
class ItemController extends Directives {

  def route: Route = create

  @GET
  @Operation(
    summary = "Get Items",
    description = "",
    requestBody = new RequestBody(content = Array(new Content(schema = new Schema()))),
    responses = Array(
      new ApiResponse(responseCode = "200",
                      description = "Create response",
                      content = Array(new Content(schema = new Schema()))),
      new ApiResponse(responseCode = "500", description = "Internal server error")
    )
  )
  def create: Route = path("items") {
    get {
      complete(
        HttpResponse(entity = HttpEntity(ContentType(MediaTypes.`application/json`), """
          {"items":"pen"}
          """))
      )
    }
  }
}

SwaggerDocService 정의



SwaggerDocService.scala

package json_server.http

import com.github.swagger.akka.SwaggerHttpService
import com.typesafe.config.ConfigFactory

class SwaggerDocService(val apis: Set[Class[_]]) extends SwaggerHttpService {

  val conf = ConfigFactory.load

  val address = conf.getString(MY_HOST)    // 0.0.0.0
  val port    = conf.getInt(MY_PORT)       // 5000

  override val apiClasses          = apis
  override val host                = s"$address:$port"
  override val apiDocsPath         = "api-docs"         // このパスでyaml/jsonを生成する
  override val schemes             = List("https")      // httpsを使いたい場合はhttpsを指定
}

Route 정의



Routes.scala
package json_server.http

import akka.actor.ActorSystem
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import akka.http.scaladsl.model.StatusCodes
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.{ ExceptionHandler, Route }
import akka.util.Timeout
import ch.megard.akka.http.cors.scaladsl.CorsDirectives._ 

import json_server.http.controller.ItemControlle

import scala.util.control.NonFatal

class Routes()(implicit system: ActorSystem, timeout: Timeout) extends SprayJsonSupport {

  /***
    * Custom Error Handler
    */
  implicit def customExceptionHandler: ExceptionHandler = ExceptionHandler {
    case NonFatal(ex) =>
      extractLog { implicit log =>
        extractUri { uri =>
          val errorMessage = s"ERROR!! URI: $uri, REASON: ${ex.getMessage}"

          log.error(errorMessage)

          complete(StatusCodes.InternalServerError -> errorMessage)
        }
      }
  }

  /***
    * Routing
    */
  val routes: Route = (cors() | handleExceptions(customExceptionHandler)) { // Route作成時にcors()を呼ばないとSwaggerでExecuteした時にレスポンスの内容が画面に表示されない
    extractLog { implicit log =>
      extractUri { uri =>
        extractMethod { method =>
          log.info(s"call api. method: ${method.value}, uri: $uri")

          path("swagger") {
            getFromResource("swagger/index.html")
          } ~ 
          // swaggerディレクトリ下のファイルにアクセス可能にする
          getFromResourceDirectory("swagger") ~ 
          // APIエンドポイントとなるクラスをSwaggerHttpService.apiClassesに渡す
          new SwaggerDocService(Set(classOf[ItemController])).routes ~ 
          // エンドポイントのルーティングを追加
          new ItemController().route
        }
      }
    }
  }
}

swagger.yaml 생성



브라우저에서 다음 URL에 액세스합니다.
https://localhost:5000/api-docs/swagger.yaml

그러면 아래의 yaml 형식의 텍스트가 브라우저에 표시됩니다.
openapi: 3.0.1
info:
  title: ""
  description: ""
  termsOfService: ""
  version: ""
servers:
- url: https://0.0.0.0:5000
security: []
paths:
  /items:
    get:
      summary: Get Items
      operationId: create
      requestBody:
        content:
          application/json: {}
      responses:
        200:
          description: Create response
          content:
            application/json: {}
        500:
          description: Internal server error
components:
  schemas:
    Function1RequestContextFutureRouteResult:
      type: object
resources 아래에 swagger.yaml를 만들고이 내용을 복사하십시오.

Swagger 실행



브라우저에서 다음 URL에 액세스하면 Swagger UI가 시작됩니다.
https://localhost:5000/swagger

애완 동물 스토어의 API 서비스 같다.


화면 상단의 텍스트 박스에, 애완동물 스토어용의 Swagger 리소스 https://petstore.swagger.io/v2/swagger.json 가 지정되어 있으므로, 방금 작성한 swagger.yaml 를 지정한다.
실행하면 Swagger에서 엔드포인트에 액세스할 수 있게 된다.


매번 swagger.yaml를 지정하는 것이 번거롭기 때문에 다음 URL로 화면을 표시하면 swagger.yaml를 읽은 상태로 시작할 수 있습니다.
https://localhost:5000/swagger?https://localhost:5000/swagger.yaml

참고:
akka-http에 swagger2.x를 통합하는 방법

좋은 웹페이지 즐겨찾기