Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get onto a supported http4s version #930

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
43 changes: 27 additions & 16 deletions application/src/main/scala/com/azavea/franklin/api/Server.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,16 @@ import io.chrisdavenport.log4cats
import io.chrisdavenport.log4cats.SelfAwareStructuredLogger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import org.http4s._
import org.http4s.blaze.server.BlazeServerBuilder
import org.http4s.dsl.Http4sDsl
import org.http4s.implicits._
import org.http4s.server.blaze._
import org.http4s.server.middleware._
import org.http4s.server.{Router, Server => HTTP4sServer}
import sttp.client.asynchttpclient.cats.AsyncHttpClientCatsBackend
import sttp.tapir.docs.openapi.OpenAPIDocsInterpreter
import sttp.tapir.docs.openapi.OpenAPIDocsOptions
import sttp.tapir.openapi.circe.yaml._
import sttp.tapir.server.http4s.Http4sServerInterpreter
import sttp.tapir.swagger.http4s.SwaggerHttp4s

import scala.concurrent.ExecutionContext
Expand Down Expand Up @@ -70,12 +72,11 @@ $$$$$ $$/ $$/ $$$$$$$/ $$/ $$/ $$/ $$/ $$/ $$/ $$/ $$/
$$$$
""".split("\n").toList

implicit val serverOptions = ServerOptions.defaultServerOptions[IO]

private def createServer(
apiConfig: ApiConfig,
dbConfig: DatabaseConfig
) = {
val interpreter = Http4sServerInterpreter[IO]
val rootLink = StacLink(
apiConfig.apiHost,
StacLinkType.StacRoot,
Expand Down Expand Up @@ -115,38 +116,48 @@ $$$$
apiConfig.enableTiles,
apiConfig.path
).endpoints ++ landingPage.endpoints
docs = OpenAPIDocsInterpreter.toOpenAPI(allEndpoints, "Franklin", "0.0.1")
docRoutes = new SwaggerHttp4s(docs.toYaml, "open-api", "spec.yaml").routes[IO]
docs = OpenAPIDocsInterpreter().toOpenAPI(allEndpoints, "Franklin", "0.0.1")
docRoutes = new SwaggerHttp4s(docs.toYaml, List("open-api", "spec.yaml")).routes[IO]
searchRoutes = new SearchService[IO](
apiConfig,
apiConfig.defaultLimit,
apiConfig.enableTiles,
xa,
rootLink
rootLink,
interpreter
).routes
tileRoutes = new TileService[IO](
apiConfig.apiHost,
apiConfig.enableTiles,
apiConfig.path,
xa
xa,
interpreter
).routes
itemExtensions <- Resource.eval { itemExtensionsRef[IO] }
collectionExtensions <- Resource.eval { collectionExtensionsRef[IO] }
collectionRoutes = new CollectionsService[IO](xa, apiConfig, collectionExtensions).routes <+> new CollectionItemsService[
collectionRoutes = new CollectionsService[IO](
xa,
apiConfig,
collectionExtensions,
interpreter
).routes <+> new CollectionItemsService[
IO
](
xa,
apiConfig,
itemExtensions,
rootLink
rootLink,
interpreter
).routes
landingPageRoutes = new LandingPageService[IO](apiConfig).routes
router = CORS(
new AccessLoggingMiddleware(
collectionRoutes <+> searchRoutes <+> tileRoutes <+> landingPageRoutes <+> docRoutes,
logger
).withLogging(true)
).orNotFound
landingPageRoutes = new LandingPageService[IO](apiConfig, interpreter).routes
router = CORS.policy
.withAllowOriginAll(
new AccessLoggingMiddleware(
collectionRoutes <+> searchRoutes <+> tileRoutes <+> landingPageRoutes <+> docRoutes,
logger
).withLogging(true)
)
.orNotFound
serverBuilderBlocker <- Blocker[IO]
server <- {
BlazeServerBuilder[IO](serverBuilderBlocker.blockingContext)
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class TileEndpoints[F[_]: Concurrent](enableTiles: Boolean, pathPrefix: Option[S
.and(query[Option[Quantile]]("upperQuantile"))
.and(query[Option[Quantile]]("lowerQuantile"))
.and(query[Option[NonNegInt]]("singleBand"))
.mapTo(ItemRasterTileRequest)
.mapTo[ItemRasterTileRequest]

val collectionRasterTileParameters: EndpointInput[CollectionMosaicRequest] =
collectionMosaicTilePath
Expand All @@ -60,7 +60,7 @@ class TileEndpoints[F[_]: Concurrent](enableTiles: Boolean, pathPrefix: Option[S
.and(query[Option[Quantile]]("upperQuantile"))
.and(query[Option[Quantile]]("lowerQuantile"))
.and(query[Option[NonNegInt]]("singleBand"))
.mapTo(CollectionMosaicRequest)
.mapTo[CollectionMosaicRequest]

val itemRasterTileEndpoint
: Endpoint[ItemRasterTileRequest, NotFound, Array[Byte], Fs2Streams[F]] =
Expand All @@ -75,7 +75,7 @@ class TileEndpoints[F[_]: Concurrent](enableTiles: Boolean, pathPrefix: Option[S
val collectionFootprintTileEndpoint
: Endpoint[MapboxVectorTileFootprintRequest, NotFound, Array[Byte], Fs2Streams[F]] =
endpoint.get
.in(collectionFootprintTileParameters.mapTo(MapboxVectorTileFootprintRequest))
.in(collectionFootprintTileParameters.mapTo[MapboxVectorTileFootprintRequest])
.out(rawBinaryBody[Array[Byte]])
.out(header("content-type", "application/vnd.mapbox-vector-tile"))
.errorOut(oneOf(statusMapping(NF, jsonBody[NotFound].description("not found"))))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import cats.effect.Sync
import cats.syntax.functor._
import io.chrisdavenport.log4cats.Logger
import io.circe.syntax._
import org.http4s.util.CaseInsensitiveString
import org.http4s.{HttpRoutes, Request}
import org.typelevel.ci.CIString

import java.time.Instant

Expand All @@ -21,17 +21,17 @@ class AccessLoggingMiddleware[F[_]: Sync](
else {
Kleisli { (request: Request[F]) =>
val requestStart = Instant.now
val headerWhitelist: Set[CaseInsensitiveString] =
val headerWhitelist: Set[CIString] =
Set(
CaseInsensitiveString("user-agent"),
CaseInsensitiveString("accept-encoding"),
CaseInsensitiveString("referer"),
CaseInsensitiveString("origin"),
CaseInsensitiveString("X-Amzn-Trace-Id")
CIString("user-agent"),
CIString("accept-encoding"),
CIString("referer"),
CIString("origin"),
CIString("X-Amzn-Trace-Id")
)
val headers =
Map(
request.headers.toList.filter(header => headerWhitelist.contains(header.name)) map {
request.headers.headers.filter(header => headerWhitelist.contains(header.name)) map {
header => header.name.toString.toLowerCase -> header.value.asJson
}: _*
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,67 @@ import com.azavea.franklin.datamodel.IfMatchMode
import com.azavea.franklin.datamodel.PaginationToken
import com.azavea.franklin.error.InvalidPatch
import com.azavea.stac4s._
import com.azavea.stac4s.types._
import eu.timepit.refined.types.string.NonEmptyString
import geotrellis.vector.Geometry
import io.circe.syntax._
import io.circe.{Encoder, Json}
import sttp.tapir.Codec.PlainCodec
import sttp.tapir.codec.enumeratum._
import sttp.tapir.codec.refined._
import sttp.tapir.generic.auto._
import sttp.tapir.json.circe._
import sttp.tapir.{Codec, DecodeResult, Schema}
import sttp.tapir.{Codec, DecodeResult, Schema, SchemaType}

import scala.util.Try

package object schemas {

implicit val schemaStacCollection: Schema[StacCollection] = Schema(schemaForCirceJson.schemaType)
implicit lazy val schemaStacLicense: Schema[StacLicense] = Schema.derived

implicit val schemaForTemporalExtent: Schema[TemporalExtent] = Schema(
schemaForCirceJson.schemaType
implicit lazy val schemaSpatialExtent: Schema[SpatialExtent] = Schema.derived

implicit lazy val schemaTemporalExtent: Schema[List[TemporalExtent]] = Schema.derived

implicit lazy val schemaInterval: Schema[Interval] = Schema.derived

implicit lazy val schemaStacExtent: Schema[StacExtent] = Schema.derived

implicit lazy val schemaSummaryValue: Schema[SummaryValue] = Schema.derived

// We can fill in a product schema without any fields as a placeholder, which is
// no worse than the schema for circe json that we used to have
implicit val schemaSummaries: Schema[Map[NonEmptyString, SummaryValue]] = Schema.apply(
SchemaType.SProduct[Map[NonEmptyString, SummaryValue]](Nil),
Some(Schema.SName("summaries"))
)
implicit val schemaForGeometry: Schema[Geometry] = Schema(schemaForCirceJson.schemaType)

implicit val schemaForStacItem: Schema[StacItem] = Schema(schemaForCirceJson.schemaType)
implicit val schemaForInvalidPatch: Schema[InvalidPatch] = Schema(schemaForCirceJson.schemaType)
implicit lazy val schemaForStacLink: Schema[StacLinkType] = Schema.derived

implicit lazy val schemaStacCollection: Schema[StacCollection] = Schema.derived

implicit lazy val schemaForTemporalExtent: Schema[TemporalExtent] = Schema.derived

// We can fill in a product schema without any fields as a placeholder, which is
// no worse than the schema for circe json that we used to have
implicit val schemaForGeometry: Schema[Geometry] = Schema(
SchemaType.SProduct[Geometry](Nil),
Some(Schema.SName("geometry"))
)

implicit lazy val schemaForBbox: Schema[TwoDimBbox] = Schema.derived

// We can fill in a product schema without any fields as a placeholder, which is
// no worse than the schema for circe json that we used to have
implicit val schemaForItemDatetime: Schema[ItemDatetime] = Schema(
SchemaType.SProduct[ItemDatetime](Nil),
Some(Schema.SName("datetime"))
)

implicit lazy val schemaForItemProperties: Schema[ItemProperties] = Schema.derived

implicit lazy val schemaForStacItem: Schema[StacItem] = Schema.derived
implicit lazy val schemaForInvalidPatch: Schema[InvalidPatch] = Schema.derived

def decode(s: String): DecodeResult[TemporalExtent] = {
temporalExtentFromString(s) match {
Expand Down Expand Up @@ -89,9 +128,6 @@ package object schemas {
implicit val codecPaginationToken: Codec.PlainCodec[PaginationToken] =
Codec.string.mapDecode(PaginationToken.decPaginationToken)(PaginationToken.encPaginationToken)

implicit val schemaForStacLink: Schema[StacLinkType] =
Schema.schemaForString.map(s => s.asJson.as[StacLinkType].toOption)(_.repr)

implicit val codecIfMatchMode: Codec.PlainCodec[IfMatchMode] =
Codec.string.mapDecode(s => DecodeResult.Value(IfMatchMode.fromString(s)))(_.toString)
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ import org.http4s.HttpRoutes
import org.http4s.dsl.Http4sDsl
import sttp.client.{NothingT, SttpBackend}
import sttp.tapir.DecodeResult
import sttp.tapir.server.DecodeFailureContext
import sttp.tapir.server.ServerDefaults
import sttp.tapir.server.http4s._

import java.net.URLDecoder
Expand All @@ -45,12 +43,10 @@ class CollectionItemsService[F[_]: Concurrent](
xa: Transactor[F],
apiConfig: ApiConfig,
itemExtensionsRef: ExtensionRef[F, StacItem],
rootLink: StacLink
rootLink: StacLink,
interpreter: Http4sServerInterpreter[F]
)(
implicit contextShift: ContextShift[F],
timer: Timer[F],
serverOptions: Http4sServerOptions[F],
backend: SttpBackend[F, Nothing, NothingT],
implicit backend: SttpBackend[F, Nothing, NothingT],
logger: Logger[F]
) extends Http4sDsl[F] {

Expand Down Expand Up @@ -345,31 +341,31 @@ class CollectionItemsService[F[_]: Concurrent](
new CollectionItemEndpoints(defaultLimit, enableTransactions, enableTiles, apiConfig.path)

val collectionItemTileRoutes =
Http4sServerInterpreter.toRoutes(collectionItemEndpoints.collectionItemTiles)({
interpreter.toRoutes(collectionItemEndpoints.collectionItemTiles)({
case (collectionId, itemId) => getCollectionItemTileInfo(collectionId, itemId)
})

val transactionRoutes: List[HttpRoutes[F]] = List(
Http4sServerInterpreter.toRoutes(collectionItemEndpoints.postItem)({
interpreter.toRoutes(collectionItemEndpoints.postItem)({
case (collectionId, stacItem) => postItem(collectionId, stacItem)
}),
Http4sServerInterpreter.toRoutes(collectionItemEndpoints.putItem)({
interpreter.toRoutes(collectionItemEndpoints.putItem)({
case (collectionId, itemId, stacItem, etag) => putItem(collectionId, itemId, stacItem, etag)
}),
Http4sServerInterpreter.toRoutes(collectionItemEndpoints.deleteItem)({
interpreter.toRoutes(collectionItemEndpoints.deleteItem)({
case (collectionId, itemId) => deleteItem(collectionId, itemId)
}),
Http4sServerInterpreter.toRoutes(collectionItemEndpoints.patchItem)({
interpreter.toRoutes(collectionItemEndpoints.patchItem)({
case (collectionId, itemId, jsonPatch, etag) =>
patchItem(collectionId, itemId, jsonPatch, etag)
})
)

val routesList: NonEmptyList[HttpRoutes[F]] = NonEmptyList.of(
Http4sServerInterpreter.toRoutes(collectionItemEndpoints.collectionItemsList)({ query =>
interpreter.toRoutes(collectionItemEndpoints.collectionItemsList)({ query =>
Function.tupled(listCollectionItems _)(query)
}),
Http4sServerInterpreter.toRoutes(collectionItemEndpoints.collectionItemsUnique)({
interpreter.toRoutes(collectionItemEndpoints.collectionItemsUnique)({
case (collectionId, itemId) => getCollectionItemUnique(collectionId, itemId)
})
) ++ (if (enableTransactions) {
Expand Down
Loading