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

WIP: Play routers and services #378

Closed

Conversation

richdougherty
Copy link
Contributor

Fixes #364.

This changes the way that Play gRPC services are generated so that the service implementation and router are in separate classes. I feel this is more idiomatic for Play. The service implementation isn't generated - the user has to do that - so I've worked to make the log and error messages informative and helpful.

At the moment this PR is in a rough state. I've made the main changes and got the tests passing. I still need to go through the code and remove duplication, moving files around and add scaladoc and javadoc.


/** Extract the longest common package prefix for a list of packages. */
private[gen] def commonPackage(packages: Seq[String]): String =
packages.reduce(commonPackage(_, _))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old code had an optimisation to check everything for equality. I've moved that optimisation out of this method and into the commonPackage(String,String) method. That means we can use reduce instead of writing our own fold.

@@ -50,7 +50,7 @@ class PlayJavaRouterSpec extends WordSpec with Matchers with BeforeAndAfterAll w
implicit def fromSourceMarshaller[T](implicit serializer: ProtobufSerializer[T], mat: Materializer, codec: Codec): ToResponseMarshaller[Source[T, NotUsed]] =
Marshaller.opaque((response: Source[T, NotUsed]) ⇒ GrpcMarshalling.marshalStream(response)(serializer, mat, codec))

val router = new GreeterServiceImpl(mat)
val router = new GreeterServiceRouter(new GreeterServiceImpl(), mat)
Copy link
Contributor Author

@richdougherty richdougherty Aug 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you can see how a new Java router and service are composed together.

@@ -29,7 +30,7 @@ class PlayScalaRouterSpec extends WordSpec with Matchers with BeforeAndAfterAll
implicit val ec = sys.dispatcher
implicit val patience = PatienceConfig(timeout = 3.seconds, interval = 15.milliseconds)

val router = new GreeterServiceImpl
val router = new GreeterServiceRouter(new GreeterServiceImpl)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you can see how a new Scala router and service are composed together.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, this looks nice than val router = new GreeterServiceImpl! 👍🏼

*/
@InternalApi
protected def createHandler(serviceName: String, mat: Materializer): HttpRequest => Future[HttpResponse]
@InternalApi abstract class PlayRouter(prefix: String, underlyingHandler: HttpRequest => Future[HttpResponse]) extends play.api.routing.Router {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed a lot of the logic from this class and just pass things in as constructor arguments.

@varargs // Helper for Java subclasses
final protected def classSeq(classes: Class[_]*): Seq[Class[_]] = classes

protected def bindingsForService[T](serviceClass: Class[T], environment: Environment, configuration: Configuration): Seq[Binding[_]] = {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is how a service is bound. I try to be helpful in my error messages.

TODO: Write tests to check this works.

@richdougherty
Copy link
Contributor Author

Apologies that I didn't get a chance to finish this. Here are some changes that are still needed.

TODO:

  • eliminate duplication between Play/Scala and Service/Client codegen
  • make Play/Scala codegen Twirl directory layouts and file names the same as each other
  • test some of the error conditions with loading classes

@dwijnand dwijnand closed this Sep 3, 2018
@dwijnand dwijnand reopened this Sep 3, 2018
@dwijnand
Copy link
Member

dwijnand commented Sep 3, 2018

@raboof / @johanandren, given your comments in #364, WDYT about this proposal?

@ignasi35 ignasi35 self-assigned this Sep 6, 2018
@ignasi35
Copy link
Contributor

ignasi35 commented Sep 6, 2018

@richdougherty I can't push to this PR. I'm looking into it more carefully and wanted to do a couple of small changes (unregarding the outcome of the discussion in #364)

@dwijnand
Copy link
Member

Discussed internally, and the vote was to reject it. Some notes:

@dwijnand dwijnand closed this Sep 26, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants