对Tapir的深度剖析
利用Tapir,一个基于 OpenAPI规范 (也可称作Swagger规范)的开源API设计工具,开发者可以通过一种高层级的抽象方式更轻松地构建和记录RESTful API。
此工具以图形化形式展示API端点及参数,并且配备了丰富的编辑选项及自动文档生成能力,方便开发者生成清晰易懂的说明文件,并支持多种输出格式如OpenAPI和Markdown等,从而适应各种不同的需求。
Tapir不仅限于API的设计与记录,它同样提供API测试和模拟服务,允许开发者模拟API响应进行测试,并且它还能自动生成客户端代码,帮助快速实现API的应用。
选择Tapir的四大理由
类型安全性: Tapir的核心优势之一在于其强调类型安全的API设计。通过Scala的强类型系统来验证API结构的合法性,这有助于避免运行时错误。
import sttp.tapir._
import sttp.tapir.generic.auto._
import sttp.tapir.json.circe._
import io.circe.generic.auto._
import java.util.UUID
case class User(name: String)
val paging: EndpointInput[(UUID, Option[Int])] =
query[UUID]("start").and(query[Option[Int]]("limit"))
val listUsersEndpoint: PublicEndpoint[(UUID, Option[Int]), Unit, List[User], Any] =
endpoint.in("user" / "list").in(paging).out(jsonBody[List[User]])
易于测试: 由于Tapir的类型安全设计,可以借助Scala的测试框架轻松创建测试用例,确保API在不同情形下都能正常工作,这有助于提升开发流程的效率,降低错误率。
维护简单: Tapir通过将API定义拆分为独立的、可组合的元素,使得维护API定义变得简单。这便于对API的特定部分进行更新,而不会影响到整体结构。
自动化生成代码和文档: Tapir能够将API定义转化成各类客户端和服务器端代码,并且还可以自动化生成API文档。这意味着降低了手工编写代码和维护文档的工作量和出错风险。
快速上手Tapir
开始之前先添加相关的库
"com.softwaremill.sttp.tapir" %% "tapir-core" % "1.2.9"
定义一个端点(Endpoint)
case class Status(uptime: Long)
val statusEndpoint: PublicEndpoint[Unit, ErrorInfo, Status, Any] =
baseEndpoint.in("status").out(jsonBody[Status])
以下是一个例子,演示如何设置分页
import sttp.tapir._
import java.util.UUID
case class Paging(from: UUID, limit: Option[Int])
val paging: EndpointInput[Paging] =
query[UUID]("start").and(query[Option[Int]]("limit"))
.map(input => Paging(input._1, input._2))(paging => (paging.from, paging.limit))
对接Web框架
import sttp.tapir._
import sttp.tapir.server.akkahttp.AkkaHttpServerInterpreter
import scala.concurrent.Future
import akka.http.scaladsl.server.Route
import scala.concurrent.ExecutionContext.Implicits.global
def countCharacters(s: String): Future[Either[Unit, Int]] =
Future.successful(Right[Unit, Int](s.length))
val countCharactersRoute: Route =
AkkaHttpServerInterpreter().toRoute(countCharactersEndpoint.serverLogic(countCharacters))
val countCharactersEndpoint: PublicEndpoint[String, Unit, Int, Any] =
endpoint.in(stringBody).out(plainBody[Int])
val countCharactersRoute: Route =
AkkaHttpServerInterpreter().toRoute(countCharactersEndpoint.serverLogic(countCharacters))
自动生成Swagger UI
生成的描述信息可以通过 Swagger UI 或Redoc界面共享给用户。
"com.softwaremill.sttp.tapir" %% "tapir-swagger-ui-bundle" % "1.2.9"
import sttp.tapir._
import sttp.tapir.swagger.bundle.SwaggerInterpreter
import sttp.tapir.server.akkahttp.AkkaHttpServerInterpreter
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
val myEndpoints: List[AnyEndpoint] = ???
val swaggerEndpoints =
SwaggerInterpreter().fromEndpoints[Future](myEndpoints, "My App", "1.0")
val swaggerRoute =
AkkaHttpServerInterpreter().toRoute(swaggerEndpoints)
使用yaml生成端点
addSbtPlugin("com.softwaremill.sttp.tapir" % "sbt-openapi-codegen" % "1.2.9")
Enable the plugin for your project in the build.sbt:
enablePlugins(OpenapiCodegenPlugin)
Add your OpenApi file to the project, and override the openapiSwaggerFile setting in the build.sbt:
openapiSwaggerFile := baseDirectory.value / "swagger.yaml"
下面是一些配置说明:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。