mirror of
https://github.com/arcan1s/ffxivbis.git
synced 2025-04-24 17:27:17 +00:00
api docs review
This commit is contained in:
parent
feea01a47e
commit
963e84f792
@ -12,6 +12,7 @@ libraryDependencies += "com.typesafe.akka" %% "akka-actor-typed" % AkkaVersion
|
||||
libraryDependencies += "com.typesafe.akka" %% "akka-stream" % AkkaVersion
|
||||
libraryDependencies += "com.github.swagger-akka-http" %% "swagger-akka-http" % "2.6.0"
|
||||
libraryDependencies += "jakarta.platform" % "jakarta.jakartaee-web-api" % "9.1.0"
|
||||
libraryDependencies += "ch.megard" %% "akka-http-cors" % "1.1.2"
|
||||
|
||||
libraryDependencies += "io.spray" %% "spray-json" % "1.3.6"
|
||||
|
||||
|
23
src/main/resources/html/api.html
Normal file
23
src/main/resources/html/api.html
Normal file
@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>FFXIV loot helper API</title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<!-- Embed elements Elements via Web Component -->
|
||||
<script src="https://unpkg.com/@stoplight/elements/web-components.min.js"></script>
|
||||
<link rel="stylesheet" href="https://unpkg.com/@stoplight/elements/styles.min.css" type="text/css">
|
||||
|
||||
<link rel="shortcut icon" href="/static/favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<elements-api
|
||||
apiDescriptionUrl="/api-docs/swagger.json"
|
||||
router="hash"
|
||||
layout="sidebar"
|
||||
/>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -139,6 +139,7 @@
|
||||
<footer class="d-flex flex-wrap justify-content-between align-items-center border-top">
|
||||
<ul class="nav">
|
||||
<li><a class="nav-link" href="/" title="home">home</a></li>
|
||||
<li><a class="nav-link" href="/api-docs" title="api">api</a></li>
|
||||
</ul>
|
||||
|
||||
<ul class="nav">
|
||||
|
@ -71,7 +71,9 @@
|
||||
|
||||
<div class="container">
|
||||
<footer class="d-flex flex-wrap justify-content-between align-items-center border-top">
|
||||
<ul class="nav"></ul>
|
||||
<ul class="nav">
|
||||
<li><a class="nav-link" href="/api-docs" title="api">api</a></li>
|
||||
</ul>
|
||||
|
||||
<ul class="nav">
|
||||
<li><a class="nav-link" href="https://github.com/arcan1s/ffxivbis" title="sources">ffxivbis</a></li>
|
||||
|
@ -156,6 +156,7 @@
|
||||
<footer class="d-flex flex-wrap justify-content-between align-items-center border-top">
|
||||
<ul class="nav">
|
||||
<li><a class="nav-link" href="/" title="home">home</a></li>
|
||||
<li><a class="nav-link" href="/api-docs" title="api">api</a></li>
|
||||
</ul>
|
||||
|
||||
<ul class="nav">
|
||||
|
@ -129,6 +129,7 @@
|
||||
<footer class="d-flex flex-wrap justify-content-between align-items-center border-top">
|
||||
<ul class="nav">
|
||||
<li><a class="nav-link" href="/" title="home">home</a></li>
|
||||
<li><a class="nav-link" href="/api-docs" title="api">api</a></li>
|
||||
</ul>
|
||||
|
||||
<ul class="nav">
|
||||
|
@ -1,19 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>FFXIV loot helper API</title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" type="text/css">
|
||||
|
||||
<link rel="shortcut icon" href="/static/favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<redoc spec-url="/api-docs/swagger.json"></redoc>
|
||||
<script src="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js"> </script>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -123,6 +123,7 @@
|
||||
<footer class="d-flex flex-wrap justify-content-between align-items-center border-top">
|
||||
<ul class="nav">
|
||||
<li><a class="nav-link" href="/" title="home">home</a></li>
|
||||
<li><a class="nav-link" href="/api-docs" title="api">api</a></li>
|
||||
</ul>
|
||||
|
||||
<ul class="nav">
|
||||
|
@ -50,7 +50,7 @@ class Application(context: ActorContext[Nothing]) extends AbstractBehavior[Nothi
|
||||
val party = context.spawn(PartyService(storage), "party")
|
||||
val http = new RootEndpoint(context.system, party, bisProvider)
|
||||
|
||||
val flow = Route.toFlow(http.route)(context.system)
|
||||
val flow = Route.toFlow(http.routes)(context.system)
|
||||
Http(context.system).newServerAt(host, port).bindFlow(flow)
|
||||
|
||||
case Success(result) =>
|
||||
|
@ -12,6 +12,7 @@ import akka.actor.typed.{ActorRef, ActorSystem, Scheduler}
|
||||
import akka.http.scaladsl.server.Directives._
|
||||
import akka.http.scaladsl.server._
|
||||
import akka.util.Timeout
|
||||
import ch.megard.akka.http.cors.scaladsl.CorsDirectives.cors
|
||||
import com.typesafe.scalalogging.StrictLogging
|
||||
import me.arcanis.ffxivbis.http.api.v1.RootApiV1Endpoint
|
||||
import me.arcanis.ffxivbis.http.view.RootView
|
||||
@ -33,28 +34,30 @@ class RootEndpoint(system: ActorSystem[Nothing], storage: ActorRef[Message], pro
|
||||
private val rootView = new RootView(auth)
|
||||
private val swagger = new Swagger(config)
|
||||
|
||||
def route: Route =
|
||||
def routes: Route =
|
||||
withHttpLog {
|
||||
ignoreTrailingSlash {
|
||||
apiRoute ~ htmlRoute ~ swagger.routes ~ swaggerUIRoute
|
||||
cors() {
|
||||
apiRoutes ~ htmlRoutes ~ swagger.routes ~ swaggerUIRoutes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def apiRoute: Route =
|
||||
private def apiRoutes: Route =
|
||||
pathPrefix("api") {
|
||||
pathPrefix(Segment) {
|
||||
case "v1" => rootApiV1Endpoint.route
|
||||
case "v1" => rootApiV1Endpoint.routes
|
||||
case _ => reject
|
||||
}
|
||||
}
|
||||
|
||||
private def htmlRoute: Route =
|
||||
private def htmlRoutes: Route =
|
||||
pathPrefix("static") {
|
||||
getFromResourceDirectory("static")
|
||||
} ~ rootView.route
|
||||
} ~ rootView.routes
|
||||
|
||||
private def swaggerUIRoute: Route =
|
||||
private def swaggerUIRoutes: Route =
|
||||
path("api-docs") {
|
||||
getFromResource("html/redoc.html")
|
||||
getFromResource("html/api.html")
|
||||
}
|
||||
}
|
||||
|
@ -42,8 +42,8 @@ class Swagger(config: Config) extends SwaggerHttpService {
|
||||
.description("basic http auth")
|
||||
.`type`(SecurityScheme.Type.HTTP)
|
||||
.in(SecurityScheme.In.HEADER)
|
||||
.scheme("bearer")
|
||||
override val securitySchemes: Map[String, SecurityScheme] = Map("basic auth" -> basicAuth)
|
||||
.scheme("basic")
|
||||
override val securitySchemes: Map[String, SecurityScheme] = Map("auth" -> basicAuth)
|
||||
|
||||
override val unwantedDefinitions: Seq[String] =
|
||||
Seq("Function1", "Function1RequestContextFutureRouteResult")
|
||||
|
@ -40,7 +40,7 @@ class BiSEndpoint(
|
||||
with Authorization
|
||||
with JsonSupport {
|
||||
|
||||
def route: Route = createBiS ~ getBiS ~ modifyBiS
|
||||
def routes: Route = createBiS ~ getBiS ~ modifyBiS
|
||||
|
||||
@PUT
|
||||
@Path("party/{partyId}/bis")
|
||||
|
@ -11,6 +11,7 @@ package me.arcanis.ffxivbis.http.api.v1
|
||||
import akka.http.scaladsl.model._
|
||||
import akka.http.scaladsl.server.Directives._
|
||||
import akka.http.scaladsl.server._
|
||||
import ch.megard.akka.http.cors.scaladsl.CorsDirectives.corsRejectionHandler
|
||||
import com.typesafe.scalalogging.StrictLogging
|
||||
import me.arcanis.ffxivbis.http.api.v1.json._
|
||||
import spray.json._
|
||||
@ -27,9 +28,26 @@ trait HttpHandler extends StrictLogging { this: JsonSupport =>
|
||||
}
|
||||
|
||||
def rejectionHandler: RejectionHandler =
|
||||
RejectionHandler.default
|
||||
RejectionHandler
|
||||
.newBuilder()
|
||||
.handleAll[MethodRejection] { rejections =>
|
||||
val (methods, names) = rejections.map(r => r.supported -> r.supported.name).unzip
|
||||
|
||||
respondWithHeader(headers.Allow(methods)) {
|
||||
options {
|
||||
complete(StatusCodes.OK, HttpEntity.Empty)
|
||||
} ~
|
||||
complete(
|
||||
StatusCodes.MethodNotAllowed,
|
||||
s"HTTP method not allowed, supported methods: ${names.mkString(", ")}"
|
||||
)
|
||||
}
|
||||
}
|
||||
.result()
|
||||
.withFallback(corsRejectionHandler)
|
||||
.seal
|
||||
.mapRejectionResponse {
|
||||
case response @ HttpResponse(_, _, entity: HttpEntity.Strict, _) =>
|
||||
case response @ HttpResponse(_, _, entity: HttpEntity.Strict, _) if entity.data.nonEmpty =>
|
||||
val message = ErrorModel(entity.data.utf8String).toJson
|
||||
response.withEntity(HttpEntity(ContentTypes.`application/json`, message.compactPrint))
|
||||
case other => other
|
||||
|
@ -37,7 +37,7 @@ class LootEndpoint(override val storage: ActorRef[Message], override val auth: A
|
||||
with JsonSupport
|
||||
with HttpHandler {
|
||||
|
||||
def route: Route = getLoot ~ modifyLoot ~ suggestLoot
|
||||
def routes: Route = getLoot ~ modifyLoot ~ suggestLoot
|
||||
|
||||
@GET
|
||||
@Path("party/{partyId}/loot")
|
||||
|
@ -40,7 +40,7 @@ class PartyEndpoint(
|
||||
with JsonSupport
|
||||
with HttpHandler {
|
||||
|
||||
def route: Route = getPartyDescription ~ modifyPartyDescription
|
||||
def routes: Route = getPartyDescription ~ modifyPartyDescription
|
||||
|
||||
@GET
|
||||
@Path("party/{partyId}/description")
|
||||
|
@ -41,7 +41,7 @@ class PlayerEndpoint(
|
||||
with JsonSupport
|
||||
with HttpHandler {
|
||||
|
||||
def route: Route = getParty ~ getPartyStats ~ modifyParty
|
||||
def routes: Route = getParty ~ getPartyStats ~ modifyParty
|
||||
|
||||
@GET
|
||||
@Path("party/{partyId}")
|
||||
|
@ -36,11 +36,11 @@ class RootApiV1Endpoint(
|
||||
private val typesEndpoint = new TypesEndpoint(config)
|
||||
private val userEndpoint = new UserEndpoint(storage, auth)
|
||||
|
||||
def route: Route =
|
||||
def routes: Route =
|
||||
handleExceptions(exceptionHandler) {
|
||||
handleRejections(rejectionHandler) {
|
||||
biSEndpoint.route ~ lootEndpoint.route ~ partyEndpoint.route ~ playerEndpoint.route ~
|
||||
statusEndpoint.route ~ typesEndpoint.route ~ userEndpoint.route
|
||||
biSEndpoint.routes ~ lootEndpoint.routes ~ partyEndpoint.routes ~ playerEndpoint.routes ~
|
||||
statusEndpoint.routes ~ typesEndpoint.routes ~ userEndpoint.routes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ import me.arcanis.ffxivbis.http.api.v1.json._
|
||||
@Path("/api/v1")
|
||||
class StatusEndpoint extends JsonSupport {
|
||||
|
||||
def route: Route = getServerStatus
|
||||
def routes: Route = getServerStatus
|
||||
|
||||
@GET
|
||||
@Path("status")
|
||||
|
@ -21,7 +21,7 @@ import me.arcanis.ffxivbis.models._
|
||||
@Path("/api/v1")
|
||||
class TypesEndpoint(config: Config) extends JsonSupport {
|
||||
|
||||
def route: Route = getAllJobs ~ getJobs ~ getPermissions ~ getPieces ~ getPieceTypes ~ getPriority
|
||||
def routes: Route = getAllJobs ~ getJobs ~ getPermissions ~ getPieces ~ getPieceTypes ~ getPriority
|
||||
|
||||
@GET
|
||||
@Path("types/jobs/all")
|
||||
|
@ -36,7 +36,7 @@ class UserEndpoint(override val storage: ActorRef[Message], override val auth: A
|
||||
with Authorization
|
||||
with JsonSupport {
|
||||
|
||||
def route: Route = createParty ~ createUser ~ deleteUser ~ getUsers ~ getUsersCurrent
|
||||
def routes: Route = createParty ~ createUser ~ deleteUser ~ getUsers ~ getUsersCurrent
|
||||
|
||||
@PUT
|
||||
@Path("party")
|
||||
|
@ -19,7 +19,10 @@ case class PlayerModel(
|
||||
@Schema(description = "looted pieces") loot: Option[Seq[LootModel]],
|
||||
@Schema(description = "link to best in slot", example = "https://ffxiv.ariyala.com/19V5R") link: Option[String],
|
||||
@Schema(description = "player loot priority", `type` = "number") priority: Option[Int],
|
||||
@Schema(description = "count of looted pieces which are parts of best in slot") lootCountBiS: Option[Int],
|
||||
@Schema(
|
||||
description = "count of looted pieces which are parts of best in slot",
|
||||
`type` = "number"
|
||||
) lootCountBiS: Option[Int],
|
||||
@Schema(description = "total count of looted pieces", `type` = "number") lootCountTotal: Option[Int],
|
||||
) {
|
||||
|
||||
|
@ -15,7 +15,7 @@ import me.arcanis.ffxivbis.http.{Authorization, AuthorizationProvider}
|
||||
|
||||
class RootView(override val auth: AuthorizationProvider) extends Authorization {
|
||||
|
||||
def route: Route = getBiS ~ getIndex ~ getLoot ~ getParty ~ getUsers
|
||||
def routes: Route = getBiS ~ getIndex ~ getLoot ~ getParty ~ getUsers
|
||||
|
||||
def getBiS: Route =
|
||||
path("party" / Segment / "bis") { partyId: String =>
|
||||
|
@ -37,7 +37,7 @@ class BiSEndpointTest extends AnyWordSpecLike with Matchers with ScalatestRouteT
|
||||
private val storage = testKit.spawn(Database())
|
||||
private val provider = testKit.spawn(BisProvider())
|
||||
private val party = testKit.spawn(PartyService(storage))
|
||||
private val route = new BiSEndpoint(party, provider, Fixtures.authProvider)(askTimeout, testKit.scheduler).route
|
||||
private val route = new BiSEndpoint(party, provider, Fixtures.authProvider)(askTimeout, testKit.scheduler).routes
|
||||
|
||||
override def beforeAll(): Unit = {
|
||||
super.beforeAll()
|
||||
|
@ -34,7 +34,7 @@ class LootEndpointTest extends AnyWordSpecLike with Matchers with ScalatestRoute
|
||||
|
||||
private val storage = testKit.spawn(Database())
|
||||
private val party = testKit.spawn(PartyService(storage))
|
||||
private val route = new LootEndpoint(party, Fixtures.authProvider)(askTimeout, testKit.scheduler).route
|
||||
private val route = new LootEndpoint(party, Fixtures.authProvider)(askTimeout, testKit.scheduler).routes
|
||||
|
||||
override def beforeAll(): Unit = {
|
||||
super.beforeAll()
|
||||
|
@ -35,7 +35,7 @@ class PartyEndpointTest extends AnyWordSpecLike with Matchers with ScalatestRout
|
||||
private val storage = testKit.spawn(Database())
|
||||
private val provider = testKit.spawn(BisProvider())
|
||||
private val party = testKit.spawn(PartyService(storage))
|
||||
private val route = new PartyEndpoint(party, provider, Fixtures.authProvider)(askTimeout, testKit.scheduler).route
|
||||
private val route = new PartyEndpoint(party, provider, Fixtures.authProvider)(askTimeout, testKit.scheduler).routes
|
||||
|
||||
override def beforeAll(): Unit = {
|
||||
super.beforeAll()
|
||||
|
@ -34,7 +34,7 @@ class PlayerEndpointTest extends AnyWordSpecLike with Matchers with ScalatestRou
|
||||
private val storage = testKit.spawn(Database())
|
||||
private val provider = testKit.spawn(BisProvider())
|
||||
private val party = testKit.spawn(PartyService(storage))
|
||||
private val route = new PlayerEndpoint(party, provider, Fixtures.authProvider)(askTimeout, testKit.scheduler).route
|
||||
private val route = new PlayerEndpoint(party, provider, Fixtures.authProvider)(askTimeout, testKit.scheduler).routes
|
||||
|
||||
override def beforeAll(): Unit = {
|
||||
super.beforeAll()
|
||||
|
@ -15,7 +15,7 @@ class StatusEndpointTest extends AnyWordSpecLike
|
||||
|
||||
override val testConfig: Config = Settings.withRandomDatabase
|
||||
|
||||
private val route = new StatusEndpoint().route
|
||||
private val route = new StatusEndpoint().routes
|
||||
|
||||
"api v1 status endpoint" must {
|
||||
|
||||
|
@ -16,7 +16,7 @@ class TypesEndpointTest extends AnyWordSpecLike
|
||||
|
||||
override val testConfig: Config = Settings.withRandomDatabase
|
||||
|
||||
private val route = new TypesEndpoint(testConfig).route
|
||||
private val route = new TypesEndpoint(testConfig).routes
|
||||
|
||||
"api v1 types endpoint" must {
|
||||
|
||||
|
@ -30,7 +30,7 @@ class UserEndpointTest extends AnyWordSpecLike with Matchers with ScalatestRoute
|
||||
private var partyId = Fixtures.partyId
|
||||
private val storage = testKit.spawn(Database())
|
||||
private val party = testKit.spawn(PartyService(storage))
|
||||
private val route = new UserEndpoint(party, Fixtures.authProvider)(askTimeout, testKit.scheduler).route
|
||||
private val route = new UserEndpoint(party, Fixtures.authProvider)(askTimeout, testKit.scheduler).routes
|
||||
|
||||
override def beforeAll(): Unit = {
|
||||
super.beforeAll()
|
||||
|
Loading…
Reference in New Issue
Block a user