Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
dhpiggott committed Aug 2, 2023
1 parent 71755fd commit 79e351c
Showing 1 changed file with 122 additions and 0 deletions.
122 changes: 122 additions & 0 deletions modules/sandbox/src/OAuthCodecs.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright 2021-2022 Disney Streaming
*
* Licensed under the Tomorrow Open Source Technology License, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://disneystreaming.github.io/TOST-1.0.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import _root_.aws.protocols.AwsQueryError
import cats.effect.Concurrent
import cats.syntax.all._
import fs2.compression.Compression
import org.http4s.EntityEncoder
import smithy4s.Endpoint
import smithy4s.codecs.PayloadPath
import smithy4s.http.Metadata
import smithy4s.http._
import smithy4s.http4s.kernel._
import smithy4s.kinds.PolyFunction
import smithy4s.schema.CachedSchemaCompiler

object OAuthCodecs {

def make[F[_]: Concurrent: Compression]: UnaryClientCodecs.Make[F] =
new UnaryClientCodecs.Make[F] {
def apply[I, E, O, SI, SO](
endpoint: Endpoint.Base[I, E, O, SI, SO]
): UnaryClientCodecs[F, I, E, O] = {
val transformEncoders = applyCompression[F](endpoint.hints)
val requestEncoderCompilersWithCompression = transformEncoders(
requestEncoderCompilers[F](
ignoreXmlFlattened = false,
capitalizeStructAndUnionMemberNames = false
)
)

val responseTag = endpoint.name + "Response"
val resultTag = endpoint.name + "Result"
val responseDecoderCompilers =
AwsXmlCodecs
.responseDecoderCompilers[F]
.contramapSchema(
smithy4s.schema.Schema.transformHintsLocallyK(
_ ++ smithy4s.Hints(
smithy4s.xml.internals.XmlStartingPath(
List(responseTag, resultTag)
)
)
)
)
val errorDecoderCompilers = AwsXmlCodecs
.responseDecoderCompilers[F]
.contramapSchema(
smithy4s.schema.Schema.transformHintsLocallyK(
_ ++ smithy4s.Hints(
smithy4s.xml.internals.XmlStartingPath(
List("ErrorResponse", "Error")
)
)
)
)
// Takes the `@awsQueryError` trait into consideration to decide how to
// discriminate error responses.
val errorNameMapping: (String => String) = endpoint.errorable match {
case None =>
identity[String]

case Some(err) =>
val mapping = err.error.alternatives.flatMap { alt =>
val shapeName = alt.schema.shapeId.name
alt.hints.get(AwsQueryError).map(_.code).map(_ -> shapeName)
}.toMap
errorCode => mapping.getOrElse(errorCode, errorCode)
}
val errorDiscriminator = AwsErrorTypeDecoder
.fromResponse(errorDecoderCompilers)
.andThen(_.map(_.map {
case HttpDiscriminator.NameOnly(name) =>
HttpDiscriminator.NameOnly(errorNameMapping(name))
case other => other
}))

val make = UnaryClientCodecs.Make[F](
input = requestEncoderCompilersWithCompression,
output = responseDecoderCompilers,
error = errorDecoderCompilers,
errorDiscriminator = errorDiscriminator
)
make.apply(endpoint)
}
}

// TODO: DRY relative to other codec?
private def requestEncoderCompilers[F[_]: Concurrent]
: CachedSchemaCompiler[RequestEncoder[F, *]] = {
val urlFormEntityEncoderCompilers = UrlForm.Encoder(
ignoreXmlFlattened = false,
capitalizeStructAndUnionMemberNames = false
)
RequestEncoder.restSchemaCompiler[F](
metadataEncoderCompiler = Metadata.AwsEncoder,
entityEncoderCompiler = urlFormEntityEncoderCompilers
)
}

private def urlFormEntityEncoder[F[_]]: EntityEncoder[F, UrlForm] =
EntityEncoders.fromHttpMediaWriter(
HttpMediaTyped(
HttpMediaType("application/x-www-form-urlencoded"),
(_: Any, urlForm: UrlForm) => Blob(urlForm.render)
)
)

}

0 comments on commit 79e351c

Please sign in to comment.