Skip to content

Commit

Permalink
Add service transformation utils (#1644)
Browse files Browse the repository at this point in the history
  • Loading branch information
kubukoz authored Feb 6, 2025
1 parent 3f253b7 commit e7ca3ec
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ When adding entries, please treat them as if they could end up in a release any

Thank you!

# 0.18.30

* Add utilities for Service.Builder in [#1644](https://github.com/disneystreaming/smithy4s/pull/1644)

# 0.18.29

* Fix for decoding of required nullable fields and some combinations of refinements with nullable fields (see [#1637](https://github.com/disneystreaming/smithy4s/pull/1637))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ import munit._
import smithy4s.kinds.PolyFunction5
import smithy4s.example.FooServiceGen
import smithy.api.Documentation
import smithy4s.schema.OperationSchema
import smithy4s.kinds.PolyFunction

class ServiceBuilderSpec extends FunSuite {

val service = smithy4s.example.FooService

val builder = smithy4s.Service.Builder.fromService(service)
val builder = service.toBuilder

test(
"can replace the following values (Id, Version and Hints) using withId, withVersion, withHints"
Expand Down Expand Up @@ -91,4 +93,30 @@ class ServiceBuilderSpec extends FunSuite {
)
}

test("can easily transform endpoint's inputs using schema PolyFunctions") {

val fk = new PolyFunction[Schema, Schema] {
def apply[A](schema: Schema[A]): Schema[A] =
schema.withId(schema.shapeId.withNamespace("replaced"))
}

val result = builder
.mapEndpointEach(
Endpoint.mapSchema(
OperationSchema
.mapInputK(fk)
.andThen(
OperationSchema.mapOutputK(fk)
)
)
)
.build

val namespaces =
result.endpoints.map(_.input.shapeId.namespace).toSet ++
result.endpoints.map(_.output.shapeId.namespace).toSet

assert(namespaces == Set("replaced"))
}

}
7 changes: 7 additions & 0 deletions modules/core/src/smithy4s/Endpoint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,13 @@ trait Endpoint[Op[_, _, _, _, _], I, E, O, SI, SO] { self =>

object Endpoint {

def mapSchema[Op[_, _, _, _, _]](
f: PolyFunction5[OperationSchema, OperationSchema]
): PolyFunction5[Endpoint[Op, *, *, *, *, *], Endpoint[Op, *, *, *, *, *]] =
new PolyFunction5[Endpoint[Op, *, *, *, *, *], Endpoint[Op, *, *, *, *, *]] {
def apply[I, E, O, SI, SO](fa: Endpoint[Op, I, E, O, SI, SO]): Endpoint[Op, I, E, O, SI, SO] = fa.mapSchema(f(_))
}

trait Middleware[A] { self =>
def prepare[Alg[_[_, _, _, _, _]]](service: Service[Alg])(endpoint: service.Endpoint[_, _, _, _, _]): A => A
final def biject[B](to: A => B)(from: B => A): Middleware[B] = new Middleware[B] {
Expand Down
2 changes: 2 additions & 0 deletions modules/core/src/smithy4s/Service.scala
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ trait Service[Alg[_[_, _, _, _, _]]] extends FunctorK5[Alg] with HasId {
*/
final def fromBifunctorHandlers[F[_, _]](handlers: EndpointHandler[Operation, Kind2[F]#toKind5]*) : FromHandlers[Kind2[F]#toKind5]
= fromHandlers[Kind2[F]#toKind5](handlers:_*)

final def toBuilder: Service.Builder[Alg, Operation] = Service.Builder.fromService(this)
}

object Service {
Expand Down
4 changes: 4 additions & 0 deletions modules/core/src/smithy4s/ShapeId.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ import smithy.api.IdRef

final case class ShapeId(namespace: String, name: String) extends HasId {
def show = s"$namespace#$name"

def withNamespace(namespace: String): ShapeId = copy(namespace = namespace)
def withName(name: String): ShapeId = copy(name = name)
def withMember(member: String): ShapeId.Member = ShapeId.Member(this, member)

override def toString = show
override def id: ShapeId = this
}
Expand Down
54 changes: 54 additions & 0 deletions modules/core/src/smithy4s/schema/OperationSchema.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package smithy4s
package schema

import smithy4s.internals.InputOutput
import smithy4s.kinds.PolyFunction5
import smithy4s.kinds.PolyFunction

final case class OperationSchema[I, E, O, SI, SO] private[smithy4s] (
id: ShapeId,
Expand Down Expand Up @@ -96,3 +98,55 @@ final case class OperationSchema[I, E, O, SI, SO] private[smithy4s] (
copy(streamedOutput = streamedOutput.map(f))

}

object OperationSchema {
def mapInputK(
fk: PolyFunction[Schema, Schema]
): PolyFunction5[OperationSchema, OperationSchema] =
new PolyFunction5[OperationSchema, OperationSchema] {
def apply[I, E, O, SI, SO](
op: OperationSchema[I, E, O, SI, SO]
): OperationSchema[I, E, O, SI, SO] =
op.mapInput(fk(_))
}

def mapOutputK(
fk: PolyFunction[Schema, Schema]
): PolyFunction5[OperationSchema, OperationSchema] =
new PolyFunction5[OperationSchema, OperationSchema] {
def apply[I, E, O, SI, SO](
op: OperationSchema[I, E, O, SI, SO]
): OperationSchema[I, E, O, SI, SO] =
op.mapOutput(fk(_))
}

def mapErrorK(
fk: PolyFunction[ErrorSchema, ErrorSchema]
): PolyFunction5[OperationSchema, OperationSchema] =
new PolyFunction5[OperationSchema, OperationSchema] {
def apply[I, E, O, SI, SO](
op: OperationSchema[I, E, O, SI, SO]
): OperationSchema[I, E, O, SI, SO] =
op.mapError(fk(_))
}

def mapStreamingInputK(
fk: PolyFunction[StreamingSchema, StreamingSchema]
): PolyFunction5[OperationSchema, OperationSchema] =
new PolyFunction5[OperationSchema, OperationSchema] {
def apply[I, E, O, SI, SO](
op: OperationSchema[I, E, O, SI, SO]
): OperationSchema[I, E, O, SI, SO] =
op.mapStreamedInput(fk(_))
}

def mapStreamingOutputK(
fk: PolyFunction[StreamingSchema, StreamingSchema]
): PolyFunction5[OperationSchema, OperationSchema] =
new PolyFunction5[OperationSchema, OperationSchema] {
def apply[I, E, O, SI, SO](
op: OperationSchema[I, E, O, SI, SO]
): OperationSchema[I, E, O, SI, SO] =
op.mapStreamedOutput(fk(_))
}
}

0 comments on commit e7ca3ec

Please sign in to comment.