diff --git a/proxy/core/src/main/scala/io/cloudstate/proxy/HttpApi.scala b/proxy/core/src/main/scala/io/cloudstate/proxy/HttpApi.scala index be5a11f6e..1784b17bd 100644 --- a/proxy/core/src/main/scala/io/cloudstate/proxy/HttpApi.scala +++ b/proxy/core/src/main/scala/io/cloudstate/proxy/HttpApi.scala @@ -674,7 +674,7 @@ object HttpApi { body = "*", // Parse all input responseBody = "", // Include all output additionalBindings = Nil, // No need for additional bindings - pattern = HttpRule.Pattern.Post((Path / "v1" / method.getName).toString) + pattern = HttpRule.Pattern.Post((Path / service.getFullName / method.getName).toString) ) log.info(s"Using generated HTTP API endpoint using [$rule]") rule diff --git a/proxy/core/src/main/scala/io/cloudstate/proxy/Serve.scala b/proxy/core/src/main/scala/io/cloudstate/proxy/Serve.scala index f0702bc81..9892e4376 100644 --- a/proxy/core/src/main/scala/io/cloudstate/proxy/Serve.scala +++ b/proxy/core/src/main/scala/io/cloudstate/proxy/Serve.scala @@ -28,7 +28,15 @@ import akka.grpc.internal.{ } import akka.NotUsed import akka.grpc.{ProtobufSerializer, Trailers} -import akka.http.scaladsl.model.{HttpEntity, HttpHeader, HttpRequest, HttpResponse, StatusCodes} +import akka.http.scaladsl.model.{ + ContentTypes, + HttpEntity, + HttpHeader, + HttpProtocols, + HttpRequest, + HttpResponse, + StatusCodes +} import akka.http.scaladsl.model.Uri.Path import akka.actor.{ActorRef, ActorSystem} import akka.event.{Logging, LoggingAdapter} @@ -196,6 +204,11 @@ object Serve { ) } + private def isGrpcRequest(request: HttpRequest): Boolean = + (request.protocol == HttpProtocols.`HTTP/2.0`) && + ((request.entity.contentType == ContentTypes.`application/grpc+proto`) || + (request.entity.contentType.mediaType.value == "application/grpc")) + private[this] final def createGrpcApi(entities: Seq[ServableEntity], router: UserFunctionRouter, entityDiscoveryClient: EntityDiscoveryClient, @@ -215,7 +228,7 @@ object Serve { }).toMap val routes: PartialFunction[HttpRequest, Future[(List[HttpHeader], Source[ProtobufAny, NotUsed])]] = { - case req: HttpRequest if rpcMethodSerializers.contains(req.uri.path) => + case req: HttpRequest if isGrpcRequest(req) && rpcMethodSerializers.contains(req.uri.path) => log.debug("Received gRPC request [{}]", req.uri.path) val handler = rpcMethodSerializers(req.uri.path) diff --git a/tck/src/main/scala/io/cloudstate/tck/CrdtEntityTCK.scala b/tck/src/main/scala/io/cloudstate/tck/CrdtEntityTCK.scala index 31e684764..ce91a30ad 100644 --- a/tck/src/main/scala/io/cloudstate/tck/CrdtEntityTCK.scala +++ b/tck/src/main/scala/io/cloudstate/tck/CrdtEntityTCK.scala @@ -1952,6 +1952,15 @@ trait CrdtEntityTCK extends TCKSpec { .expectIncoming(command(1, id, "Process", Request(id))) .expectOutgoing(reply(1, PNCounter.state(0))) + client.http + .request("cloudstate.tck.model.crdt.CrdtTwo/Call", s"""{"id": "$id"}""") + .futureValue mustBe "{}" + interceptor + .expectCrdtEntityConnection() + .expectIncoming(init(ServiceTwo, id)) + .expectIncoming(command(1, id, "Call", Request(id))) + .expectOutgoing(reply(1, Response())) + client.http .request(s"tck/model/crdt/$id", """{"actions": [{"update": {"pncounter": {"change": 42} }}]}""") .futureValue mustBe """{"state":{"pncounter":{"value":"42"}}}""" diff --git a/tck/src/main/scala/io/cloudstate/tck/EntityTCK.scala b/tck/src/main/scala/io/cloudstate/tck/EntityTCK.scala index 970295528..77cb380f1 100644 --- a/tck/src/main/scala/io/cloudstate/tck/EntityTCK.scala +++ b/tck/src/main/scala/io/cloudstate/tck/EntityTCK.scala @@ -425,6 +425,15 @@ trait EntityTCK extends TCKSpec { .expectIncoming(command(1, id, "Process", Request(id))) .expectOutgoing(reply(1, Response())) + client.http + .request("cloudstate.tck.model.valueentity.ValueEntityTwo/Call", s"""{"id": "$id"}""") + .futureValue mustBe """{"message":""}""" + interceptor + .expectEntityConnection() + .expectIncoming(init(ServiceTwo, id)) + .expectIncoming(command(1, id, "Call", Request(id))) + .expectOutgoing(reply(1, Response())) + client.http .request(s"tck/model/entity/$id", """{"actions": [{"update": {"value": "one"}}]}""") .futureValue mustBe """{"message":"one"}""" diff --git a/tck/src/main/scala/io/cloudstate/tck/EventSourcedEntityTCK.scala b/tck/src/main/scala/io/cloudstate/tck/EventSourcedEntityTCK.scala index cd48b6873..c5d06e190 100644 --- a/tck/src/main/scala/io/cloudstate/tck/EventSourcedEntityTCK.scala +++ b/tck/src/main/scala/io/cloudstate/tck/EventSourcedEntityTCK.scala @@ -504,6 +504,15 @@ trait EventSourcedEntityTCK extends TCKSpec { .expectIncoming(command(1, id, "Process", Request(id))) .expectOutgoing(reply(1, Response())) + client.http + .request("cloudstate.tck.model.EventSourcedTwo/Call", s"""{"id": "$id"}""") + .futureValue mustBe """{"message":""}""" + interceptor + .expectEventSourcedEntityConnection() + .expectIncoming(init(ServiceTwo, id)) + .expectIncoming(command(1, id, "Call", Request(id))) + .expectOutgoing(reply(1, Response())) + client.http .request(s"tck/model/eventsourced/$id", """{"actions": [{"emit": {"value": "x"}}]}""") .futureValue mustBe """{"message":"x"}"""